Prepares the full QA test infrastructure for the admin frontend before all prerequisite feature tasks (RCA-12–18) are complete. - playwright.config.ts: 6 browser/device projects (Chromium, Firefox, WebKit, mobile Chrome, mobile Safari, tablet) - tests/e2e/01-login.spec.ts: login form, route guards, setup wizard - tests/e2e/02-dashboard.spec.ts: stats cards, device list, quick actions - tests/e2e/03-cookies.spec.ts: cookie list, search, detail panel, delete - tests/e2e/04-devices.spec.ts: device cards, revoke flow, status filter - tests/e2e/05-settings.spec.ts: three-tab layout, save/error toasts - tests/e2e/06-responsive.spec.ts: no horizontal scroll on mobile/tablet - tests/api/admin-api.spec.ts: REST API contract tests for all /admin/* endpoints - helpers/auth.ts: loginViaUI + loginViaAPI helpers - helpers/mock-api.ts: route intercept fixtures for all pages Co-Authored-By: Paperclip <noreply@paperclip.ing>
154 lines
3.8 KiB
TypeScript
154 lines
3.8 KiB
TypeScript
import { type Page } from "@playwright/test";
|
|
|
|
/**
|
|
* Intercept /admin/dashboard and return a canned response so UI tests
|
|
* don't depend on a running relay server with real data.
|
|
*/
|
|
export async function mockDashboard(page: Page): Promise<void> {
|
|
await page.route("**/admin/dashboard", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
devices: { total: 3, online: 2, offline: 1 },
|
|
cookies: { total: 142, domains: 8 },
|
|
syncCount: 57,
|
|
uptimeSeconds: 86400,
|
|
}),
|
|
}),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Intercept /admin/cookies and return a paginated list.
|
|
*/
|
|
export async function mockCookies(page: Page): Promise<void> {
|
|
await page.route("**/admin/cookies*", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
cookies: [
|
|
{
|
|
id: "c1",
|
|
domain: "example.com",
|
|
name: "session",
|
|
value: "abc123",
|
|
path: "/",
|
|
expires: "2027-01-01T00:00:00Z",
|
|
secure: true,
|
|
httpOnly: true,
|
|
},
|
|
{
|
|
id: "c2",
|
|
domain: "example.com",
|
|
name: "pref",
|
|
value: "dark",
|
|
path: "/",
|
|
expires: "2027-06-01T00:00:00Z",
|
|
secure: false,
|
|
httpOnly: false,
|
|
},
|
|
{
|
|
id: "c3",
|
|
domain: "other.io",
|
|
name: "token",
|
|
value: "xyz",
|
|
path: "/",
|
|
expires: null,
|
|
secure: true,
|
|
httpOnly: true,
|
|
},
|
|
],
|
|
total: 3,
|
|
page: 1,
|
|
}),
|
|
}),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Intercept /admin/devices and return device list.
|
|
*/
|
|
export async function mockDevices(page: Page): Promise<void> {
|
|
await page.route("**/admin/devices*", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
devices: [
|
|
{
|
|
id: "d1",
|
|
name: "Chrome on macOS",
|
|
platform: "chrome",
|
|
online: true,
|
|
lastSeen: new Date().toISOString(),
|
|
registeredAt: "2026-01-01T00:00:00Z",
|
|
ipAddress: "192.168.1.10",
|
|
extensionVersion: "2.0.0",
|
|
},
|
|
{
|
|
id: "d2",
|
|
name: "Firefox on Windows",
|
|
platform: "firefox",
|
|
online: false,
|
|
lastSeen: "2026-03-15T10:00:00Z",
|
|
registeredAt: "2026-02-01T00:00:00Z",
|
|
ipAddress: null,
|
|
extensionVersion: "2.0.0",
|
|
},
|
|
],
|
|
}),
|
|
}),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Intercept /admin/settings and return settings object.
|
|
*/
|
|
export async function mockSettings(page: Page): Promise<void> {
|
|
await page.route("**/admin/settings*", (route) => {
|
|
if (route.request().method() === "GET") {
|
|
return route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
sync: {
|
|
autoSync: true,
|
|
frequency: "realtime",
|
|
domainWhitelist: [],
|
|
domainBlacklist: [],
|
|
},
|
|
security: {
|
|
sessionTimeoutMinutes: 60,
|
|
requirePairingPin: false,
|
|
},
|
|
appearance: {
|
|
theme: "system",
|
|
language: "zh",
|
|
},
|
|
}),
|
|
});
|
|
}
|
|
return route.fulfill({ status: 200, contentType: "application/json", body: "{}" });
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Simulate a 500 error on the given path — used for error-handling tests.
|
|
*/
|
|
export async function mockAPIError(
|
|
page: Page,
|
|
urlPattern: string,
|
|
status = 500,
|
|
message = "Internal Server Error",
|
|
): Promise<void> {
|
|
await page.route(urlPattern, (route) =>
|
|
route.fulfill({
|
|
status,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ error: message }),
|
|
}),
|
|
);
|
|
}
|