88 lines
4.5 KiB
JavaScript
88 lines
4.5 KiB
JavaScript
// tests/playground/voyage-playground-structure.test.mjs
|
|
// v4.3 Step 29 — Group B structural assertions for the voyage playground.
|
|
//
|
|
// Group B verifies that DS-token classes, theme-toggle wiring, and the
|
|
// sidebar-tab/keyboard pattern are present in voyage-playground.html.
|
|
// All assertions are static-grep (no DOM, no browser). Companion to:
|
|
// - tests/playground/voyage-playground.test.mjs (Group A — SC1/3/6/7)
|
|
// - tests/integration/annotation-export-schema.test.mjs (Group C — SC6)
|
|
|
|
import { test } from 'node:test';
|
|
import { strict as assert } from 'node:assert';
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, resolve, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = resolve(__dirname, '..', '..');
|
|
const HTML = join(ROOT, 'playground', 'voyage-playground.html');
|
|
|
|
// --- DS-token classes present ----------------------------------------
|
|
test('Group B — DS badge--scope-voyage class present (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /badge--scope-voyage/, 'badge--scope-voyage required');
|
|
});
|
|
|
|
test('Group B — DS guide-panel + key-stats classes present (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /class="guide-panel/, 'guide-panel base class required');
|
|
assert.match(text, /class="key-stats/, 'key-stats class required');
|
|
});
|
|
|
|
test('Group B — DS fleet-grid + fleet-tile classes present (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /class="fleet-grid"/, 'fleet-grid required');
|
|
assert.match(text, /class="fleet-tile/, 'fleet-tile required');
|
|
});
|
|
|
|
// --- Theme-toggle wired ---------------------------------------------
|
|
test('Group B — theme-toggle button has data-action attribute (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /data-action="toggle-theme"/, 'data-action=toggle-theme required');
|
|
assert.match(text, /aria-label="Bytt tema"/, 'theme-toggle aria-label required');
|
|
});
|
|
|
|
test('Group B — wireThemeToggle handler exists (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /function\s+wireThemeToggle\s*\(/, 'wireThemeToggle function required');
|
|
});
|
|
|
|
test('Group B — theme persistence to localStorage (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /(voyage-theme|voyage_theme)/, 'theme localStorage key required');
|
|
});
|
|
|
|
// --- Sidebar-tab / keyboard pattern ---------------------------------
|
|
test('Group B — sidebar role=tablist with aria-selected (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
assert.match(text, /role="tablist"/, 'role=tablist required');
|
|
assert.match(text, /aria-selected="(true|false)"/, 'aria-selected attribute required');
|
|
});
|
|
|
|
test('Group B — keyboard nav J/K + Esc handlers wired (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
// Step 20 — J/K navigation + Esc dismiss
|
|
assert.match(text, /(keydown|keypress|keyup)/, 'keyboard event listener required');
|
|
assert.match(text, /(['"]j['"]|['"]J['"]|KeyJ)/, 'J navigation required');
|
|
assert.match(text, /(['"]k['"]|['"]K['"]|KeyK)/, 'K navigation required');
|
|
});
|
|
|
|
test('Group B — anchor-ID format ANN-NNNN matches Node-side parser (v4.3 Step 29)', () => {
|
|
const text = readFileSync(HTML, 'utf-8');
|
|
// Mirror of lib/parsers/anchor-parser.mjs ID_RE (^ANN-\d{4}$)
|
|
assert.match(text, /\/\^ANN-\\d\{4\}\$\//, 'VOYAGE_ANCHOR_ID_RE pattern required');
|
|
assert.match(text, /function\s+parseAnchor\s*\(/, 'parseAnchor function required');
|
|
});
|
|
|
|
// --- Fleet-grid CSS parity vs vendored DS (v4.3 Step 9 / 99707f51) ---
|
|
test('Group B — SC1.4 fleet-grid CSS parity vs vendored DS (99707f51)', () => {
|
|
const cssPath = join(ROOT, 'playground', 'vendor', 'playground-design-system', 'components-tier3-supplement.css');
|
|
const css = readFileSync(cssPath, 'utf-8');
|
|
const startIdx = css.indexOf('.fleet-grid {');
|
|
assert.notStrictEqual(startIdx, -1, '.fleet-grid block required in vendored DS components-tier3-supplement.css');
|
|
const endIdx = css.indexOf('}', startIdx);
|
|
assert.notStrictEqual(endIdx, -1, '.fleet-grid block must terminate');
|
|
const block = css.slice(startIdx, endIdx + 1);
|
|
assert.match(block, /grid-template-columns:\s*repeat\(4,\s*1fr\)/, '.fleet-grid grid-template-columns: repeat(4, 1fr) required');
|
|
assert.match(block, /gap:\s*var\(--space-3\)/, '.fleet-grid gap: var(--space-3) required');
|
|
});
|