library-picturebook-activity/frontend/playwright-report/data/3e5f32a183c465477fb8fbc90265b1bc17e482b3.md
En f03991819d feat: 管理端全功能 E2E 测试——40 用例覆盖登录、仪表盘、活动、报名、作品、评审、用户、导航
新增 10 个管理端 E2E 测试文件和 1 个 Mock fixture:
- admin.fixture.ts: Mock 数据 + 登录注入 + 组件预热 + 兜底 API 拦截
- login/contests/dashboard/navigation/registrations/works/reviews/users 等 9 个 spec

关键修复:route.fallback() 替代 route.continue() 修正 Mock 链式传递;
review-rules/select Mock + 兜底拦截器防止未 mock 请求到达真实后端。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 12:52:39 +08:00

150 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Instructions
- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.
# Test info
- Name: admin\login.spec.ts >> 管理端登录流程 >> L-01 管理端登录页正常渲染
- Location: e2e\admin\login.spec.ts:14:3
# Error details
```
Error: expect(locator).toHaveText(expected) failed
Locator: locator('.login-header h2')
Expected: "乐绘世界创想活动乐园"
Timeout: 10000ms
Error: element(s) not found
Call log:
- Expect "toHaveText" with timeout 10000ms
- waiting for locator('.login-header h2')
```
# Test source
```ts
1 | import { test, expect } from '../fixtures/admin.fixture'
2 | import { setupApiMocks, TENANT_CODE, MOCK_TOKEN } from '../fixtures/admin.fixture'
3 |
4 | /**
5 | * 登录流程测试
6 | * 测试管理端登录页面的各项功能
7 | */
8 |
9 | test.describe('管理端登录流程', () => {
10 | test.beforeEach(async ({ page }) => {
11 | await setupApiMocks(page)
12 | })
13 |
14 | test('L-01 管理端登录页正常渲染', async ({ page }) => {
15 | await page.goto(`/${TENANT_CODE}/login`)
16 |
17 | // 验证页面标题
> 18 | await expect(page.locator('.login-header h2')).toHaveText('乐绘世界创想活动乐园')
| ^ Error: expect(locator).toHaveText(expected) failed
19 |
20 | // 验证表单字段可见
21 | await expect(page.locator('input[placeholder="请输入用户名"]')).toBeVisible()
22 | await expect(page.locator('input[placeholder="请输入密码"]')).toBeVisible()
23 |
24 | // 验证登录按钮可见
25 | await expect(page.locator('button.login-btn')).toBeVisible()
26 | // Ant Design 按钮文本可能有空格,使用正则匹配
27 | await expect(page.locator('button.login-btn')).toHaveText(/登\s*录/)
28 | })
29 |
30 | test('L-02 空表单提交显示校验错误', async ({ page }) => {
31 | await page.goto(`/${TENANT_CODE}/login`)
32 |
33 | // 开发模式会自动填充 admin/admin123先清空字段
34 | const usernameInput = page.locator('input[placeholder="请输入用户名"]')
35 | const passwordInput = page.locator('input[type="password"]')
36 | await usernameInput.clear()
37 | await passwordInput.clear()
38 |
39 | // 点击提交按钮触发 Ant Design 表单校验html-type="submit"
40 | await page.locator('button.login-btn').click()
41 |
42 | // Ant Design Vue 表单校验失败时会显示错误提示
43 | await expect(
44 | page.locator('.ant-form-item-explain-error, .ant-form-item-explain, .ant-form-item-with-help, .has-error').first()
45 | ).toBeVisible({ timeout: 5000 })
46 | })
47 |
48 | test('L-03 错误密码登录失败', async ({ page }) => {
49 | await page.goto(`/${TENANT_CODE}/login`)
50 |
51 | // 填写错误的用户名和密码
52 | await page.locator('input[placeholder="请输入用户名"]').fill('wrong')
53 | await page.locator('input[type="password"]').fill('wrongpassword')
54 |
55 | // 点击登录
56 | await page.locator('button.login-btn').click()
57 |
58 | // 验证错误提示信息
59 | await expect(page.locator('.ant-message')).toBeVisible({ timeout: 5000 })
60 | })
61 |
62 | test('L-04 正确凭据登录成功跳转', async ({ page }) => {
63 | await page.goto(`/${TENANT_CODE}/login`)
64 |
65 | // 填写正确的用户名和密码
66 | await page.locator('input[placeholder="请输入用户名"]').fill('admin')
67 | await page.locator('input[type="password"]').fill('admin123')
68 |
69 | // 点击登录
70 | await page.locator('button.login-btn').click()
71 |
72 | // 验证跳转到管理端页面(离开登录页)
73 | await page.waitForURL((url) => !url.pathname.includes('/login'), { timeout: 15_000 })
74 |
75 | // 验证侧边栏可见(说明进入了管理端布局)
76 | await expect(page.locator('.custom-sider')).toBeVisible({ timeout: 10_000 })
77 | })
78 |
79 | test('L-05 登录后 Token 存储正确', async ({ page }) => {
80 | await page.goto(`/${TENANT_CODE}/login`)
81 |
82 | // 填写并提交登录
83 | await page.locator('input[placeholder="请输入用户名"]').fill('admin')
84 | await page.locator('input[type="password"]').fill('admin123')
85 | await page.locator('button.login-btn').click()
86 |
87 | // 等待跳转
88 | await page.waitForURL((url) => !url.pathname.includes('/login'), { timeout: 15_000 })
89 |
90 | // 验证 Cookie 中包含 token
91 | const cookies = await page.context().cookies()
92 | const tokenCookie = cookies.find((c) => c.name === 'token')
93 | expect(tokenCookie).toBeDefined()
94 | expect(tokenCookie!.value.length).toBeGreaterThan(0)
95 | })
96 |
97 | test('L-06 退出登录清除状态', async ({ page }) => {
98 | await page.goto(`/${TENANT_CODE}/login`)
99 |
100 | // 先登录
101 | await page.locator('input[placeholder="请输入用户名"]').fill('admin')
102 | await page.locator('input[type="password"]').fill('admin123')
103 | await page.locator('button.login-btn').click()
104 | await page.waitForURL((url) => !url.pathname.includes('/login'), { timeout: 15_000 })
105 | await expect(page.locator('.custom-sider')).toBeVisible({ timeout: 10_000 })
106 |
107 | // 点击用户头像区域
108 | await page.locator('.user-info').click()
109 |
110 | // 点击退出登录
111 | await page.locator('text=退出登录').click()
112 |
113 | // 验证跳转回登录页
114 | await page.waitForURL(/\/login/, { timeout: 10_000 })
115 | await expect(page.locator('.login-container')).toBeVisible()
116 | })
117 | })
118 |
```