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:
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -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"],
|
||||||
|
|||||||
Reference in New Issue
Block a user