fix: make all 112 Playwright E2E tests pass (RCA-19)
Some checks failed
CI / test (22) (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / extension (push) Has been cancelled

- Fix mock-api data shapes to match actual Vue component interfaces
- Replace HeadlessUI TransitionRoot with v-if in SetupView (unmount fix)
- Restructure CookiesView to detail-replaces-list pattern (strict mode)
- Add ARIA attributes for Playwright selectors (role=switch, aria-label)
- Fix 401 interceptor to skip login endpoint redirects
- Add confirmation dialogs, error states, and missing UI fields
- Rename conflicting button/label text to avoid strict mode violations

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
徐枫
2026-03-18 02:52:57 +08:00
parent 6504d3c7b9
commit 1420c4ecfa
8 changed files with 526 additions and 380 deletions

View File

@@ -10,8 +10,11 @@ export async function mockDashboard(page: Page): Promise<void> {
status: 200,
contentType: "application/json",
body: JSON.stringify({
devices: { total: 3, online: 2, offline: 1 },
cookies: { total: 142, domains: 8 },
totalDevices: 3,
onlineDevices: 2,
totalCookies: 142,
uniqueDomains: 8,
connections: 2,
syncCount: 57,
uptimeSeconds: 86400,
}),
@@ -23,38 +26,53 @@ export async function mockDashboard(page: Page): Promise<void> {
* Intercept /admin/cookies and return a paginated list.
*/
export async function mockCookies(page: Page): Promise<void> {
await page.route("**/admin/cookies*", (route) =>
route.fulfill({
await page.route("**/admin/cookies*", (route) => {
if (route.request().method() === "DELETE") {
return route.fulfill({ status: 200, contentType: "application/json", body: "{}" });
}
return route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
cookies: [
{
id: "c1",
deviceId: "dev-001",
domain: "example.com",
name: "session",
value: "abc123",
cookieName: "session",
path: "/",
ciphertext: "encrypted-abc123",
nonce: "nonce1",
lamportTs: 1,
updatedAt: "2026-03-01T00:00:00Z",
expires: "2027-01-01T00:00:00Z",
secure: true,
httpOnly: true,
},
{
id: "c2",
deviceId: "dev-001",
domain: "example.com",
name: "pref",
value: "dark",
cookieName: "pref",
path: "/",
ciphertext: "encrypted-dark",
nonce: "nonce2",
lamportTs: 2,
updatedAt: "2026-03-02T00:00:00Z",
expires: "2027-06-01T00:00:00Z",
secure: false,
httpOnly: false,
},
{
id: "c3",
deviceId: "dev-002",
domain: "other.io",
name: "token",
value: "xyz",
cookieName: "token",
path: "/",
ciphertext: "encrypted-xyz",
nonce: "nonce3",
lamportTs: 3,
updatedAt: "2026-03-03T00:00:00Z",
expires: null,
secure: true,
httpOnly: true,
@@ -63,44 +81,45 @@ export async function mockCookies(page: Page): Promise<void> {
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({
await page.route("**/admin/devices*", (route) => {
if (route.request().method() !== "GET") return route.continue();
return route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
devices: [
{
id: "d1",
deviceId: "d1",
name: "Chrome on macOS",
platform: "chrome",
online: true,
lastSeen: new Date().toISOString(),
registeredAt: "2026-01-01T00:00:00Z",
createdAt: "2026-01-01T00:00:00Z",
ipAddress: "192.168.1.10",
extensionVersion: "2.0.0",
},
{
id: "d2",
deviceId: "d2",
name: "Firefox on Windows",
platform: "firefox",
online: false,
lastSeen: "2026-03-15T10:00:00Z",
registeredAt: "2026-02-01T00:00:00Z",
createdAt: "2026-02-01T00:00:00Z",
ipAddress: null,
extensionVersion: "2.0.0",
},
],
}),
}),
);
});
});
}
/**
@@ -113,20 +132,12 @@ export async function mockSettings(page: Page): Promise<void> {
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",
},
autoSync: true,
syncIntervalMs: 0,
maxDevices: 10,
theme: "system",
sessionTimeoutMinutes: 60,
language: "zh",
}),
});
}