TODO-app/tests/e2e/todo.spec.ts

145 lines
4.8 KiB
TypeScript

import { test, expect } 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: any) =>
page.locator("form", { has: page.locator('input[name="title"]') });
// Hitta tabellraden för en titel
const getRowByTitle = (page: any, 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);
});
});