Add Playwright E2E tests replacing Cypress with MSW integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 16:43:32 +08:00
parent 67a723207f
commit aa2661b556
33 changed files with 2284 additions and 7 deletions

View File

@@ -0,0 +1,91 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/22
import { test, expect } from "@playwright/test";
test.describe("Login Flow", () => {
test("renders the login form", async ({ page }) => {
await page.goto("/login");
await expect(page.getByRole("heading", { name: "LOGIN", exact: true }).first()).toBeVisible();
await expect(page.locator("#account")).toBeVisible();
await expect(page.locator("#password")).toBeVisible();
await expect(page.locator("#login_btn_main_btn")).toBeDisabled();
});
test("login button is disabled when fields are empty", async ({
page,
}) => {
await page.goto("/login");
await expect(page.locator("#login_btn_main_btn")).toBeDisabled();
// Only username filled - still disabled
await page.locator("#account").fill("testuser");
await expect(page.locator("#login_btn_main_btn")).toBeDisabled();
});
test("login button enables when both fields are filled", async ({
page,
}) => {
await page.goto("/login");
await page.locator("#account").fill("testadmin");
await page.locator("#password").fill("password123");
await expect(page.locator("#login_btn_main_btn")).toBeEnabled();
});
test("successful login redirects to /files", async ({ page }) => {
await page.goto("/login");
await page.locator("#account").fill("testadmin");
await page.locator("#password").fill("password123");
await page.locator("#login_btn_main_btn").click();
await expect(page).toHaveURL(/\/files/);
});
test("failed login shows error message", async ({ page }) => {
// Visit login first to load app + MSW
await page.goto("/login");
await expect(page.locator("#login_btn_main_btn")).toBeVisible();
// Override the token endpoint to return 401 via MSW
await page.evaluate(() => {
const { http, HttpResponse } = window.__msw__;
window.__mswWorker__.use(
http.post("/api/oauth/token", () =>
HttpResponse.json(
{ detail: "Incorrect username or password" },
{ status: 401 },
),
),
);
});
await page.locator("#account").fill("wronguser");
await page.locator("#password").fill("wrongpass");
await page.locator("#login_btn_main_btn").click();
await expect(
page.getByText("Incorrect account or password"),
).toBeVisible();
});
test("toggles password visibility", async ({ page }) => {
await page.goto("/login");
await page.locator("#password").fill("secret123");
await expect(
page.locator("#password"),
).toHaveAttribute("type", "password");
// Click the eye icon to show password
await page.locator('label[for="passwordt"] span.cursor-pointer').click();
await expect(
page.locator("#password"),
).toHaveAttribute("type", "text");
// Click again to hide
await page.locator('label[for="passwordt"] span.cursor-pointer').click();
await expect(
page.locator("#password"),
).toHaveAttribute("type", "password");
});
});