story-kit: merge 236_story_show_test_results_for_a_story_in_expanded_work_item

This commit is contained in:
Dave
2026-02-28 09:38:51 +00:00
parent c434aa3016
commit 894231428e
6 changed files with 609 additions and 37 deletions

View File

@@ -1,14 +1,20 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { AgentEvent, AgentInfo } from "../api/agents";
import { agentsApi, subscribeAgentStream } from "../api/agents";
import { api } from "../api/client";
import type { TestResultsResponse } from "../api/client";
vi.mock("../api/client", () => ({
api: {
getWorkItemContent: vi.fn(),
},
}));
vi.mock("../api/client", async () => {
const actual =
await vi.importActual<typeof import("../api/client")>("../api/client");
return {
...actual,
api: {
...actual.api,
getWorkItemContent: vi.fn(),
getTestResults: vi.fn(),
},
};
});
vi.mock("../api/agents", () => ({
agentsApi: {
@@ -17,10 +23,12 @@ vi.mock("../api/agents", () => ({
subscribeAgentStream: vi.fn(() => () => {}),
}));
// Dynamic import so mocks are in place before the module loads
import { agentsApi, subscribeAgentStream } from "../api/agents";
import { api } from "../api/client";
const { WorkItemDetailPanel } = await import("./WorkItemDetailPanel");
const mockedGetWorkItemContent = vi.mocked(api.getWorkItemContent);
const mockedGetTestResults = vi.mocked(api.getTestResults);
const mockedListAgents = vi.mocked(agentsApi.listAgents);
const mockedSubscribeAgentStream = vi.mocked(subscribeAgentStream);
@@ -30,16 +38,35 @@ const DEFAULT_CONTENT = {
name: "Big Title Story",
};
describe("WorkItemDetailPanel", () => {
beforeEach(() => {
vi.clearAllMocks();
mockedGetWorkItemContent.mockResolvedValue(DEFAULT_CONTENT);
mockedListAgents.mockResolvedValue([]);
mockedSubscribeAgentStream.mockReturnValue(() => {});
});
const sampleTestResults: TestResultsResponse = {
unit: [
{ name: "test_add", status: "pass", details: null },
{ name: "test_subtract", status: "fail", details: "expected 3, got 4" },
],
integration: [{ name: "test_api_endpoint", status: "pass", details: null }],
};
beforeEach(() => {
vi.clearAllMocks();
mockedGetWorkItemContent.mockResolvedValue(DEFAULT_CONTENT);
mockedGetTestResults.mockResolvedValue(null);
mockedListAgents.mockResolvedValue([]);
mockedSubscribeAgentStream.mockReturnValue(() => {});
});
afterEach(() => {
vi.restoreAllMocks();
});
describe("WorkItemDetailPanel", () => {
it("renders the story name in the header", async () => {
render(<WorkItemDetailPanel storyId="237_bug_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="237_bug_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(screen.getByTestId("detail-panel-title")).toHaveTextContent(
"Big Title Story",
@@ -48,20 +75,38 @@ describe("WorkItemDetailPanel", () => {
});
it("shows loading state initially", () => {
render(<WorkItemDetailPanel storyId="237_bug_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="237_bug_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
expect(screen.getByTestId("detail-panel-loading")).toBeInTheDocument();
});
it("calls onClose when close button is clicked", async () => {
const onClose = vi.fn();
render(<WorkItemDetailPanel storyId="237_bug_test" onClose={onClose} />);
render(
<WorkItemDetailPanel
storyId="237_bug_test"
pipelineVersion={0}
onClose={onClose}
/>,
);
const closeButton = screen.getByTestId("detail-panel-close");
closeButton.click();
expect(onClose).toHaveBeenCalledTimes(1);
});
it("renders markdown headings with constrained inline font size", async () => {
render(<WorkItemDetailPanel storyId="237_bug_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="237_bug_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
const content = screen.getByTestId("detail-panel-content");
const h1 = content.querySelector("h1");
@@ -72,15 +117,14 @@ describe("WorkItemDetailPanel", () => {
});
describe("WorkItemDetailPanel - Agent Logs", () => {
beforeEach(() => {
vi.clearAllMocks();
mockedGetWorkItemContent.mockResolvedValue(DEFAULT_CONTENT);
mockedListAgents.mockResolvedValue([]);
mockedSubscribeAgentStream.mockReturnValue(() => {});
});
it("shows placeholder when no agent is assigned to the story", async () => {
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("detail-panel-content");
const placeholder = screen.getByTestId("placeholder-agent-logs");
expect(placeholder).toBeInTheDocument();
@@ -101,7 +145,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
const statusBadge = await screen.findByTestId("agent-status-badge");
expect(statusBadge).toHaveTextContent("coder-1");
@@ -130,7 +180,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("agent-status-badge");
@@ -169,7 +225,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("agent-status-badge");
@@ -218,7 +280,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("agent-status-badge");
@@ -257,7 +325,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("agent-status-badge");
@@ -291,7 +365,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
const statusBadge = await screen.findByTestId("agent-status-badge");
expect(statusBadge).toHaveTextContent("completed");
@@ -312,7 +392,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
const statusBadge = await screen.findByTestId("agent-status-badge");
expect(statusBadge).toHaveTextContent("failed");
@@ -333,7 +419,13 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
];
mockedListAgents.mockResolvedValue(agentList);
render(<WorkItemDetailPanel storyId="42_story_test" onClose={() => {}} />);
render(
<WorkItemDetailPanel
storyId="42_story_test"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await screen.findByTestId("agent-logs-section");
@@ -342,3 +434,121 @@ describe("WorkItemDetailPanel - Agent Logs", () => {
).not.toBeInTheDocument();
});
});
describe("WorkItemDetailPanel - Test Results", () => {
it("shows empty test results message when no results exist", async () => {
mockedGetTestResults.mockResolvedValue(null);
render(
<WorkItemDetailPanel
storyId="42_story_foo"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(screen.getByTestId("test-results-empty")).toBeInTheDocument();
});
expect(screen.getByText("No test results recorded")).toBeInTheDocument();
});
it("shows unit and integration test results when available", async () => {
mockedGetTestResults.mockResolvedValue(sampleTestResults);
render(
<WorkItemDetailPanel
storyId="42_story_foo"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(screen.getByTestId("test-results-content")).toBeInTheDocument();
});
// Unit test section
expect(screen.getByTestId("test-section-unit")).toBeInTheDocument();
expect(
screen.getByText("Unit Tests (1 passed, 1 failed)"),
).toBeInTheDocument();
// Integration test section
expect(screen.getByTestId("test-section-integration")).toBeInTheDocument();
expect(
screen.getByText("Integration Tests (1 passed, 0 failed)"),
).toBeInTheDocument();
});
it("shows pass/fail status and details for each test", async () => {
mockedGetTestResults.mockResolvedValue(sampleTestResults);
render(
<WorkItemDetailPanel
storyId="42_story_foo"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(screen.getByTestId("test-case-test_add")).toBeInTheDocument();
});
// Passing test
expect(screen.getByTestId("test-status-test_add")).toHaveTextContent(
"PASS",
);
expect(screen.getByText("test_add")).toBeInTheDocument();
// Failing test with details
expect(screen.getByTestId("test-status-test_subtract")).toHaveTextContent(
"FAIL",
);
expect(screen.getByText("test_subtract")).toBeInTheDocument();
expect(screen.getByTestId("test-details-test_subtract")).toHaveTextContent(
"expected 3, got 4",
);
// Integration test
expect(
screen.getByTestId("test-status-test_api_endpoint"),
).toHaveTextContent("PASS");
});
it("re-fetches test results when pipelineVersion changes", async () => {
mockedGetTestResults.mockResolvedValue(null);
const { rerender } = render(
<WorkItemDetailPanel
storyId="42_story_foo"
pipelineVersion={0}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(mockedGetTestResults).toHaveBeenCalledTimes(1);
});
// Update with new results and bump pipelineVersion.
mockedGetTestResults.mockResolvedValue(sampleTestResults);
rerender(
<WorkItemDetailPanel
storyId="42_story_foo"
pipelineVersion={1}
onClose={() => {}}
/>,
);
await waitFor(() => {
expect(mockedGetTestResults).toHaveBeenCalledTimes(2);
});
await waitFor(() => {
expect(screen.getByTestId("test-results-content")).toBeInTheDocument();
});
});
});