import assert from 'node:assert/strict'; import test from 'node:test'; import { installPageLangReport, LANG_REPORT_RETRIES } from '../src/pageLang.ts'; /** A page whose never changes, with timers we step by hand. */ function fakePage(lang: string, parsed = true) { const timers: Array<() => void> = []; const listeners = new Map void>(); const root = { getAttribute: (name: string) => (name === 'lang' ? lang : null) }; const document = { documentElement: parsed ? root : null, addEventListener: (type: string, fn: () => void) => { listeners.set(type, fn); }, removeEventListener: (type: string) => { listeners.delete(type); }, }; const win = { document, MutationObserver: class { observe() {} disconnect() {} }, setTimeout: (fn: () => void) => { timers.push(fn); return timers.length; }, clearTimeout: () => {}, } as unknown as Window & typeof globalThis; const parse = () => { document.documentElement = root; listeners.get('DOMContentLoaded')?.(); }; return { win, timers, parse, listeners }; } const settle = () => new Promise(resolve => setImmediate(resolve)); test('a language report lost at document start (no IPC bridge yet) is sent again', async () => { const { win, timers } = fakePage('en-GB'); const sent: unknown[] = []; let bridge = false; installPageLangReport(win, async (command, args) => { if (!bridge) throw new Error('IPC bridge not ready'); sent.push([command, args]); }); await settle(); assert.equal(sent.length, 0); assert.equal(timers.length, 1, 'a retry is scheduled'); bridge = true; timers.shift()!(); await settle(); assert.deepEqual(sent, [['tab_report', { report: { lang: 'en-GB' } }]]); assert.equal(timers.length, 0, 'nothing more once it went through'); }); test('retries are bounded and stop after dispose', async () => { const { win, timers } = fakePage('tr'); let calls = 0; const handle = installPageLangReport(win, async () => { calls += 1; throw new Error('down'); }); for (let i = 0; i < LANG_REPORT_RETRIES + 5; i += 1) { await settle(); timers.shift()?.(); } await settle(); assert.equal(calls, LANG_REPORT_RETRIES + 1); assert.equal(timers.length, 0); const second = fakePage('ja'); let later = 0; const h2 = installPageLangReport(second.win, async () => { later += 1; throw new Error('down'); }); await settle(); h2.dispose(); second.timers.shift()?.(); await settle(); assert.equal(later, 1, 'no report after dispose'); handle.dispose(); }); test('installed at document start before exists, it reports once the parser made it', async () => { const page = fakePage('en-GB', false); const sent: unknown[] = []; const handle = installPageLangReport(page.win, async (command, args) => { sent.push([command, args]); }); await settle(); assert.equal(sent.length, 0); page.parse(); await settle(); assert.deepEqual(sent, [['tab_report', { report: { lang: 'en-GB' } }]]); handle.dispose(); assert.equal(page.listeners.size, 0); });