AT Mot — a bilingual (EN/FR) daily word game native to the AT Protocol.
1// @vitest-environment happy-dom
2import { describe, expect, it, vi } from 'vitest';
3import { renderHeader } from '../src/ui/header.js';
4import { pathForLangSwitch } from '../src/config.js';
5import type { Ctx } from '../src/ui/context.js';
6
7function makeCtx(over: Partial<Ctx> = {}): Ctx {
8 return {
9 lang: 'fr',
10 session: null,
11 handle: null,
12 pendingRecord: null,
13 setLang() {},
14 navigate() {},
15 rerender() {},
16 async signInWith() {},
17 async signOut() {},
18 ...over,
19 };
20}
21
22describe('renderHeader language switch', () => {
23 it('the EN button asks to switch to English', () => {
24 const setLang = vi.fn();
25 const header = renderHeader(makeCtx({ setLang }));
26 const en = [...header.querySelectorAll('button')].find((b) => b.textContent === 'EN');
27 expect(en).toBeDefined();
28 en!.click();
29 expect(setLang).toHaveBeenCalledWith('en');
30 });
31
32 // Regression: on a French puzzle page, switching to EN must route to the
33 // English puzzle. Previously setLang only flipped ctx.lang and re-rendered,
34 // so the router re-derived `fr` from the unchanged path and nothing changed.
35 it('switching language on a puzzle page routes to the same puzzle in the new language', () => {
36 expect(pathForLangSwitch('/p/fr/1', 'en')).toBe('/p/en/1');
37 });
38});
39
40describe('renderHeader sign-in button', () => {
41 const signedIn = { session: {} as Ctx['session'] };
42 const signIn = (header: HTMLElement) =>
43 [...header.querySelectorAll('button')].find((b) => b.textContent === 'Sign in');
44
45 it('shows a Sign in button on the play view when signed out', () => {
46 const header = renderHeader(makeCtx({ lang: 'en' }), { showSignIn: true });
47 expect(signIn(header)).toBeDefined();
48 });
49
50 it('hides the Sign in button when signed in', () => {
51 const header = renderHeader(makeCtx({ lang: 'en', ...signedIn }), { showSignIn: true });
52 expect(signIn(header)).toBeUndefined();
53 });
54
55 it('hides the Sign in button on views that do not opt in (puzzle/about)', () => {
56 const header = renderHeader(makeCtx({ lang: 'en' }));
57 expect(signIn(header)).toBeUndefined();
58 });
59});