ktg-plugin-marketplace/plugins/voyage/tests/playground/voyage-playground.test.mjs
Kjell Tore Guttormsen 2f4330265c feat(voyage): scaffold playground/ with DS vendor sync — v4.2 Step 5
- playground/voyage-playground.html: minimal skeleton (DOCTYPE, app-header, guide-panel, aria-live region, skip-to-main link). Steps 8-11 will extend with render-pipeline + creation gestures + sidebar + export.
- playground/vendor/playground-design-system/: synced via 'node scripts/sync-design-system.mjs voyage' (27 files + MANIFEST.json with source_commit + sync_date + SHA-256 per file).
- tests/playground/voyage-playground.test.mjs: 8 tests pinning HTML existence, DOCTYPE, no-external-URLs, no-marked, A11Y skip-to-main + aria-live, MANIFEST.json structure, vendored DS files present.
- shared/PLAYGROUND-MAINTENANCE.md: consumer list updated 5 -> 6 (added voyage).
2026-05-09 12:55:02 +02:00

67 lines
3 KiB
JavaScript

// tests/playground/voyage-playground.test.mjs
// Filesystem + content tests for v4.2 voyage playground.
// Pure existence + grep checks — no browser launch.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { existsSync, statSync, readFileSync, readdirSync } 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 PLAYGROUND = join(ROOT, 'playground');
const HTML = join(PLAYGROUND, 'voyage-playground.html');
const VENDOR = join(PLAYGROUND, 'vendor', 'playground-design-system');
const MANIFEST = join(VENDOR, 'MANIFEST.json');
test('voyage-playground.html exists and has nonzero size', () => {
assert.ok(existsSync(HTML), 'voyage-playground.html must exist');
assert.ok(statSync(HTML).size > 0, 'must have content');
});
test('voyage-playground.html has DOCTYPE + html closing tag', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /^<!DOCTYPE html>/i);
assert.match(text, /<\/html>\s*$/);
});
test('voyage-playground.html does NOT contain external (http/https) URLs', () => {
// SC1 zero-network constraint: all assets must be relative to ./vendor/
const text = readFileSync(HTML, 'utf-8');
assert.ok(!/https?:\/\//.test(text), 'no external URLs allowed in playground HTML');
});
test('voyage-playground.html does NOT contain literal `marked` (renderer ban per risk-assessor H1)', () => {
const text = readFileSync(HTML, 'utf-8');
// marked is disqualified by issue #3515; markdown-it locked instead
// Allow comments mentioning "marked" as an explanatory artifact, but no actual import paths
assert.ok(!/from ['"].*marked/.test(text), 'no import from marked');
assert.ok(!/<script[^>]*marked\.min\.js/.test(text), 'no marked script tag');
});
test('voyage-playground.html includes skip-to-main link (A11Y baseline)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /Skip to main content/);
});
test('voyage-playground.html declares aria-live region', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /aria-live="polite"/);
});
test('playground/vendor/playground-design-system/MANIFEST.json exists and parses as JSON with expected keys', () => {
assert.ok(existsSync(MANIFEST), 'MANIFEST.json must be present from sync-design-system.mjs');
const obj = JSON.parse(readFileSync(MANIFEST, 'utf-8'));
assert.ok(obj.source_commit, 'source_commit field required');
assert.ok(obj.sync_date, 'sync_date field required');
assert.ok(obj.files && typeof obj.files === 'object', 'files map required');
});
test('playground/vendor/playground-design-system/ contains expected DS files', () => {
const files = readdirSync(VENDOR);
for (const expected of ['tokens.css', 'base.css', 'components.css', 'fonts.css', 'print.css']) {
assert.ok(files.includes(expected), `${expected} expected in vendor/`);
}
assert.ok(files.includes('fonts'), 'fonts/ subdirectory expected');
});