import { test, expect } from "@playwright/test"; test.describe("Kanban Board", () => { // Helper to set up a mock project in localStorage async function setupMockProject(page: ReturnType) { await page.addInitScript(() => { const mockProject = { id: "test-project-1", name: "Test Project", path: "/mock/test-project", lastOpened: new Date().toISOString(), }; localStorage.setItem( "automaker-storage", JSON.stringify({ state: { projects: [mockProject], currentProject: mockProject, currentView: "board", sidebarOpen: true, theme: "dark", }, version: 0, }) ); }); } test("shows Add Feature button", async ({ page }) => { await setupMockProject(page); await page.goto("/"); await expect(page.getByTestId("add-feature-button")).toBeVisible(); }); test("opens add feature dialog", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Click add feature button await page.getByTestId("add-feature-button").click(); // Dialog should appear await expect(page.getByTestId("add-feature-dialog")).toBeVisible(); await expect(page.getByTestId("feature-category-input")).toBeVisible(); await expect(page.getByTestId("feature-description-input")).toBeVisible(); }); test("can add a new feature", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Click add feature button await page.getByTestId("add-feature-button").click(); // Fill in feature details await page.getByTestId("feature-category-input").fill("Test Category"); await page .getByTestId("feature-description-input") .fill("Test Feature Description"); await page.getByTestId("feature-step-0-input").fill("Step 1: First step"); // Submit the form await page.getByTestId("confirm-add-feature").click(); // Dialog should close await expect(page.getByTestId("add-feature-dialog")).not.toBeVisible(); }); test("refresh button is visible", async ({ page }) => { await setupMockProject(page); await page.goto("/"); await expect(page.getByTestId("refresh-board")).toBeVisible(); }); test("loads cards from .automaker/feature_list.json and displays them in correct columns", async ({ page, }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for loading to complete (the mock IPC returns a sample feature) // The mock returns a feature in "backlog" column (passes: false) await expect(page.getByTestId("kanban-column-backlog")).toBeVisible(); // After loading, the backlog should show the sample feature from mock data // Looking at the electron.ts mock, it returns one feature with "Sample Feature" const backlogColumn = page.getByTestId("kanban-column-backlog"); await expect(backlogColumn.getByText("Sample Feature")).toBeVisible(); }); test("features with passes:true appear in verified column", async ({ page, }) => { // Create a project and add a feature manually await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Add a new feature await page.getByTestId("add-feature-button").click(); await page.getByTestId("feature-category-input").fill("Core"); await page .getByTestId("feature-description-input") .fill("Verified Test Feature"); await page.getByTestId("confirm-add-feature").click(); // The new feature should appear in backlog await expect( page .getByTestId("kanban-column-backlog") .getByText("Verified Test Feature") ).toBeVisible(); }); test("can edit feature card details", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for features to load - the mock returns "Sample Feature" await expect( page.getByTestId("kanban-column-backlog").getByText("Sample Feature") ).toBeVisible(); // Find and click the edit button on the card using specific testid pattern const backlogColumn = page.getByTestId("kanban-column-backlog"); // The edit button has testid "edit-feature-{feature.id}" where feature.id contains "feature-0-" const editButton = backlogColumn.locator( '[data-testid^="edit-feature-feature-0-"]' ); await editButton.click(); // Edit dialog should appear await expect(page.getByTestId("edit-feature-dialog")).toBeVisible(); // Edit the description await page .getByTestId("edit-feature-description") .fill("Updated Feature Description"); // Save the changes await page.getByTestId("confirm-edit-feature").click(); // Dialog should close await expect(page.getByTestId("edit-feature-dialog")).not.toBeVisible(); // The updated description should be visible await expect(page.getByText("Updated Feature Description")).toBeVisible(); }); test("edit dialog shows existing feature data", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for features to load await expect( page.getByTestId("kanban-column-backlog").getByText("Sample Feature") ).toBeVisible(); // Click edit button using specific testid pattern const backlogColumn = page.getByTestId("kanban-column-backlog"); const editButton = backlogColumn.locator( '[data-testid^="edit-feature-feature-0-"]' ); await editButton.click(); // Check that the dialog pre-populates with existing data await expect(page.getByTestId("edit-feature-description")).toHaveValue( "Sample Feature" ); await expect(page.getByTestId("edit-feature-category")).toHaveValue("Core"); }); test("can drag card from Backlog to In Progress column", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for features to load in Backlog const backlogColumn = page.getByTestId("kanban-column-backlog"); const inProgressColumn = page.getByTestId("kanban-column-in_progress"); await expect(backlogColumn.getByText("Sample Feature")).toBeVisible(); // Find the drag handle specifically const dragHandle = backlogColumn.locator( '[data-testid^="drag-handle-feature-0-"]' ); await expect(dragHandle).toBeVisible(); // Get drag handle and target positions const handleBox = await dragHandle.boundingBox(); const targetBox = await inProgressColumn.boundingBox(); if (!handleBox || !targetBox) throw new Error("Could not find elements"); // Use mouse events - start from center of drag handle const startX = handleBox.x + handleBox.width / 2; const startY = handleBox.y + handleBox.height / 2; const endX = targetBox.x + targetBox.width / 2; const endY = targetBox.y + 100; await page.mouse.move(startX, startY); await page.mouse.down(); // Move in steps to trigger dnd-kit activation (needs >8px movement) await page.mouse.move(endX, endY, { steps: 20 }); await page.mouse.up(); // Verify card moved to In Progress column await expect(inProgressColumn.getByText("Sample Feature")).toBeVisible(); // Verify card is no longer in Backlog await expect(backlogColumn.getByText("Sample Feature")).not.toBeVisible(); }); test("displays delete button (trash icon) on feature card", async ({ page, }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for features to load in Backlog const backlogColumn = page.getByTestId("kanban-column-backlog"); await expect(backlogColumn.getByText("Sample Feature")).toBeVisible(); // Find the delete button on the card const deleteButton = backlogColumn.locator( '[data-testid^="delete-feature-feature-0-"]' ); await expect(deleteButton).toBeVisible(); }); test("can delete a feature from kanban board", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Wait for features to load in Backlog const backlogColumn = page.getByTestId("kanban-column-backlog"); await expect(backlogColumn.getByText("Sample Feature")).toBeVisible(); // Find and click the delete button const deleteButton = backlogColumn.locator( '[data-testid^="delete-feature-feature-0-"]' ); await deleteButton.click(); // Verify the feature is removed from the board await expect(backlogColumn.getByText("Sample Feature")).not.toBeVisible(); }); test("deleting feature removes it from all columns", async ({ page }) => { await setupMockProject(page); await page.goto("/"); // Wait for board to load await expect(page.getByTestId("board-view")).toBeVisible(); // Add a new feature first await page.getByTestId("add-feature-button").click(); await page.getByTestId("feature-category-input").fill("Test Category"); await page .getByTestId("feature-description-input") .fill("Feature to Delete"); await page.getByTestId("confirm-add-feature").click(); // Wait for the new feature to appear in backlog const backlogColumn = page.getByTestId("kanban-column-backlog"); await expect(backlogColumn.getByText("Feature to Delete")).toBeVisible(); // Find and click the delete button for the newly added feature const deleteButton = backlogColumn .locator('[data-testid^="delete-feature-feature-"]') .last(); await deleteButton.click(); // Verify the feature is removed await expect( backlogColumn.getByText("Feature to Delete") ).not.toBeVisible(); // Also verify it's not anywhere else on the board await expect(page.getByText("Feature to Delete")).not.toBeVisible(); }); });