Files
storkit/frontend/tests/e2e/story-todos.spec.ts

167 lines
4.5 KiB
TypeScript
Raw Normal View History

import { expect, test } from "@playwright/test";
import type {
AcceptanceResponse,
ReviewListResponse,
TodoListResponse,
} from "../../src/api/workflow";
function mockChatApis(
page: import("@playwright/test").Page,
overrides: {
acceptance?: AcceptanceResponse;
reviewQueue?: ReviewListResponse;
todos?: TodoListResponse;
} = {},
) {
const acceptance: AcceptanceResponse = overrides.acceptance ?? {
can_accept: false,
reasons: ["No test results recorded for the story."],
warning: null,
summary: { total: 0, passed: 0, failed: 0 },
missing_categories: ["unit", "integration"],
};
const reviewQueue: ReviewListResponse = overrides.reviewQueue ?? {
stories: [],
};
const todos: TodoListResponse = overrides.todos ?? {
stories: [],
};
return Promise.all([
page.route("**/api/projects", (route) =>
route.fulfill({ json: ["/tmp/test-project"] }),
),
page.route("**/api/io/fs/home", (route) =>
route.fulfill({ json: "/tmp" }),
),
page.route("**/api/project", (route) => {
if (route.request().method() === "POST") {
return route.fulfill({ json: "/tmp/test-project" });
}
if (route.request().method() === "DELETE") {
return route.fulfill({ json: true });
}
return route.fulfill({ json: null });
}),
page.route("**/api/ollama/models**", (route) =>
route.fulfill({ json: ["llama3.1"] }),
),
page.route("**/api/anthropic/key/exists", (route) =>
route.fulfill({ json: false }),
),
page.route("**/api/anthropic/models", (route) =>
route.fulfill({ json: [] }),
),
page.route("**/api/model", (route) => {
if (route.request().method() === "POST") {
return route.fulfill({ json: true });
}
return route.fulfill({ json: null });
}),
page.route("**/api/workflow/acceptance", (route) => {
if (route.request().url().includes("/ensure")) return route.fallback();
return route.fulfill({ json: acceptance });
}),
page.route("**/api/workflow/review/all", (route) =>
route.fulfill({ json: reviewQueue }),
),
page.route("**/api/workflow/acceptance/ensure", (route) =>
route.fulfill({ json: true }),
),
page.route("**/api/io/fs/list/absolute**", (route) =>
route.fulfill({ json: [] }),
),
page.route("**/api/workflow/todos", (route) =>
route.fulfill({ json: todos }),
),
]);
}
async function openProject(page: import("@playwright/test").Page) {
await page.goto("/");
await page.getByPlaceholder("/path/to/project").fill("/tmp/test-project");
await page.getByRole("button", { name: "Open Project" }).click();
await expect(page.getByText("Story TODOs", { exact: true })).toBeVisible();
}
test.describe("Story TODOs panel", () => {
test("shows unchecked acceptance criteria", async ({ page }) => {
await mockChatApis(page, {
todos: {
stories: [
{
story_id: "28_ui_show_test_todos",
story_name: "Show Remaining Test TODOs in the UI",
todos: [
"The UI lists unchecked acceptance criteria.",
"Each TODO is displayed as its full text.",
],
},
],
},
});
await openProject(page);
await expect(
page.getByText("The UI lists unchecked acceptance criteria."),
).toBeVisible();
await expect(
page.getByText("Each TODO is displayed as its full text."),
).toBeVisible();
await expect(page.getByText("2 remaining")).toBeVisible();
});
test("shows completion message when all criteria are checked", async ({
page,
}) => {
await mockChatApis(page, {
todos: {
stories: [
{
story_id: "28_ui_show_test_todos",
story_name: "Show Remaining Test TODOs in the UI",
todos: [],
},
],
},
});
await openProject(page);
await expect(
page.getByText("All acceptance criteria complete."),
).toBeVisible();
await expect(page.getByText("0 remaining")).toBeVisible();
});
test("shows TODO items from multiple stories", async ({ page }) => {
await mockChatApis(page, {
todos: {
stories: [
{
story_id: "28_ui_show_test_todos",
story_name: "Show TODOs",
todos: ["First criterion."],
},
{
story_id: "29_another_story",
story_name: "Another Story",
todos: ["Second criterion."],
},
],
},
});
await openProject(page);
await expect(page.getByText("First criterion.")).toBeVisible();
await expect(page.getByText("Second criterion.")).toBeVisible();
await expect(page.getByText("2 remaining")).toBeVisible();
await expect(page.getByText("Show TODOs")).toBeVisible();
await expect(page.getByText("Another Story")).toBeVisible();
});
});