diff --git a/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts b/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts new file mode 100644 index 00000000..134d21c1 --- /dev/null +++ b/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import { test } from "bun:test"; + +import { + MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR, + nodeWebObserveRunnerSamplingSource, +} from "./hwlab-node-web-observe-runner-sampling-source"; + +test("MDTODO task tree pane gap treats the pinned facts footer as content", async () => { + assert.match(MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR, /\[data-testid="mdtodo-task-tree-facts"\]/u); + + const source = nodeWebObserveRunnerSamplingSource(); + assert.ok(source.includes(`measurePaneGap("task-tree", '[data-testid="mdtodo-task-tree"]', ${JSON.stringify(MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR)})`)); + + const child = Bun.spawn(["node", "--input-type=module", "--check", "-"], { + stdin: "pipe", + stdout: "pipe", + stderr: "pipe", + }); + child.stdin.write(source); + child.stdin.end(); + const [stderr, exitCode] = await Promise.all([new Response(child.stderr).text(), child.exited]); + assert.equal(exitCode, 0, stderr); +}); diff --git a/scripts/src/hwlab-node-web-observe-runner-sampling-source.ts b/scripts/src/hwlab-node-web-observe-runner-sampling-source.ts index 33e7a130..c0b6809d 100644 --- a/scripts/src/hwlab-node-web-observe-runner-sampling-source.ts +++ b/scripts/src/hwlab-node-web-observe-runner-sampling-source.ts @@ -1,6 +1,19 @@ // SPEC: PJ2026-01040111 long-running Workbench observation. // Responsibility: Runner page sampling, screenshots, DOM digest, response body summaries, and command record source fragment. +export const MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR = [ + '[data-testid="mdtodo-task-tree-facts"]', + "[data-task-ref]", + '[role="treeitem"]', + '[role="listitem"]', + "li", + "button", + "input", + "select", + ".task-row-shell", + ".task-tools", +].join(", "); + export function nodeWebObserveRunnerSamplingSource(): string { return String.raw`async function preflightSummary() { return { currentUrl: currentPageUrl(), title: await page.title().catch(() => null), pageId, auth: publicAuth(auth) }; @@ -461,7 +474,7 @@ async function sampleOnePage(targetPage, { reason, groupSeq, pageRole, targetPag }; }; const paneGaps = [ - measurePaneGap("task-tree", '[data-testid="mdtodo-task-tree"]', '[data-task-ref], [role="treeitem"], [role="listitem"], li, button, input, select, .task-row-shell, .task-tools'), + measurePaneGap("task-tree", '[data-testid="mdtodo-task-tree"]', ${JSON.stringify(MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR)}), measurePaneGap("task-detail", '[data-testid="mdtodo-task-detail"]', '[data-testid="mdtodo-body-rendered"] > *, [data-testid="mdtodo-report-section"], [data-testid="mdtodo-workbench-launch"], [data-testid="mdtodo-delete-task"], [data-testid="mdtodo-task-detail-error"], .mdtodo-detail-header, .task-status-stack > *, .task-document-footer'), measurePaneGap("report-sidebar", '[data-testid="mdtodo-report-sidebar"]', '[data-testid="mdtodo-report-preview"] > *, [data-testid="mdtodo-report-error"], [data-testid="mdtodo-report-fullscreen"], [data-testid="mdtodo-report-close"], .report-sidebar-header, .report-preview .markdown-body > *'), ];