AT Mot — a bilingual (EN/FR) daily word game native to the AT Protocol.
1import { describe, it, expect } from 'vitest';
2import { normalizeWord, isPlayableFiveLetter } from '../src/engine/normalize.js';
3
4describe('normalizeWord', () => {
5 it('strips French diacritics to A–Z', () => {
6 expect(normalizeWord('élève')).toBe('ELEVE');
7 expect(normalizeWord('français')).toBe('FRANCAIS');
8 expect(normalizeWord('hôtel')).toBe('HOTEL');
9 expect(normalizeWord('naïf')).toBe('NAIF');
10 });
11
12 it('expands ligatures before length checks', () => {
13 expect(normalizeWord('œuf')).toBe('OEUF');
14 expect(normalizeWord('nœud')).toBe('NOEUD'); // 5 letters once expanded
15 expect(normalizeWord('cœur')).toBe('COEUR');
16 });
17
18 it('drops apostrophes and hyphens', () => {
19 expect(normalizeWord("aujourd'hui")).toBe('AUJOURDHUI');
20 expect(normalizeWord('arc-en-ciel')).toBe('ARCENCIEL');
21 });
22
23 it('uppercases plain ASCII', () => {
24 expect(normalizeWord('crane')).toBe('CRANE');
25 });
26});
27
28describe('isPlayableFiveLetter', () => {
29 it('accepts words that are 5 letters once normalized', () => {
30 expect(isPlayableFiveLetter('NŒUD')).toBe(true); // -> NOEUD
31 expect(isPlayableFiveLetter('élève')).toBe(true); // -> ELEVE
32 expect(isPlayableFiveLetter('CRANE')).toBe(true);
33 });
34
35 it('rejects words that are not 5 letters normalized', () => {
36 expect(isPlayableFiveLetter('cœur')).toBe(true); // COEUR = 5
37 expect(isPlayableFiveLetter('œuf')).toBe(false); // OEUF = 4
38 expect(isPlayableFiveLetter('bonjour')).toBe(false);
39 });
40});