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"; import { nodeWebObserveAnalyzerProjectSource } from "./hwlab-node-web-observe-analyzer-project-source"; import { nodeWebObserveRunnerControlSource } from "./hwlab-node-web-observe-runner-control-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, ); assert.match( MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR, /\[data-testid="mdtodo-task-page-fact"\]/u, ); const source = nodeWebObserveRunnerSamplingSource(); assert.ok( source.includes( `measurePaneGap("task-tree", '[data-testid="mdtodo-task-tree"]', ${JSON.stringify(MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR)})`, ), ); assert.match( source, /semanticTaskCandidates\.length > 0 \? semanticTaskCandidates : fallbackTaskCandidates/u, ); assert.match( source, /taskCandidates\.filter\(\(candidate\) => !taskRefElement\(candidate\)\)\.length/u, ); assert.doesNotMatch(source, /taskCandidates\.length - taskItems\.length/u); assert.match(source, /mdtodo-body-read/u); assert.match(source, /mdtodo-launch-workbench/u); 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); }); test("MDTODO pane gap ignores a naturally short task tree but keeps primary pane regressions", () => { const projectManagementPaneGapRows = new Function( "maxNumber", "projectManagementSampleRef", `${nodeWebObserveAnalyzerProjectSource()}; return projectManagementPaneGapRows;`, )( (values: unknown[]) => Math.max(0, ...values.map((value) => Number(value ?? 0))), (sample: Record) => ({ seq: sample.seq ?? null }), ) as (samples: unknown[]) => { actionable: unknown[]; ignored: unknown[] }; const pane = (name: string, bottomGapPx: number, bottomGapRatio: number) => ({ name, visible: true, widthPx: 300, heightPx: 600, bottomGapPx, bottomGapRatio, contentNodeCount: 4, }); const sample = (paneGaps: unknown[]) => ({ seq: 1, projectManagement: { pageKind: "project-management-mdtodo", selectedTaskRef: { hash: "sha256:opaque" }, paneGaps, }, }); assert.deepEqual( projectManagementPaneGapRows([sample([pane("task-tree", 391, 0.618)])]), { actionable: [], ignored: [], valuesRedacted: true }, ); assert.equal( projectManagementPaneGapRows([sample([pane("task-detail", 391, 0.618)])]).actionable.length, 1, ); assert.equal( projectManagementPaneGapRows([sample([ pane("task-tree", 240, 0.4), pane("task-detail", 180, 0.3), ])]).actionable.length, 1, ); }); test("MDTODO command readiness accepts a selected mobile task when the hidden tree has no visible rows", async () => { const source = nodeWebObserveRunnerControlSource(); const makeReady = (snapshot: Record) => new Function( "projectManagementCommandSnapshot", "safeUrlPath", "currentPageUrl", "page", `${source}; return waitForProjectManagementCommandReady;`, )( async () => snapshot, () => String(snapshot.path ?? ""), () => `https://hwlab.pikapython.com${String(snapshot.path ?? "")}`, { waitForTimeout: async () => undefined }, ) as (options: { timeoutMs: number }) => Promise<{ ok: boolean; reason: string }>; const selectedMobileTask = { path: "/projects/mdtodo/sources/source/files/file/tasks/R1", pageKind: "project-management-mdtodo", sourceCount: 3, fileCount: 18, taskCount: 0, selectedTaskRef: { hash: "sha256:opaque" }, taskBodyVisible: true, launchButtonVisible: true, }; assert.equal((await makeReady(selectedMobileTask)({ timeoutMs: 1 })).ok, true); const unselectedRoot = { path: "/projects/mdtodo", pageKind: "project-management-mdtodo", sourceCount: 3, fileCount: 18, taskCount: 0, }; assert.equal((await makeReady(unselectedRoot)({ timeoutMs: 1 })).ok, false); });