test(dashboard): align app tests with recent product changes (FN-7057/7340/7156/7342/6825/7265)

Update five dashboard app test files whose assertions drifted from
intentional product changes that landed on main without updating them:

- graph-workflow-header: FN-7057 treats stale/missing workflow ids as the
  default workflow, so FN-unknown now shows under the default selection.
- EngineControlMenu.css: FN-7340 added a 768px range-thumb touch-target
  block; narrow the popover-breakpoint assertion to that selector.
- MissionManager.delete-confirm: FN-7156 removed first-mission auto-select;
  explicitly select the mission before the detail-delete flow.
- board-mobile-initial-render: FN-7342 preserves board column scroll during
  stabilization; FN-6825 renders the workflow toolbar on options, not callbacks.
- workflow-auto-layout: FN-7265 removed the stepwise review node (per-step
  review lives in the foreach); the connected run ends at completion-summary.

No assertion was loosened or deleted to force a pass; each change cites the
breaking commit via an FNXC comment. packages/dashboard is private (no changeset).
This commit is contained in:
gsxdsm
2026-07-07 08:27:26 -07:00
parent f3c50de7e7
commit 7e089e188e
5 changed files with 60 additions and 8 deletions

View File

@@ -89,11 +89,15 @@ describe("Graph workflow header integration", () => {
expect(headerSlot.contains(selector)).toBe(true);
const contextTasks = screen.getByTestId("graph-plugin-context-tasks");
/*
FNXC:GraphWorkflowSelection 2026-07-07-08:15:
FN-7057 changed filterTasksByGraphWorkflowSelection to treat stale taskWorkflowIds entries that reference deleted/missing workflows as DEFAULT-workflow assignments (so tasks never vanish from every view). FN-unknown carries wf-missing, so under the default Coding selection it now resolves to the default workflow and is SHOWN, not filtered out.
*/
await waitFor(() => {
expect(within(contextTasks).getByTestId("graph-context-task-FN-default")).toBeInTheDocument();
expect(within(contextTasks).getByTestId("graph-context-task-FN-unassigned")).toBeInTheDocument();
expect(within(contextTasks).queryByTestId("graph-context-task-FN-review")).toBeNull();
expect(within(contextTasks).queryByTestId("graph-context-task-FN-unknown")).toBeNull();
expect(within(contextTasks).getByTestId("graph-context-task-FN-unknown")).toBeInTheDocument();
});
fireEvent.click(selector);

View File

@@ -90,6 +90,28 @@ function extractMobileMediaBlocks(css: string): string {
return blocks.join("\n");
}
function extractMediaBlocksForWidth(css: string, width: string): string {
const blocks: string[] = [];
const regex = new RegExp(`@media[^{}]*\\(max-width:\\s*${width}\\)[^{]*\\{`, "g");
let match: RegExpExecArray | null;
while ((match = regex.exec(css)) !== null) {
const startIdx = match.index + match[0].length;
let braceCount = 1;
let endIdx = startIdx;
while (braceCount > 0 && endIdx < css.length) {
if (css[endIdx] === "{") braceCount += 1;
if (css[endIdx] === "}") braceCount -= 1;
endIdx += 1;
}
if (braceCount === 0) {
blocks.push(css.slice(startIdx, endIdx - 1));
}
}
return blocks.join("\n");
}
function normalizeCss(css: string): string {
return css.replace(/\s+/g, " ").trim();
}
@@ -132,7 +154,11 @@ describe("EngineControlMenu CSS token validity (FN-6862)", () => {
it("renders the mobile and narrow-tablet footer popover as a viewport-safe bottom panel", () => {
expect(componentCss).toContain("@media (max-width: 1024px)");
expect(componentCss).not.toContain("@media (max-width: 768px)");
/*
FNXC:EngineControls 2026-07-07-08:20:
FN-7340 added a @media (max-width: 768px) block for range-slider thumb touch-target sizing — a separate concern from popover placement, which stays on the 1024px breakpoint (extractMobileMediaBlocks). The earlier whole-file ban on "@media (max-width: 768px)" was too broad; assert instead that the 768px block never repositions the popover.
*/
expect(extractMediaBlocksForWidth(componentCss, "768px")).not.toContain(".engine-control-menu__popover");
const desktopPopoverBlock = normalizeCss(extractRuleBlock(componentCss, ".engine-control-menu__popover"));
const footerDesktopPopoverBlock = normalizeCss(

View File

@@ -227,6 +227,12 @@ describe("MissionManager mission delete confirmation", () => {
const addToast = vi.fn();
renderMissionManager(addToast);
/*
FNXC:MissionManager 2026-07-07-08:25:
FN-7156 made inline Missions open on the overview (no first-mission auto-selection), so a selected-detail delete must first click the mission in the list to load its detail before the fetchMission/delete-modal flow runs.
*/
fireEvent.click(await findMissionListItem("Build Auth System"));
await waitFor(() => {
expect(mockFetchMission).toHaveBeenCalledWith("M-001", projectId);
});

View File

@@ -127,7 +127,7 @@ describe("Board mobile initial render stabilization (FN-4574)", () => {
vi.unstubAllGlobals();
});
it("normalizes scrollLeft to 0 on initial mobile render and keeps snap style in CSS, not inline", () => {
it("preserves board column scroll during initial mobile stabilization while keeping snap style in CSS, not inline", () => {
const viewportSpy = mockViewport(375);
const raf = vi.fn<(cb: FrameRequestCallback) => number>((cb) => {
setTimeout(() => cb(0), 0);
@@ -145,14 +145,18 @@ describe("Board mobile initial render stabilization (FN-4574)", () => {
act(() => {
vi.runOnlyPendingTimers();
});
expect(board.scrollLeft).toBe(0);
/*
FNXC:BoardMobile 2026-07-07-08:30:
FN-7342 (preserve board scroll during refresh stabilization) removed the `boardEl.scrollLeft = 0` reset from mobile stabilization — #board is the user's horizontal scroller, so stabilization now only normalizes document-level horizontal drift and must not force the board back to triage. The board's column scroll position is therefore preserved (500) instead of reset to 0; rAF scheduling and the CSS-not-inline snap invariant still hold.
*/
expect(board.scrollLeft).toBe(500);
expect(raf).toHaveBeenCalled();
expect(board.style.scrollSnapType).toBe("");
viewportSpy.mockRestore();
});
it("re-anchors on pageshow persisted restore for mobile", () => {
it("preserves board column scroll on pageshow persisted restore for mobile", () => {
const viewportSpy = mockViewport(375);
vi.stubGlobal("requestAnimationFrame", (cb: FrameRequestCallback) => {
setTimeout(() => cb(0), 0);
@@ -176,7 +180,11 @@ describe("Board mobile initial render stabilization (FN-4574)", () => {
act(() => {
vi.runOnlyPendingTimers();
});
expect(board.scrollLeft).toBe(0);
/*
FNXC:BoardMobile 2026-07-07-08:32:
FN-7342 keeps pageshow/bfcache stabilization scoped to document-level drift, so the board column scroll set before the restore (500) is preserved rather than re-anchored to 0.
*/
expect(board.scrollLeft).toBe(500);
viewportSpy.mockRestore();
});
@@ -468,7 +476,11 @@ describe("Board mobile initial render stabilization (FN-4574)", () => {
expect(document.querySelector("main.board.board-workflow-columns")).not.toBeNull();
});
expect(document.querySelector(".board-workflow-toolbar")).toBeNull();
/*
FNXC:BoardMobile 2026-07-07-08:35:
FN-6825 (combine workflow actions in switcher) moved edit/create into the WorkflowSwitcher, so shouldRenderWorkflowControls is now `workflowOptions.length > 0` rather than gated on onCreateWorkflow/onOpenWorkflowEditor. A Board rendered without those callbacks still shows the switcher toolbar whenever workflow options exist, so the no-callbacks toolbar shell no longer disappears.
*/
expect(document.querySelector(".board-workflow-toolbar")).not.toBeNull();
expect(document.querySelectorAll(".board-workflow-columns [data-testid^='column-']")).toHaveLength(6);
viewportSpy.mockRestore();

View File

@@ -236,11 +236,15 @@ describe("autoLayout — foreach / unreachable / cycles", () => {
"code-review",
"review",
]);
/*
FNXC:WorkflowAutoLayout 2026-07-07-08:10:
FN-7265 (align per-step review workflow) removed the standalone `review` prompt node from the stepwise IR — per-step review now happens inside the foreach (step-review), so the post-foreach success path is steps → browser-verification → code-review → completion-summary → merge-gate. The connected editor run for the stepwise built-in therefore ends at `completion-summary`, not `review`.
*/
assertAutoLayoutRunConnected("stepwise", workflowDef(BUILTIN_STEPWISE_CODING_WORKFLOW_IR), [
"steps",
"browser-verification",
"code-review",
"review",
"completion-summary",
]);
});