From de585d69610a8d73cd1a9827570b2efda8be5d92 Mon Sep 17 00:00:00 2001 From: thatguywob Date: Mon, 26 Oct 2026 10:40:33 +0000 Subject: [PATCH] test: extend branch coverage floor to inline page scripts Attribute harness execution to stable inline URLs and report original page lines. Assert all 21 previously uncovered ranges and verify mapping with real child coverage. Hive-Run: hivecommons/hivecommons.github.io#275 Hive-Plan: issue-275-inline-coverage-floor Hive-Spec: issue-275#recommendation Signed-off-by: thatguywob --- README.md | 2 ++ scripts/carousels.test.mjs | 19 +++++++++++++++ scripts/coverage-floor.test.mjs | 41 +++++++++++++++++++++++++++++++++ scripts/inline-scripts.test.mjs | 12 ++++++++++ 4 files changed, 74 insertions(+) create mode 100644 scripts/inline-scripts.test.mjs diff --git a/README.md b/README.md index a9a2791..8bd4419 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,8 @@ red PR job against. Then pins the live tree: every committed content page is already up to date, so the tool and `page-csp.test.mjs` agree on what correct means, and a failure names the regenerate command. Zero dependencies. +- `node --test scripts/inline-scripts.test.mjs` — checks shared inline-script extraction, + unique hook matching, page line numbers and stable V8 source URLs. - `node --test scripts/coverage-floor.test.mjs` — branch-coverage floor over the `scripts/*.mjs` helpers the other gates import (`page-csp.mjs`, `html-pages.mjs`, `actions-if.mjs`, `update-csp-hashes.mjs`, `inline-scripts.mjs`) and over every inline diff --git a/scripts/carousels.test.mjs b/scripts/carousels.test.mjs index 5b3c540..27cc68c 100644 --- a/scripts/carousels.test.mjs +++ b/scripts/carousels.test.mjs @@ -998,3 +998,22 @@ test("projects track inset: an empty computed padding-left counts as 0, not NaN" t.next.dispatch("click"); assert.equal(t.lastScroll().left, SLIDE_PITCH, "would be NaN if the empty padding were not coerced"); }); + +test("hero: keyboard focuses a slide without links and retries unsupported focus options", () => { + const t = bootHero(); + t.slides[0].children[0].focus(); + t.slides[1].children.forEach((el) => el.remove()); + const attempts = []; + const target = t.slides[1]; + target.focus = (options) => { + attempts.push(options); + if (options) throw new TypeError('options unsupported'); + t.doc.activeElement = target; + }; + t.root.dispatch('keydown', { key: 'ArrowRight' }); + assert.equal(t.currentIndex(), 1); + assert.equal(target.tabIndex, -1); + assert.deepEqual(attempts, [{ preventScroll: true }, undefined]); + assert.equal(t.doc.activeElement, target); + assert.equal(t.rotating(), false); +}); diff --git a/scripts/coverage-floor.test.mjs b/scripts/coverage-floor.test.mjs index 73c5fa9..7c5c51f 100644 --- a/scripts/coverage-floor.test.mjs +++ b/scripts/coverage-floor.test.mjs @@ -339,3 +339,44 @@ test("every branch of every scripts/*.mjs helper and every inline page script is ...problemsOf(inline, inlineRuns.runs), ], []); }); + +test("fixture: real inline child coverage maps Function wrappers to original page lines", () => { + const dir = mkdtempSync(join(tmpdir(), "coverage-inline-fixture-")); + try { + mkdirSync(join(dir, "scripts")); + const page = '

Fixture

\n\n'; + writeFileSync(join(dir, "page.html"), page); + const helper = pathToFileURL(join(HERE, "inline-scripts.mjs")).href; + writeFileSync(join(dir, "scripts", "page.test.mjs"), ` +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { inlineScript } from ${JSON.stringify(helper)}; +const { src } = inlineScript(readFileSync("page.html", "utf8"), "page.html", "pick"); +new Function("assert", "flag", "expected", src)(assert, true, "yes"); +new Function("assert", "flag", "expected", "unusedLongParameter", src)(assert, true, "yes"); +`); + const registry = { "page.html": [{ hook: "pick" }] }; + const sources = inlineSources(dir, registry); + const first = collect(dir, suiteFiles(dir)); + assert.equal(first.status, 0, first.stdout + first.stderr); + const { runs, problems } = inlineRunsFromReports(first.reports, sources); + assert.deepEqual(problems, []); + assert.deepEqual([...runs.keys()], ["page.html#pick"]); + assert.deepEqual(problemsOf(sources, runs), [ + 'page.html#pick:5 `: "no"` never executed by the suite (add a test that asserts what this branch decides)', + ]); + assert.deepEqual(problemsOf(sources, new Map()), ['page.html#pick: never loaded by the suite']); + writeFileSync(join(dir, "scripts", "both.test.mjs"), ` +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { inlineScript } from ${JSON.stringify(helper)}; +new Function("assert", "flag", "expected", inlineScript(readFileSync("page.html", "utf8"), "page.html", "pick").src)(assert, false, "no"); +`); + const both = collect(dir, suiteFiles(dir)); + assert.equal(both.status, 0, both.stdout + both.stderr); + assert.deepEqual(problemsOf(sources, inlineRunsFromReports(both.reports, sources).runs), []); + assert.deepEqual([...inlineRunsFromReports([{ result: [{ url: "inline:unknown", functions: [] }, { url: "node:fs" }, { url: pathToFileURL(join(dir, "scripts", "unknown.mjs")).href }] }, {}], sources).runs], []); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); diff --git a/scripts/inline-scripts.test.mjs b/scripts/inline-scripts.test.mjs new file mode 100644 index 0000000..4bb46aa --- /dev/null +++ b/scripts/inline-scripts.test.mjs @@ -0,0 +1,12 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { inlineScript, inlineUrl } from "./inline-scripts.mjs"; + +test("inline extraction pins body, page line and stable source URL", () => { + const html = '

Hi

\n'; + assert.equal(inlineScript(html, 'p.html', 'widget').line, 2); + assert.equal(inlineUrl('p.html', 'widget'), 'inline:p.html#widget'); + assert.equal(inlineScript(html, 'p.html', 'widget').src, '\nwidget();\n\n//# sourceURL=inline:p.html#widget\n'); + assert.throws(() => inlineScript(html, 'p.html', 'missing'), /p.html: expected exactly one.*found 0/); + assert.throws(() => inlineScript(html + html, 'p.html', 'widget'), /found 2/); +});