FN-8906: scope Stats runtime-status assertions

Scope Task Detail Stats status assertions to their semantic region.

- Centralize the shared Stats runtime-status assertion helper.
- Update Stats-tab integration assertions to avoid ambiguous status queries.

Files changed:
 ...lModal.inline-editing-and-integrations.test.tsx | 10 ++++++++--
 .../__tests__/TaskDetailModal.rendering.test.tsx   | 19 ++----------------
 .../__tests__/TaskDetailModal.test-helpers.ts      | 23 +++++++++++++++++++++-
 3 files changed, 32 insertions(+), 20 deletions(-)

Fusion-Task-Id: FN-8906
Fusion-Task-Lineage: 980f24a1-0409-46ba-9957-a87329e9831e
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-09 10:03:49 -07:00
parent 6ee8994767
commit 5108cfc312
3 changed files with 32 additions and 20 deletions

View File

@@ -17,6 +17,7 @@ import {
mockConfirm,
mockUsePluginUiSlots,
expectBaseRule,
expectSingleStatsRuntimeStatus,
readDashboardStylesSource,
setupTaskDetailModalHooks,
} from "./TaskDetailModal.test-helpers";
@@ -83,6 +84,11 @@ function getRuleBlockFromSelectorList(css: string, selector: string): string {
return ruleEnd === -1 ? "" : css.slice(ruleStart + 1, ruleEnd);
}
/*
FNXC:TaskDetailStatsAssertions 2026-08-09-16:50:
FN-8906 requires Stats-tab runtime-status assertions to be scoped to the named Stats region because
the modal header lifecycle badge intentionally renders the same raw status string.
*/
describe("TaskDetailModal", () => {
describe("source issue metadata", () => {
beforeEach(() => {
@@ -2440,7 +2446,7 @@ describe("TaskDetailModal", () => {
expect(screen.getByText("Execution Details")).toBeInTheDocument();
expect(screen.getByText("Loading token statistics…")).toBeDefined();
expect(screen.getAllByText("Fast").length).toBeGreaterThan(0);
expect(screen.getByText("executing")).toBeInTheDocument();
expectSingleStatsRuntimeStatus("executing");
});
it("shows spec content after fetchTaskDetail resolves", async () => {
@@ -2529,7 +2535,7 @@ describe("TaskDetailModal", () => {
expect(screen.getByText("Execution mode")).toBeInTheDocument();
expect(screen.getByText("Runtime status")).toBeInTheDocument();
expect(screen.getAllByText("Fast").length).toBeGreaterThan(0);
expect(screen.getByText("executing")).toBeInTheDocument();
expectSingleStatsRuntimeStatus("executing");
expect(screen.getByText((1200).toLocaleString())).toBeInTheDocument();
expect(screen.getByText((450).toLocaleString())).toBeInTheDocument();
expect(screen.getByText((210).toLocaleString())).toBeInTheDocument();

View File

@@ -12,7 +12,7 @@ query ambiguous once the trigger stopped being a mobile-only affordance.
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent, act, waitFor, cleanup, within } from "@testing-library/react";
import { render, screen, fireEvent, act, waitFor, cleanup } from "@testing-library/react";
// FNXC:Markdown 2026-06-23-03:30: Mock the heavy `mermaid` library so the shared
// markdown pipeline's MermaidDiagram resolves without loading the real renderer.
@@ -35,6 +35,7 @@ import {
mockConfirm,
mockUsePluginUiSlots,
expectBaseRule,
expectSingleStatsRuntimeStatus,
readDashboardStylesSource,
resetTaskDetailFetchMock,
setupTaskDetailModalHooks,
@@ -45,22 +46,6 @@ import * as dashboardApi from "../../api";
import { FileBrowserProvider } from "../../context/FileBrowserContext";
import type { Task } from "@fusion/core";
/*
FNXC:TaskDetailOptimisticOpening 2026-08-05-07:39:
A running task deliberately exposes its raw runtime status in two ownership regions: the modal
header's lifecycle badge and the Stats panel's Runtime status row. Optimistic-opening assertions
must scope the Stats claim to its named semantic region, then assert one row there and the expected
two owned values overall; this catches a duplicated Stats panel without treating legitimate header
context as a production rendering defect.
*/
function expectSingleStatsRuntimeStatus(status: string) {
const statsPanel = screen.getByRole("region", { name: "Task execution statistics" });
expect(within(statsPanel).getByText(status)).toBeInTheDocument();
expect(within(statsPanel).getAllByText(status)).toHaveLength(1);
expect(screen.getByTestId("task-detail-status-badge")).toHaveTextContent(status);
expect(screen.getAllByText(status)).toHaveLength(2);
}
setupTaskDetailModalHooks();
describe("TaskDetailModal", () => {

View File

@@ -3,7 +3,7 @@ import { loadAllAppCss } from "../../test/cssFixture";
import React from "react";
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
import { render, screen, fireEvent, act, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { TaskDetailModal, TaskDetailContent } from "../TaskDetailModal";
import type { TaskDetail, Column, MergeResult, Task } from "@fusion/core";
@@ -16,6 +16,27 @@ const taskDetailSseSubscriptions = vi.hoisted(() => [] as Array<{
export { taskDetailSseSubscriptions };
/*
FNXC:TaskDetailOptimisticOpening 2026-08-05-07:39:
A running task deliberately exposes its raw runtime status in two ownership regions: the modal
header's lifecycle badge and the Stats panel's Runtime status row. Optimistic-opening assertions
must scope the Stats claim to its named semantic region, then assert one row there and the expected
two owned values overall; this catches a duplicated Stats panel without treating legitimate header
context as a production rendering defect.
FNXC:TaskDetailStatsAssertions 2026-08-09-16:50:
FN-8906 requires every TaskDetailModal test to use this shared helper: a non-empty raw runtime
status is owned by the header lifecycle badge and the Stats Runtime status row, so an unscoped
getByText(status) after opening Stats is ambiguous.
*/
export function expectSingleStatsRuntimeStatus(status: string): void {
const statsPanel = screen.getByRole("region", { name: "Task execution statistics" });
expect(within(statsPanel).getByText(status)).toBeInTheDocument();
expect(within(statsPanel).getAllByText(status)).toHaveLength(1);
expect(screen.getByTestId("task-detail-status-badge")).toHaveTextContent(status);
expect(screen.getAllByText(status)).toHaveLength(2);
}
vi.mock("../../sse-bus", () => ({
subscribeSse: vi.fn((url: string, options: { events?: Record<string, (event: MessageEvent) => void> }) => {
taskDetailSseSubscriptions.push({ url, options });