multica/e2e/issues.spec.ts
Jiayuan Zhang 1ba0fb071a fix(web): fix stale state bugs, add real-time updates, and build verification pipeline
- Fix kanban board columns not adapting to available width (w-64 → flex-1)
- Fix workspace name not updating in sidebar after save in settings
- Fix comments leaking across issues when navigating between issue details
- Fix duplicate issue appearing on create (race between callback and WebSocket)
- Add real-time WebSocket listeners for agents and inbox pages
- Add `make check` one-click verification pipeline (typecheck + tests + E2E)
- Add E2E test fixtures for self-contained test data setup/teardown
- Add settings E2E test and updateWorkspace unit test
- Make `make start/setup` reuse existing PostgreSQL if already running
- Update CLAUDE.md with AI agent verification loop and E2E test patterns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 12:44:49 +08:00

88 lines
2.7 KiB
TypeScript

import { test, expect } from "@playwright/test";
import { loginAsDefault, createTestApi } from "./helpers";
import type { TestApiClient } from "./fixtures";
test.describe("Issues", () => {
let api: TestApiClient;
test.beforeEach(async ({ page }) => {
api = await createTestApi();
await loginAsDefault(page);
});
test.afterEach(async () => {
await api.cleanup();
});
test("issues page loads with board view", async ({ page }) => {
await expect(page.locator("text=All Issues")).toBeVisible();
// Board columns should be visible
await expect(page.locator("text=Backlog")).toBeVisible();
await expect(page.locator("text=Todo")).toBeVisible();
await expect(page.locator("text=In Progress")).toBeVisible();
});
test("can switch between board and list view", async ({ page }) => {
await expect(page.locator("text=All Issues")).toBeVisible();
// Switch to list view
await page.click("text=List");
await expect(page.locator("text=All Issues")).toBeVisible();
// Switch back to board view
await page.click("text=Board");
await expect(page.locator("text=Backlog")).toBeVisible();
});
test("can create a new issue", async ({ page }) => {
await page.click("text=New Issue");
const title = "E2E Created " + Date.now();
await page.fill('input[placeholder="Issue title..."]', title);
await page.click("text=Create");
// New issue should appear on the page
await expect(page.locator(`text=${title}`).first()).toBeVisible({
timeout: 10000,
});
});
test("can navigate to issue detail page", async ({ page }) => {
// Create a known issue via API so we don't depend on seed data
const issue = await api.createIssue("E2E Detail Test " + Date.now());
// Reload to see the new issue
await page.reload();
await expect(page.locator("text=All Issues")).toBeVisible();
// Navigate to the issue detail
const issueLink = page.locator(`a[href="/issues/${issue.id}"]`);
await expect(issueLink).toBeVisible({ timeout: 5000 });
await issueLink.click();
await page.waitForURL(/\/issues\/[\w-]+/);
// Should show Properties panel
await expect(page.locator("text=Properties")).toBeVisible();
// Should show breadcrumb link back to Issues
await expect(
page.locator("a", { hasText: "Issues" }).first(),
).toBeVisible();
});
test("can cancel issue creation", async ({ page }) => {
await page.click("text=New Issue");
await expect(
page.locator('input[placeholder="Issue title..."]'),
).toBeVisible();
await page.click("text=Cancel");
await expect(
page.locator('input[placeholder="Issue title..."]'),
).not.toBeVisible();
await expect(page.locator("text=New Issue")).toBeVisible();
});
});