mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-19 08:33:56 -06:00
test: stub navigator so the i18n test runs on Node 20 too
i18n.js sniffs navigator.language at module load. Node has had navigator as a global only since 21, so the test passed locally on Node 24 and failed in CI on Node 20 with "navigator is not defined" — a green local run that proved nothing about the version CI actually uses. Stubbed explicitly, and verified on both 20 and 24 this time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kfhrUPit5MCqxeTQyqr56
This commit is contained in:
parent
9823aaf595
commit
68c7903cc8
|
|
@ -85,16 +85,25 @@ test('the interpolation resolves, and falls back to the product name', async ()
|
||||||
// i18n.js reads window.__ST_BRAND_NAME at CALL time, so branding.js can refresh it after first
|
// i18n.js reads window.__ST_BRAND_NAME at CALL time, so branding.js can refresh it after first
|
||||||
// paint and a workspace switch shows the new brand rather than the one cached at module load.
|
// paint and a workspace switch shows the new brand rather than the one cached at module load.
|
||||||
const mod = path.join(I18N_DIR, '..', 'i18n.js');
|
const mod = path.join(I18N_DIR, '..', 'i18n.js');
|
||||||
// i18n.js reads the saved language from localStorage as it loads, so both browser globals have to
|
/*
|
||||||
// exist before the import — not because this test cares about storage, but because the module
|
* i18n.js reads the saved language from localStorage AND sniffs navigator.language as it loads,
|
||||||
// would throw on the way in.
|
* so both browser globals have to exist before the import — not because this test cares about
|
||||||
|
* either, but because the module throws on the way in without them.
|
||||||
|
*
|
||||||
|
* ⚠️ navigator is the one that bites: Node has had it as a global only since 21, so this passed
|
||||||
|
* locally on Node 24 and failed in CI on Node 20 with "navigator is not defined". Stubbing it
|
||||||
|
* explicitly makes the test independent of which Node happens to be running it.
|
||||||
|
*/
|
||||||
const store = new Map();
|
const store = new Map();
|
||||||
globalThis.localStorage = {
|
globalThis.localStorage = {
|
||||||
getItem: (k) => (store.has(k) ? store.get(k) : null),
|
getItem: (k) => (store.has(k) ? store.get(k) : null),
|
||||||
setItem: (k, v) => store.set(k, String(v)),
|
setItem: (k, v) => store.set(k, String(v)),
|
||||||
removeItem: (k) => store.delete(k),
|
removeItem: (k) => store.delete(k),
|
||||||
};
|
};
|
||||||
globalThis.window = { __ST_BRAND_NAME: undefined, localStorage: globalThis.localStorage };
|
const priorNavigator = globalThis.navigator;
|
||||||
|
if (!priorNavigator) globalThis.navigator = { language: 'en-US', languages: ['en-US'] };
|
||||||
|
globalThis.window = { __ST_BRAND_NAME: undefined, localStorage: globalThis.localStorage,
|
||||||
|
navigator: globalThis.navigator };
|
||||||
const { t } = await import(`file://${mod}`);
|
const { t } = await import(`file://${mod}`);
|
||||||
|
|
||||||
const unbranded = t('settings.setup_step_1');
|
const unbranded = t('settings.setup_step_1');
|
||||||
|
|
@ -112,4 +121,5 @@ test('the interpolation resolves, and falls back to the product name', async ()
|
||||||
assert.ok(t('settings.setup_step_1').includes('ScreenTinker'));
|
assert.ok(t('settings.setup_step_1').includes('ScreenTinker'));
|
||||||
delete globalThis.window;
|
delete globalThis.window;
|
||||||
delete globalThis.localStorage;
|
delete globalThis.localStorage;
|
||||||
|
if (!priorNavigator) delete globalThis.navigator;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue