Files
mokosh/tests/i18n/manifest-i18n.test.ts
Mark 9dcfcf0793 fix(02): revise plans per checker (B1 + 4 flags) — add tabs permission for D-P2-02
- BLOCKER B1: add `tabs` to manifest.json permissions (DEC-011 Amendment 1
  cites Phase 2 D-P2-02 meta.urls feature as justification). Honors
  D-P2-02 "all tabs visible" wording verbatim. Updates manifest-i18n test
  expected permission list lockstep.
- F1: add A28 harness assertion for REQ-archive-layout strict zip-layout
  verification (5 entries, no extras).
- F2: createArchive empty-tracker fallback removed; logs warn + sets
  urls:[] instead of fake [extension-origin URL]. 02-01 RED test pins
  empty-tracker → urls:[].
- F3: 02-02 Task 3 prose deliberation struck; typed `blob-url-mint-failed`
  throw is the resolved-only contract.
- F4: 02-02 Task 3 verify block adds full-suite `npm test` after focused
  test runs.
- A27 strict-mode (Plan 02-04): REQUIRES both URLs in meta.urls; FAILS
  on length < 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:25:20 +02:00

131 lines
5.7 KiB
TypeScript

// tests/i18n/manifest-i18n.test.ts — Plan 01-12 i18n migration regression
// pin (post-D-07 state).
//
// Asserts manifest.json uses chrome i18n placeholders with default_locale='en'
// + _locales/{en,ru}/messages.json carrying the D-07 + D-08 canonical strings.
//
// History: Plan 01-12 D-07 migrated manifest.json:name from the literal
// 'AI Call Recorder' (no default_locale; no _locales/) to the
// '__MSG_extName__' i18n placeholder that resolves to
// 'Mokosh — Session Capture' (en) / 'Mokosh — Запись сессии' (ru). The
// test was Wave-0 RED against the pre-migration state and flipped GREEN
// after Wave-3 Task 1 landed the manifest + messages.json files. This
// file now pins the post-D-07 state as a regression guard.
//
// 2026-05-20 Plan 02-03 amendment (DEC-011 Amendment 1): manifest.json
// permissions array extended to include `"tabs"` per Phase 2 D-P2-02
// (meta.urls multi-tab visibility). The permission-set describe block
// below pins the post-amendment 8-entry set as a regression guard.
//
// References:
// - RESEARCH §10 + §11 (Chrome i18n schema; __MSG_* placeholder rules)
// - brand-decisions-v1.md D-07 override (`Mokosh — Session Capture`)
// - brand-decisions-v1.md D-08 tagline (`Thirty seconds ago, always at hand.`)
// - .planning/PROJECT.md DEC-011 Amendment 1 (`tabs` permission, 2026-05-20)
// - .planning/phases/02-stabilize-export-pipeline/02-CONTEXT.md D-P2-02
import { describe, expect, it } from 'vitest';
import { existsSync, readFileSync } from 'node:fs';
import { resolve as resolvePath } from 'node:path';
const MANIFEST_PATH = resolvePath(process.cwd(), 'manifest.json');
const EN_LOCALE_PATH = resolvePath(process.cwd(), '_locales/en/messages.json');
const RU_LOCALE_PATH = resolvePath(process.cwd(), '_locales/ru/messages.json');
interface I18nEntry {
message: string;
description?: string;
}
type LocaleFile = Record<string, I18nEntry>;
describe('Plan 01-12: manifest i18n migration (__MSG_*__ + default_locale)', () => {
it('manifest.json:name === "__MSG_extName__" (i18n placeholder)', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(manifest.name).toBe('__MSG_extName__');
});
it('manifest.json:description === "__MSG_extDesc__"', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(manifest.description).toBe('__MSG_extDesc__');
});
it('manifest.json:default_locale === "en"', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(manifest.default_locale).toBe('en');
});
it('manifest.json:action.default_title === "__MSG_tooltipOff__"', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(manifest.action?.default_title).toBe('__MSG_tooltipOff__');
});
});
describe('Plan 01-12: _locales/en/messages.json (default_locale fallback)', () => {
it('_locales/en/messages.json exists + parses', () => {
expect(existsSync(EN_LOCALE_PATH), `Expected ${EN_LOCALE_PATH}`).toBe(true);
const en = JSON.parse(readFileSync(EN_LOCALE_PATH, 'utf8'));
expect(typeof en).toBe('object');
});
it('en:extName === "Mokosh — Session Capture" (D-07 override)', () => {
const en: LocaleFile = JSON.parse(readFileSync(EN_LOCALE_PATH, 'utf8'));
expect(en.extName?.message).toBe('Mokosh — Session Capture');
});
it('en:extDesc === "Thirty seconds ago, always at hand." (D-08 tagline)', () => {
const en: LocaleFile = JSON.parse(readFileSync(EN_LOCALE_PATH, 'utf8'));
expect(en.extDesc?.message).toBe('Thirty seconds ago, always at hand.');
});
});
describe('Plan 01-12: _locales/ru/messages.json (primary operator locale)', () => {
it('_locales/ru/messages.json exists + parses', () => {
expect(existsSync(RU_LOCALE_PATH), `Expected ${RU_LOCALE_PATH}`).toBe(true);
const ru = JSON.parse(readFileSync(RU_LOCALE_PATH, 'utf8'));
expect(typeof ru).toBe('object');
});
it('ru:extName === "Mokosh — Запись сессии"', () => {
const ru: LocaleFile = JSON.parse(readFileSync(RU_LOCALE_PATH, 'utf8'));
expect(ru.extName?.message).toBe('Mokosh — Запись сессии');
});
it('ru:extDesc === "Тридцать секунд назад, всегда под рукой."', () => {
const ru: LocaleFile = JSON.parse(readFileSync(RU_LOCALE_PATH, 'utf8'));
expect(ru.extDesc?.message).toBe('Тридцать секунд назад, всегда под рукой.');
});
});
describe('Plan 02-03 DEC-011 Amendment 1: manifest.json permissions include "tabs" (D-P2-02)', () => {
// Locked set per DEC-011 Amendment 1 (2026-05-20). `tabs` added to enable
// chrome.tabs.get(tabId).url + chrome.tabs.query for the tab-url-tracker
// (D-P2-02 meta.urls feature). Any future permission delta requires a
// formal DEC-011 amendment update — DO NOT edit this list without one.
const EXPECTED_PERMISSIONS: ReadonlyArray<string> = [
'desktopCapture',
'activeTab',
'tabs',
'downloads',
'scripting',
'storage',
'offscreen',
'notifications',
];
it('manifest.json:permissions includes "tabs" (DEC-011 Amendment 1)', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(Array.isArray(manifest.permissions)).toBe(true);
expect(manifest.permissions).toContain('tabs');
});
it('manifest.json:permissions has exactly the 8 entries in DEC-011 Amendment 1', () => {
const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8'));
expect(Array.isArray(manifest.permissions)).toBe(true);
const actual = [...manifest.permissions].sort();
const expected = [...EXPECTED_PERMISSIONS].sort();
expect(actual).toEqual(expected);
expect(manifest.permissions.length).toBe(EXPECTED_PERMISSIONS.length);
});
});