Story 31: View Upcoming Stories
Add GET /workflow/upcoming endpoint that reads .story_kit/stories/upcoming/ and returns story IDs with names parsed from frontmatter. Add UpcomingPanel component wired into Chat view with loading, error, empty, and list states. 12 new tests (3 backend, 9 frontend) all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,8 +9,11 @@ const baseProps = {
|
||||
gateStatusColor: "#aaa",
|
||||
isGateLoading: false,
|
||||
gateError: null,
|
||||
coverageError: null,
|
||||
lastGateRefresh: null,
|
||||
onRefresh: vi.fn(),
|
||||
onCollectCoverage: vi.fn(),
|
||||
isCollectingCoverage: false,
|
||||
};
|
||||
|
||||
describe("GatePanel", () => {
|
||||
@@ -21,9 +24,7 @@ describe("GatePanel", () => {
|
||||
|
||||
it("shows loading message when isGateLoading is true", () => {
|
||||
render(<GatePanel {...baseProps} isGateLoading={true} />);
|
||||
expect(
|
||||
screen.getByText("Loading workflow gates..."),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("Loading workflow gates...")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows error with retry button", async () => {
|
||||
@@ -64,13 +65,12 @@ describe("GatePanel", () => {
|
||||
warning: null,
|
||||
summary: { total: 5, passed: 5, failed: 0 },
|
||||
missingCategories: [],
|
||||
coverageReport: null,
|
||||
}}
|
||||
gateStatusLabel="Ready to accept"
|
||||
/>,
|
||||
);
|
||||
expect(
|
||||
screen.getByText(/5\/5 passing, 0 failing/),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText(/5\/5 passing, 0 failing/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows missing categories", () => {
|
||||
@@ -83,12 +83,11 @@ describe("GatePanel", () => {
|
||||
warning: null,
|
||||
summary: { total: 0, passed: 0, failed: 0 },
|
||||
missingCategories: ["unit", "integration"],
|
||||
coverageReport: null,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
expect(
|
||||
screen.getByText("Missing: unit, integration"),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("Missing: unit, integration")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows warning text", () => {
|
||||
@@ -101,6 +100,7 @@ describe("GatePanel", () => {
|
||||
warning: "Multiple tests failing — fix one at a time.",
|
||||
summary: { total: 4, passed: 2, failed: 2 },
|
||||
missingCategories: [],
|
||||
coverageReport: null,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
@@ -119,12 +119,11 @@ describe("GatePanel", () => {
|
||||
warning: null,
|
||||
summary: { total: 2, passed: 1, failed: 1 },
|
||||
missingCategories: [],
|
||||
coverageReport: null,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
expect(
|
||||
screen.getByText("No approved test plan."),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("No approved test plan.")).toBeInTheDocument();
|
||||
expect(screen.getByText("Tests are failing.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -132,9 +131,7 @@ describe("GatePanel", () => {
|
||||
const onRefresh = vi.fn();
|
||||
render(<GatePanel {...baseProps} onRefresh={onRefresh} />);
|
||||
|
||||
await userEvent.click(
|
||||
screen.getByRole("button", { name: "Refresh" }),
|
||||
);
|
||||
await userEvent.click(screen.getByRole("button", { name: "Refresh" }));
|
||||
expect(onRefresh).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user