AT Mot — a bilingual (EN/FR) daily word game native to the AT Protocol.
0

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 3.4 kB View raw
1import { describe, it, expect } from 'vitest'; 2import { 3 buildShareText, 4 buildShareFacets, 5 assembleShareText, 6 defaultShareNote, 7 countGraphemes, 8 POST_MAX_GRAPHEMES, 9 emojiGrid, 10 shareHeader, 11} from '../src/engine/share.js'; 12import type { GameResult } from '../src/engine/types.js'; 13 14const win: GameResult = { 15 lang: 'fr', 16 puzzleNumber: 412, 17 solved: true, 18 guessCount: 4, 19 rows: [ 20 ['absent', 'present', 'absent', 'absent', 'present'], 21 ['absent', 'correct', 'absent', 'present', 'absent'], 22 ['correct', 'correct', 'absent', 'present', 'present'], 23 ['correct', 'correct', 'correct', 'correct', 'correct'], 24 ], 25}; 26 27describe('share text', () => { 28 it('header is "AT Mot <n> (<LANG>) <score>"', () => { 29 expect(shareHeader(win)).toBe('AT Mot 412 (FR) 4/6'); 30 }); 31 32 it('uses standard Unicode squares (not brand colours)', () => { 33 expect(emojiGrid(win.rows).split('\n')[3]).toBe('🟩🟩🟩🟩🟩'); 34 expect(emojiGrid([['absent', 'present', 'correct', 'absent', 'absent']])).toBe('⬛🟨🟩⬛⬛'); 35 }); 36 37 it('includes the puzzle permalink (load-bearing for Constellation discovery)', () => { 38 const text = buildShareText(win); 39 expect(text).toContain('https://atmot.herve.bzh/p/fr/412'); 40 // header, blank, grid, blank, link 41 const parts = text.split('\n\n'); 42 expect(parts[0]).toBe('AT Mot 412 (FR) 4/6'); 43 expect(parts[2]).toBe('https://atmot.herve.bzh/p/fr/412'); 44 }); 45 46 it('shows X/6 on a loss', () => { 47 const loss: GameResult = { ...win, solved: false, guessCount: undefined, rows: win.rows.slice(0, 6) }; 48 expect(shareHeader(loss)).toContain('X/6'); 49 }); 50 51 it('never contains the word "Wordle"', () => { 52 expect(buildShareText(win).toLowerCase()).not.toContain('wordle'); 53 }); 54}); 55 56describe('custom share message', () => { 57 it('defaultShareNote is the header line', () => { 58 expect(defaultShareNote(win)).toBe('AT Mot 412 (FR) 4/6'); 59 }); 60 61 it('assembleShareText keeps grid + link, with the note first', () => { 62 const text = assembleShareText(win, 'I nailed it 🎉'); 63 const parts = text.split('\n\n'); 64 expect(parts[0]).toBe('I nailed it 🎉'); 65 expect(parts[parts.length - 1]).toBe('https://atmot.herve.bzh/p/fr/412'); 66 expect(text).toContain(emojiGrid(win.rows)); 67 }); 68 69 it('assembleShareText drops the note line when the note is empty', () => { 70 const text = assembleShareText(win, ' '); 71 expect(text).not.toContain('AT Mot'); 72 expect(text.split('\n\n')[0]).toBe(emojiGrid(win.rows)); 73 expect(text).toContain('https://atmot.herve.bzh/p/fr/412'); 74 }); 75 76 it('buildShareText is unchanged (default note = header)', () => { 77 expect(buildShareText(win)).toBe(assembleShareText(win, shareHeader(win))); 78 }); 79 80 it('buildShareFacets recomputes byte offsets for a custom note', () => { 81 const note = 'Réussi ! 🎉 accents éàü'; 82 const text = assembleShareText(win, note); 83 const facet = buildShareFacets(win, note)[0]!; 84 const bytes = new TextEncoder().encode(text); 85 const slice = new TextDecoder().decode(bytes.slice(facet.index.byteStart, facet.index.byteEnd)); 86 expect(slice).toBe('https://atmot.herve.bzh/p/fr/412'); 87 }); 88 89 it('countGraphemes treats each emoji square as one', () => { 90 expect(countGraphemes('🟩🟩🟩')).toBe(3); 91 expect(countGraphemes('abc')).toBe(3); 92 expect(POST_MAX_GRAPHEMES).toBe(300); 93 }); 94});