fix(FN-2504): remove hardcoded workflow step and stabilize dashboard timeouts

- Stop injecting a hardcoded Browser Verification option in WorkflowResultsTab and rely only on fetched workflow step definitions
- Normalize workflow step checkbox test IDs to be id-based for all options, including template-backed Browser Verification steps
- Extend WorkflowResultsTab coverage to assert Browser Verification renders exactly once when provided by API data
- Increase dashboard Vitest timeout defaults and update the slow route test timeout to reduce flaky failures under concurrent workspace runs
This commit is contained in:
Fusion
2026-04-25 12:18:55 -07:00
committed by gsxdsm
parent 61f09b2e32
commit f1aa2fc219
4 changed files with 39 additions and 17 deletions

View File

@@ -233,22 +233,12 @@ export function WorkflowResultsTab({
const selectedWorkflowSteps = enabledWorkflowSteps ?? []; const selectedWorkflowSteps = enabledWorkflowSteps ?? [];
const workflowStepOptions = useMemo<WorkflowStepOption[]>(() => { const workflowStepOptions = useMemo<WorkflowStepOption[]>(() => {
const fetched = allWorkflowSteps.map((step) => ({ return allWorkflowSteps.map((step) => ({
id: step.id, id: step.id,
name: step.name, name: step.name,
description: step.description, description: step.description,
phase: (step.phase || "pre-merge") as "pre-merge" | "post-merge", phase: (step.phase || "pre-merge") as "pre-merge" | "post-merge",
})); }));
return [
...fetched,
{
id: "browser-verification",
name: "Browser Verification",
description: "Verify web application functionality using browser automation (agent-browser)",
phase: "pre-merge",
},
];
}, [allWorkflowSteps]); }, [allWorkflowSteps]);
const workflowStepLookup = useMemo(() => { const workflowStepLookup = useMemo(() => {
@@ -362,9 +352,7 @@ export function WorkflowResultsTab({
<label <label
key={step.id} key={step.id}
className="checkbox-label workflow-step-item" className="checkbox-label workflow-step-item"
data-testid={step.id === "browser-verification" data-testid={`workflow-step-checkbox-${step.id}`}
? "browser-verification-checkbox"
: `workflow-step-checkbox-${step.id}`}
> >
<input <input
type="checkbox" type="checkbox"

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach, vi } from "vitest"; import { describe, it, expect, beforeEach, vi } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { render, screen, fireEvent, waitFor, within } from "@testing-library/react";
import { WorkflowResultsTab } from "../WorkflowResultsTab"; import { WorkflowResultsTab } from "../WorkflowResultsTab";
import { fetchWorkflowSteps } from "../../api"; import { fetchWorkflowSteps } from "../../api";
import type { WorkflowStep, WorkflowStepResult } from "@fusion/core"; import type { WorkflowStep, WorkflowStepResult } from "@fusion/core";
@@ -34,6 +34,18 @@ describe("WorkflowResultsTab", () => {
createdAt: "2026-04-01T00:00:00Z", createdAt: "2026-04-01T00:00:00Z",
updatedAt: "2026-04-01T00:00:00Z", updatedAt: "2026-04-01T00:00:00Z",
}, },
{
id: "WS-103",
name: "Browser Verification",
description: "Verify web application functionality using browser automation",
mode: "prompt",
phase: "pre-merge",
prompt: "Verify browser flows",
enabled: true,
createdAt: "2026-04-01T00:00:00Z",
updatedAt: "2026-04-01T00:00:00Z",
templateId: "browser-verification",
},
]; ];
beforeEach(() => { beforeEach(() => {
@@ -555,7 +567,7 @@ describe("WorkflowResultsTab", () => {
fireEvent.click(screen.getByTestId("workflow-steps-edit-toggle")); fireEvent.click(screen.getByTestId("workflow-steps-edit-toggle"));
expect(screen.getByTestId("workflow-steps-editor")).toBeInTheDocument(); expect(screen.getByTestId("workflow-steps-editor")).toBeInTheDocument();
await screen.findByTestId("workflow-step-checkbox-WS-101"); await screen.findByTestId("workflow-step-checkbox-WS-101");
expect(screen.getByTestId("browser-verification-checkbox")).toBeInTheDocument(); expect(screen.getByTestId("workflow-step-checkbox-WS-103")).toBeInTheDocument();
fireEvent.click(screen.getByTestId("workflow-steps-edit-toggle")); fireEvent.click(screen.getByTestId("workflow-steps-edit-toggle"));
expect(screen.queryByTestId("workflow-steps-editor")).not.toBeInTheDocument(); expect(screen.queryByTestId("workflow-steps-editor")).not.toBeInTheDocument();
@@ -660,6 +672,24 @@ describe("WorkflowResultsTab", () => {
await screen.findByTestId("workflow-step-checkbox-WS-101"); await screen.findByTestId("workflow-step-checkbox-WS-101");
}); });
it("renders Browser Verification exactly once when fetched steps include the template-backed option", async () => {
render(
<WorkflowResultsTab
taskId="FN-001"
results={[]}
canEdit
enabledWorkflowSteps={["WS-103"]}
/>,
);
fireEvent.click(screen.getByTestId("workflow-steps-edit-toggle"));
const editor = await screen.findByTestId("workflow-steps-editor");
await screen.findByTestId("workflow-step-checkbox-WS-103");
expect(screen.queryByTestId("browser-verification-checkbox")).not.toBeInTheDocument();
expect(within(editor).getAllByText("Browser Verification")).toHaveLength(1);
});
it("fetches workflow step definitions when canEdit and projectId are provided", async () => { it("fetches workflow step definitions when canEdit and projectId are provided", async () => {
render( render(
<WorkflowResultsTab <WorkflowResultsTab

View File

@@ -4376,7 +4376,7 @@ describe("Pause/Unpause endpoints", () => {
} finally { } finally {
rmSync(tempDir, { recursive: true, force: true }); rmSync(tempDir, { recursive: true, force: true });
} }
}); }, 15_000);
it("POST /tasks/:id/comments — skips heartbeat wake when task has no assigned agent", async () => { it("POST /tasks/:id/comments — skips heartbeat wake when task has no assigned agent", async () => {
const heartbeatMonitor = { const heartbeatMonitor = {

View File

@@ -33,6 +33,10 @@ export default defineConfig({
poolOptions: { threads: { minThreads: 1, maxThreads: maxWorkers }, forks: { minForks: 1, maxForks: maxWorkers } }, poolOptions: { threads: { minThreads: 1, maxThreads: maxWorkers }, forks: { minForks: 1, maxForks: maxWorkers } },
fileParallelism: true, fileParallelism: true,
isolate: true, isolate: true,
// Dashboard route and integration-heavy suites can exceed the Vitest
// 5s default under workspace-concurrent runs.
testTimeout: 15_000,
hookTimeout: 15_000,
coverage: { coverage: {
enabled: false, enabled: false,
reporter: ["text", "html", "json"], reporter: ["text", "html", "json"],