import { test, expect, type Page } from "@playwright/test"; test.describe("Todo lifecycle E2E", () => { test.describe.configure({ mode: "serial" }); const title = `E2E Todo ${Date.now()}`; const description = "E2E Desc"; // Hitta create-formen const getCreateForm = (page: Page) => page.locator("form", { has: page.locator('input[name="title"]') }); // Hitta tabellraden för en titel const getRowByTitle = (page: Page, t: string) => page.locator("tr", { has: page.locator(".fw-semibold", { hasText: t }) }); test("user can create a todo and see it on dashboard", async ({ page }) => { await page.goto("/dashboard"); const createForm = getCreateForm(page); // Fyll i formuläret await createForm.locator('input[name="title"]').fill(title); await createForm.locator('textarea[name="description"]').fill(description); await createForm.locator('select[name="status"]').selectOption("not-started"); // Skicka await createForm.locator('button[type="submit"]').click(); // Syns i listan await expect(page.locator(".fw-semibold", { hasText: title })).toBeVisible(); }); test("user can update status to done", async ({ page }) => { await page.goto("/dashboard"); const row = getRowByTitle(page, title); await expect(row).toBeVisible(); // Ändra status const statusSelect = row.locator('select[name="status"]'); await Promise.all([ page.waitForLoadState("networkidle"), statusSelect.selectOption("done"), ]); // Kontrollera att status är done const rowAfter = getRowByTitle(page, title); await expect(rowAfter.locator('select[name="status"]')).toHaveValue("done"); }); test("user can change status multiple times", async ({ page }) => { await page.goto("/dashboard"); const row = getRowByTitle(page, title); await expect(row).toBeVisible(); const statusSelect = row.locator('select[name="status"]'); // not-started -> in-progress await Promise.all([ page.waitForLoadState("networkidle"), statusSelect.selectOption("in-progress"), ]); await expect(getRowByTitle(page, title).locator('select[name="status"]')).toHaveValue( "in-progress" ); // in-progress -> done await Promise.all([ page.waitForLoadState("networkidle"), statusSelect.selectOption("done"), ]); await expect(getRowByTitle(page, title).locator('select[name="status"]')).toHaveValue("done"); }); test("cannot create todo without required fields", async ({ page }) => { await page.goto("/dashboard"); const createForm = getCreateForm(page); // Tomma fält (bara mellanslag) await createForm.locator('input[name="title"]').fill(" "); await createForm.locator('textarea[name="description"]').fill(" "); await createForm.locator('button[type="submit"]').click(); // Felmeddelande visas await expect(page.getByText("Title och description krävs.")).toBeVisible(); }); test("cannot create todo when description is missing", async ({ page }) => { const badTitle = `E2E Missing Desc ${Date.now()}`; await page.goto("/dashboard"); const createForm = getCreateForm(page); await createForm.locator('input[name="title"]').fill(badTitle); await createForm.locator('textarea[name="description"]').fill(" "); await createForm.locator('button[type="submit"]').click(); // Felmeddelande + ingen rad skapas await expect(page.getByText("Title och description krävs.")).toBeVisible(); await expect(page.locator(".fw-semibold", { hasText: badTitle })).toHaveCount(0); }); test("invalid status is normalized to not-started on create", async ({ page }) => { const t = `E2E Weird Status ${Date.now()}`; await page.goto("/dashboard"); const createForm = getCreateForm(page); await createForm.locator('input[name="title"]').fill(t); await createForm.locator('textarea[name="description"]').fill("desc"); // Sätt ett ogiltigt status-värde await createForm.locator('select[name="status"]').evaluate((sel: HTMLSelectElement) => { sel.value = "hax-status"; }); await createForm.locator('button[type="submit"]').click(); // Ska defaulta till not-started const row = getRowByTitle(page, t); await expect(row).toBeVisible(); await expect(row.locator('select[name="status"]')).toHaveValue("not-started"); // Städa await row.locator('button[title="Delete"]').click(); await expect(page.locator(".fw-semibold", { hasText: t })).toHaveCount(0); }); test("user can delete todo", async ({ page }) => { await page.goto("/dashboard"); const row = getRowByTitle(page, title); await expect(row).toBeVisible(); // Ta bort await row.locator('button[title="Delete"]').click(); // Ska vara borta await expect(page.locator(".fw-semibold", { hasText: title })).toHaveCount(0); }); });