@zmice/zc 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +98 -11
  2. package/dist/cli/__tests__/platform.test.js +215 -2
  3. package/dist/cli/__tests__/platform.test.js.map +1 -1
  4. package/dist/cli/__tests__/surface.test.js +52 -0
  5. package/dist/cli/__tests__/surface.test.js.map +1 -1
  6. package/dist/cli/__tests__/team.test.d.ts +2 -0
  7. package/dist/cli/__tests__/team.test.d.ts.map +1 -0
  8. package/dist/cli/__tests__/team.test.js +29 -0
  9. package/dist/cli/__tests__/team.test.js.map +1 -0
  10. package/dist/cli/__tests__/upstream.test.js +4 -0
  11. package/dist/cli/__tests__/upstream.test.js.map +1 -1
  12. package/dist/cli/platform.d.ts +11 -3
  13. package/dist/cli/platform.d.ts.map +1 -1
  14. package/dist/cli/platform.js +216 -54
  15. package/dist/cli/platform.js.map +1 -1
  16. package/dist/cli/team.d.ts.map +1 -1
  17. package/dist/cli/team.js +114 -4
  18. package/dist/cli/team.js.map +1 -1
  19. package/dist/cli/upstream.d.ts +1 -0
  20. package/dist/cli/upstream.d.ts.map +1 -1
  21. package/dist/cli/upstream.js +84 -5
  22. package/dist/cli/upstream.js.map +1 -1
  23. package/dist/node_modules/@zmice/platform-core/dist/index.d.ts +37 -3
  24. package/dist/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
  25. package/dist/node_modules/@zmice/platform-core/dist/index.js +68 -0
  26. package/dist/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
  27. package/dist/node_modules/@zmice/platform-core/dist/index.test.js +44 -1
  28. package/dist/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  29. package/dist/runtime/__tests__/worktree-manager.test.js +63 -1
  30. package/dist/runtime/__tests__/worktree-manager.test.js.map +1 -1
  31. package/dist/runtime/worktree-manager.d.ts +26 -1
  32. package/dist/runtime/worktree-manager.d.ts.map +1 -1
  33. package/dist/runtime/worktree-manager.js +126 -12
  34. package/dist/runtime/worktree-manager.js.map +1 -1
  35. package/dist/team/__tests__/orchestrator.test.js +40 -0
  36. package/dist/team/__tests__/orchestrator.test.js.map +1 -1
  37. package/dist/team/__tests__/planner.test.d.ts +2 -0
  38. package/dist/team/__tests__/planner.test.d.ts.map +1 -0
  39. package/dist/team/__tests__/planner.test.js +43 -0
  40. package/dist/team/__tests__/planner.test.js.map +1 -0
  41. package/dist/team/__tests__/task-queue.test.js +18 -0
  42. package/dist/team/__tests__/task-queue.test.js.map +1 -1
  43. package/dist/team/orchestrator.d.ts +2 -1
  44. package/dist/team/orchestrator.d.ts.map +1 -1
  45. package/dist/team/orchestrator.js +29 -10
  46. package/dist/team/orchestrator.js.map +1 -1
  47. package/dist/team/planner.d.ts +27 -0
  48. package/dist/team/planner.d.ts.map +1 -0
  49. package/dist/team/planner.js +120 -0
  50. package/dist/team/planner.js.map +1 -0
  51. package/dist/team/task-queue.d.ts +3 -0
  52. package/dist/team/task-queue.d.ts.map +1 -1
  53. package/dist/team/task-queue.js +11 -2
  54. package/dist/team/task-queue.js.map +1 -1
  55. package/package.json +2 -2
  56. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts +37 -3
  57. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
  58. package/vendor/node_modules/@zmice/platform-core/dist/index.js +68 -0
  59. package/vendor/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
  60. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +44 -1
  61. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  62. package/vendor/packages/platform-claude/dist/index.d.ts.map +1 -1
  63. package/vendor/packages/platform-claude/dist/index.js +12 -70
  64. package/vendor/packages/platform-claude/dist/index.js.map +1 -1
  65. package/vendor/packages/platform-codex/dist/generate.d.ts +1 -1
  66. package/vendor/packages/platform-codex/dist/generate.d.ts.map +1 -1
  67. package/vendor/packages/platform-codex/dist/generate.js +1 -1
  68. package/vendor/packages/platform-codex/dist/generate.js.map +1 -1
  69. package/vendor/packages/platform-codex/dist/index.d.ts +15 -1
  70. package/vendor/packages/platform-codex/dist/index.d.ts.map +1 -1
  71. package/vendor/packages/platform-codex/dist/index.js +320 -47
  72. package/vendor/packages/platform-codex/dist/index.js.map +1 -1
  73. package/vendor/packages/platform-codex/dist/index.test.js +113 -5
  74. package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
  75. package/vendor/packages/platform-opencode/dist/index.d.ts.map +1 -1
  76. package/vendor/packages/platform-opencode/dist/index.js +15 -81
  77. package/vendor/packages/platform-opencode/dist/index.js.map +1 -1
  78. package/vendor/packages/platform-qwen/dist/index.d.ts.map +1 -1
  79. package/vendor/packages/platform-qwen/dist/index.js +28 -84
  80. package/vendor/packages/platform-qwen/dist/index.js.map +1 -1
  81. package/vendor/packages/toolkit/src/content/agents/architect/body.md +8 -0
  82. package/vendor/packages/toolkit/src/content/agents/code-reviewer/body.md +10 -0
  83. package/vendor/packages/toolkit/src/content/agents/product-owner/body.md +8 -0
  84. package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +3 -1
  85. package/vendor/packages/toolkit/src/content/commands/start/body.md +51 -2
  86. package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +2 -2
  87. package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/body.md +17 -0
  88. package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/body.md +77 -520
  89. package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/body.md +56 -387
  90. package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/body.md +10 -0
  91. package/vendor/packages/toolkit/src/content/skills/code-simplification/body.md +55 -301
  92. package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +10 -0
  93. package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +66 -331
  94. package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/body.md +30 -1
  95. package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/body.md +79 -317
  96. package/vendor/packages/toolkit/src/content/skills/performance-optimization/body.md +60 -330
  97. package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/body.md +35 -0
  98. package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/body.md +66 -342
  99. package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/body.md +66 -303
  100. package/vendor/packages/toolkit/src/content/skills/team-orchestration/body.md +81 -327
  101. package/vendor/packages/toolkit/src/content/skills/test-driven-development/body.md +50 -346
  102. package/vendor/packages/toolkit/src/content/skills/using-agent-skills/body.md +26 -2
  103. package/vendor/references/upstreams.yaml +5 -0
@@ -1,554 +1,111 @@
1
1
  # Browser QA Testing
2
2
 
3
- ## Overview
3
+ ## 角色定位
4
4
 
5
- Unit tests verify functions. API tests verify endpoints. Neither tells you whether a user can actually log in, fill a form, or navigate your app without hitting a blank screen or a cryptic error. Browser-level QA testing fills this gap by driving a real browser through the same flows your users follow — clicking buttons, filling inputs, waiting for network responses, and validating what appears on screen.
5
+ 用真实浏览器验证用户是否真的能完成关键路径。单元测试和 API 测试不能证明页面可用、交互可达、网络错误可见或视觉没有严重错位;浏览器 QA 用运行中的应用和可复查证据补上这层门禁。
6
6
 
7
- **Why this matters:** The most common production incidents aren't logic bugs caught by unit tests — they're broken builds that render blank pages, API integrations that fail silently, modals that can't be dismissed, or forms that submit empty data. These only surface when a real browser renders real DOM, executes real JavaScript, and makes real network requests.
7
+ 本文只给执行骨架。项目已有 Playwright/Cypress/Puppeteer 时优先沿用;没有既有选择时默认 Playwright。
8
8
 
9
- ## When to Use
9
+ ## 何时使用
10
10
 
11
- - After frontend component development is complete and you need to verify the integrated experience
12
- - After user flow changes (new pages, modified navigation, updated forms)
13
- - Before any release or deployment — as the final quality gate
14
- - When visual regression is suspected (CSS changes, dependency upgrades, design system updates)
15
- - When accessibility compliance needs verification (WCAG audits)
16
- - After backend API changes that affect frontend behavior
17
- - When a bug report describes browser-specific behavior you can't reproduce with unit tests
11
+ - 前端页面、组件、导航、表单或状态流改动后。
12
+ - 后端 API 改动会影响前端体验时。
13
+ - 发布前需要最终用户路径证据时。
14
+ - bug 报告来自浏览器行为、视觉错位或交互失败时。
15
+ - 单元/API 测试通过,但仍需要确认真实页面没有空白、控制台错误或不可操作状态时。
18
16
 
19
- ## 方法原则
17
+ 不适用:纯后端逻辑、纯文档、无需浏览器渲染的配置改动。
20
18
 
21
- - 先验证最小关键路径,再扩展到次要路径;不要一上来铺满低价值场景
22
- - 浏览器 QA 的输出必须可作为证据使用,失败时要留下截图、trace、控制台或网络记录
23
- - 对复杂改动谨慎推进,先锁定一条可复现路径,再扩大覆盖面
24
- - 视觉、交互、网络、可访问性检查都应服务当前目标,而不是机械堆清单
19
+ ## 快速路径
25
20
 
26
- ## 最小关键路径
21
+ 1. 明确 1-3 条失败就不能放行的关键路径。
22
+ 2. 启动应用或确认目标 URL 可访问。
23
+ 3. 准备稳定测试数据,避免依赖生产数据。
24
+ 4. 驱动真实浏览器执行关键路径。
25
+ 5. 同时检查 DOM 可见结果、控制台错误、网络失败和基本响应式。
26
+ 6. 失败时保留截图、trace、控制台或网络证据。
27
+ 7. 修复后重跑原始失败路径,证明不再复发。
27
28
 
28
- 每轮浏览器 QA 至少先选 1-3 条“失败就不能放行”的路径,通常包括:
29
+ ## 工具选择
29
30
 
30
- 1. 进入应用或核心页面
31
- 2. 完成一次主要业务动作
32
- 3. 看到可验证的成功结果或明确错误反馈
33
-
34
- 如果这是一个 bug 修复,最小关键路径必须先覆盖“原始失败如何复现”和“修复后如何证明不再复发”。
35
-
36
- ## Tool Selection
37
-
38
- ### Playwright (Recommended)
39
-
40
- Best overall choice for AI-driven QA workflows:
41
-
42
- ```
43
- Strengths:
44
- - Multi-browser (Chromium, Firefox, WebKit) with one API
45
- - Auto-wait for elements (no manual sleep/waitFor)
46
- - Built-in screenshot, video, and trace capture
47
- - Network interception and mocking
48
- - Native accessibility testing via @axe-core/playwright
49
-
50
- Install: npm init playwright@latest
51
- ```
52
-
53
- ### Cypress
54
-
55
- Better for teams already invested in the Cypress ecosystem:
56
-
57
- ```
58
- Strengths:
59
- - Excellent interactive test runner with time-travel debugging
60
- - Rich plugin ecosystem
61
- - Good for component testing in isolation
62
-
63
- Limitations:
64
- - Chromium-family only (no Safari/WebKit)
65
- - Cannot test multiple browser tabs or origins in one test
66
- ```
67
-
68
- ### Puppeteer
69
-
70
- Use only when you need raw Chrome DevTools Protocol access:
71
-
72
- ```
73
- Strengths:
74
- - Direct CDP access for advanced scenarios (performance profiling, coverage)
75
- - Lightweight if you only need Chrome
76
-
77
- Limitations:
78
- - Chrome/Chromium only
79
- - No built-in test runner — you must bring your own
80
- - More boilerplate than Playwright for common tasks
81
- ```
82
-
83
- **Decision rule:** Default to Playwright unless the project already uses Cypress. Use Puppeteer only for Chrome-specific DevTools scenarios.
84
-
85
- ### Browser Configuration
86
-
87
- ```typescript
88
- // playwright.config.ts — recommended baseline
89
- import { defineConfig, devices } from '@playwright/test';
90
-
91
- export default defineConfig({
92
- testDir: './e2e',
93
- timeout: 30_000,
94
- retries: process.env.CI ? 2 : 0,
95
- use: {
96
- baseURL: process.env.BASE_URL || 'http://localhost:3000',
97
- screenshot: 'only-on-failure',
98
- video: 'retain-on-failure',
99
- trace: 'retain-on-failure',
100
- },
101
- projects: [
102
- { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
103
- { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
104
- { name: 'webkit', use: { ...devices['Desktop Safari'] } },
105
- { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
106
- { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
107
- ],
108
- webServer: {
109
- command: 'npm run dev',
110
- port: 3000,
111
- reuseExistingServer: !process.env.CI,
112
- },
113
- });
114
- ```
115
-
116
- ## QA Testing Workflow
117
-
118
- ### Step 1: Environment Preparation
119
-
120
- Before any browser test can run, the application must be running and data must be in a known state.
121
-
122
- ```
123
- Pre-flight checklist:
124
- □ Application builds without errors
125
- □ Dev server or preview server is running and responding
126
- □ Test database is seeded with known data (or API mocks are configured)
127
- □ Environment variables are set (API URLs, feature flags)
128
- □ No port conflicts on the target URL
129
- ```
130
-
131
- **Seed data strategy:** Either use a test database with fixtures, or intercept network requests and return mock responses. Never rely on production data for QA tests.
132
-
133
- ```typescript
134
- // Example: API mocking with Playwright
135
- test.beforeEach(async ({ page }) => {
136
- await page.route('**/api/tasks', route =>
137
- route.fulfill({
138
- status: 200,
139
- contentType: 'application/json',
140
- body: JSON.stringify([
141
- { id: 1, title: 'Test task', done: false },
142
- { id: 2, title: 'Completed task', done: true },
143
- ]),
144
- })
145
- );
146
- });
147
- ```
148
-
149
- ### Step 2: Core User Flow Testing
150
-
151
- Test the critical paths a real user follows. Prioritize by business impact:
152
-
153
- ```
154
- Priority 1 (Must pass — blocks release):
155
- - Authentication (login, logout, session persistence)
156
- - Primary CRUD operations (create, read, update, delete core entities)
157
- - Payment/checkout flows (if applicable)
158
- - Navigation between main sections
159
-
160
- Priority 2 (Should pass — file bugs if broken):
161
- - Search and filtering
162
- - Settings and preferences
163
- - Notification flows
164
- - Export/import operations
165
-
166
- Priority 3 (Nice to have):
167
- - Edge case interactions
168
- - Rarely used features
169
- - Admin-only flows
170
- ```
171
-
172
- 先把 Priority 1 做成稳定、可重复、可留证据的路径;在它们还不稳定时,不要把精力优先花在长尾流程上。
173
-
174
- ```typescript
175
- // Example: Complete login → dashboard → action flow
176
- test('user can log in and create a task', async ({ page }) => {
177
- await page.goto('/login');
178
-
179
- await page.getByLabel('Email').fill('user@test.com');
180
- await page.getByLabel('Password').fill('testpass123');
181
- await page.getByRole('button', { name: 'Sign in' }).click();
182
-
183
- // Verify redirect to dashboard
184
- await expect(page).toHaveURL('/dashboard');
185
- await expect(page.getByRole('heading', { name: 'My Tasks' })).toBeVisible();
186
-
187
- // Create a new task
188
- await page.getByRole('button', { name: 'New Task' }).click();
189
- await page.getByLabel('Task title').fill('Write QA tests');
190
- await page.getByRole('button', { name: 'Save' }).click();
191
-
192
- // Verify task appears in list
193
- await expect(page.getByText('Write QA tests')).toBeVisible();
194
- });
195
- ```
196
-
197
- ### Step 3: Interaction Testing
198
-
199
- Test form submissions, navigation, and state changes that go beyond happy-path flows:
200
-
201
- ```typescript
202
- // Form validation testing
203
- test('form shows validation errors for invalid input', async ({ page }) => {
204
- await page.goto('/register');
205
-
206
- // Submit empty form
207
- await page.getByRole('button', { name: 'Create account' }).click();
208
-
209
- // Check validation messages appear
210
- await expect(page.getByText('Email is required')).toBeVisible();
211
- await expect(page.getByText('Password must be at least 8 characters')).toBeVisible();
212
-
213
- // Check invalid email
214
- await page.getByLabel('Email').fill('not-an-email');
215
- await page.getByRole('button', { name: 'Create account' }).click();
216
- await expect(page.getByText('Enter a valid email address')).toBeVisible();
217
- });
218
-
219
- // Navigation and back-button behavior
220
- test('browser back button returns to previous page', async ({ page }) => {
221
- await page.goto('/tasks');
222
- await page.getByText('Task 1').click();
223
- await expect(page).toHaveURL(/\/tasks\/\d+/);
224
-
225
- await page.goBack();
226
- await expect(page).toHaveURL('/tasks');
227
- });
228
- ```
229
-
230
- ### Step 4: Visual Verification
231
-
232
- Use screenshots to detect visual regressions:
233
-
234
- ```typescript
235
- // Full-page screenshot comparison
236
- test('dashboard matches visual baseline', async ({ page }) => {
237
- await page.goto('/dashboard');
238
- await page.waitForLoadState('networkidle');
239
-
240
- await expect(page).toHaveScreenshot('dashboard.png', {
241
- maxDiffPixelRatio: 0.01, // Allow 1% pixel difference
242
- fullPage: true,
243
- });
244
- });
245
-
246
- // Component-level screenshot
247
- test('task card renders correctly', async ({ page }) => {
248
- await page.goto('/tasks');
249
- const card = page.getByTestId('task-card').first();
250
-
251
- await expect(card).toHaveScreenshot('task-card.png');
252
- });
253
- ```
254
-
255
- **Update baselines** when intentional visual changes are made: `npx playwright test --update-snapshots`
256
-
257
- ### Step 4.5: Failure Regression Evidence
258
-
259
- 当测试失败时,至少保留一类可以复盘的证据:
260
-
261
- - 截图,证明页面状态与预期不符
262
- - trace 或录像,证明交互链路在哪里中断
263
- - console error / network failure,证明是前端异常、接口失败还是环境问题
264
-
265
- 没有证据的“浏览器测过了”不构成可审查的结论。
266
-
267
- ### Step 5: Accessibility Audit
268
-
269
- Integrate axe-core for automated WCAG compliance checking:
270
-
271
- ```typescript
272
- import AxeBuilder from '@axe-core/playwright';
273
-
274
- test('home page has no accessibility violations', async ({ page }) => {
275
- await page.goto('/');
276
-
277
- const results = await new AxeBuilder({ page })
278
- .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
279
- .analyze();
280
-
281
- expect(results.violations).toEqual([]);
282
- });
283
-
284
- // Targeted audit on specific component
285
- test('modal dialog meets accessibility standards', async ({ page }) => {
286
- await page.goto('/tasks');
287
- await page.getByRole('button', { name: 'New Task' }).click();
288
-
289
- const modal = page.getByRole('dialog');
290
- const results = await new AxeBuilder({ page })
291
- .include(await modal.elementHandle())
292
- .analyze();
293
-
294
- expect(results.violations).toEqual([]);
295
- });
296
- ```
297
-
298
- **Manual keyboard checks to include:**
299
-
300
- ```
301
- □ Tab order follows visual order
302
- □ Focus is visible on all interactive elements
303
- □ Escape closes modals and dropdowns
304
- □ Enter/Space activates buttons and links
305
- □ Arrow keys work in menus and listboxes
306
- ```
307
-
308
- ### Step 6: Console and Network Monitoring
309
-
310
- Enforce a zero-error policy in the browser console and verify network behavior:
311
-
312
- ```typescript
313
- // Collect console errors during test
314
- test('page loads without console errors', async ({ page }) => {
315
- const errors: string[] = [];
316
- page.on('console', msg => {
317
- if (msg.type() === 'error') errors.push(msg.text());
318
- });
319
-
320
- await page.goto('/dashboard');
321
- await page.waitForLoadState('networkidle');
322
-
323
- // Filter out known third-party noise if needed
324
- const realErrors = errors.filter(e => !e.includes('third-party-sdk'));
325
- expect(realErrors).toHaveLength(0);
326
- });
327
-
328
- // Verify no failed network requests
329
- test('all API requests succeed', async ({ page }) => {
330
- const failedRequests: string[] = [];
331
- page.on('response', response => {
332
- if (response.status() >= 400) {
333
- failedRequests.push(`${response.status()} ${response.url()}`);
334
- }
335
- });
336
-
337
- await page.goto('/dashboard');
338
- await page.waitForLoadState('networkidle');
339
-
340
- expect(failedRequests).toHaveLength(0);
341
- });
342
-
343
- // Verify specific API calls are made
344
- test('dashboard fetches tasks on load', async ({ page }) => {
345
- const apiCalls: string[] = [];
346
- page.on('request', req => {
347
- if (req.url().includes('/api/')) apiCalls.push(req.url());
348
- });
349
-
350
- await page.goto('/dashboard');
351
- await page.waitForLoadState('networkidle');
352
-
353
- expect(apiCalls.some(url => url.includes('/api/tasks'))).toBe(true);
354
- });
355
- ```
356
-
357
- ### Step 7: Regression Test Generation
358
-
359
- When a bug is found during QA, immediately convert it into an automated test:
360
-
361
- ```typescript
362
- // Bug found: clicking "Delete" on last task causes blank screen
363
- // → Convert to regression test:
364
-
365
- test('deleting the last task shows empty state instead of blank screen', async ({ page }) => {
366
- // Setup: single task
367
- await page.route('**/api/tasks', route =>
368
- route.fulfill({ body: JSON.stringify([{ id: 1, title: 'Only task', done: false }]) })
369
- );
370
-
371
- await page.goto('/tasks');
372
- await page.getByRole('button', { name: 'Delete' }).click();
373
- await page.getByRole('button', { name: 'Confirm' }).click();
374
-
375
- // Should show empty state, not blank screen
376
- await expect(page.getByText('No tasks yet')).toBeVisible();
377
- await expect(page.getByRole('button', { name: 'Create Task' })).toBeVisible();
378
- });
379
- ```
380
-
381
- ## Common Test Scenario Templates
382
-
383
- ### Login/Registration
384
-
385
- ```typescript
386
- test.describe('Authentication', () => {
387
- test('successful login redirects to dashboard', async ({ page }) => { /* ... */ });
388
- test('wrong password shows error message', async ({ page }) => { /* ... */ });
389
- test('session persists across page reload', async ({ page }) => { /* ... */ });
390
- test('logout clears session and redirects to login', async ({ page }) => { /* ... */ });
391
- test('registration with valid data creates account', async ({ page }) => { /* ... */ });
392
- test('registration with duplicate email shows error', async ({ page }) => { /* ... */ });
393
- });
394
- ```
395
-
396
- ### CRUD Operations
397
-
398
- ```typescript
399
- test.describe('Task CRUD', () => {
400
- test('create: new task appears in list', async ({ page }) => { /* ... */ });
401
- test('read: task detail page shows all fields', async ({ page }) => { /* ... */ });
402
- test('update: edited task saves and reflects changes', async ({ page }) => { /* ... */ });
403
- test('delete: removed task disappears with confirmation', async ({ page }) => { /* ... */ });
404
- test('bulk: select-all and batch delete works', async ({ page }) => { /* ... */ });
405
- });
406
- ```
407
-
408
- ### Responsive Layout
409
-
410
- ```typescript
411
- const viewports = [
412
- { name: 'mobile', width: 375, height: 812 },
413
- { name: 'tablet', width: 768, height: 1024 },
414
- { name: 'desktop', width: 1440, height: 900 },
415
- ];
416
-
417
- for (const vp of viewports) {
418
- test(`dashboard layout is correct at ${vp.name}`, async ({ page }) => {
419
- await page.setViewportSize({ width: vp.width, height: vp.height });
420
- await page.goto('/dashboard');
421
- await expect(page).toHaveScreenshot(`dashboard-${vp.name}.png`);
422
- });
423
- }
424
- ```
425
-
426
- ### Error State Display
427
-
428
- ```typescript
429
- test.describe('Error handling', () => {
430
- test('API failure shows error message with retry button', async ({ page }) => {
431
- await page.route('**/api/tasks', route => route.fulfill({ status: 500 }));
432
- await page.goto('/tasks');
433
-
434
- await expect(page.getByText('Something went wrong')).toBeVisible();
435
- await expect(page.getByRole('button', { name: 'Retry' })).toBeVisible();
436
- });
437
-
438
- test('404 page shows helpful navigation', async ({ page }) => {
439
- await page.goto('/nonexistent-page');
440
- await expect(page.getByText('Page not found')).toBeVisible();
441
- await expect(page.getByRole('link', { name: 'Go home' })).toBeVisible();
442
- });
443
- });
444
- ```
445
-
446
- ## QA Report Format
31
+ | 工具 | 默认判断 |
32
+ |---|---|
33
+ | Playwright | 默认推荐,适合跨浏览器、trace、截图、自动等待和 CI |
34
+ | Cypress | 项目已经使用 Cypress 时沿用 |
35
+ | Puppeteer | 只在需要 Chrome DevTools Protocol 细节时使用 |
36
+ | Browser plugin / in-app browser | 适合快速人工式走查和本地交互验证 |
447
37
 
448
- After a QA run, produce a structured report:
38
+ 不要为了浏览器 QA 引入第二套 E2E 框架,除非现有工具无法覆盖目标。
449
39
 
450
- ```markdown
451
- ## QA Report — [Feature/Page Name] — [Date]
40
+ ## 关键路径选择
452
41
 
453
- ### Environment
454
- - URL: http://localhost:3000
455
- - Browser: Chromium 120, Firefox 121, WebKit 17.4
456
- - Viewport: 1440×900 (desktop), 375×812 (mobile)
42
+ 优先级:
457
43
 
458
- ### Summary
459
- - Total tests: 24
460
- - ✅ Passed: 21
461
- - ❌ Failed: 2
462
- - ⚠️ Flaky: 1
44
+ - P0:应用能打开,核心页面不是空白。
45
+ - P1:主要业务动作能完成,并看到可验证结果。
46
+ - P2:错误路径有明确反馈,不是静默失败。
47
+ - P3:关键移动端/桌面布局没有阻塞性重叠。
463
48
 
464
- ### Failed Tests
465
- | Test | Browser | Error | Screenshot |
466
- |------|---------|-------|------------|
467
- | Login form validation | WebKit | "Email required" message not visible | ![](/screenshots/login-webkit-001.png) |
468
- | Task delete on mobile | Mobile Chrome | Confirm button outside viewport | ![](/screenshots/delete-mobile-001.png) |
49
+ bug 修复场景必须先覆盖:
469
50
 
470
- ### Accessibility Audit
471
- - Violations found: 3
472
- 1. Missing alt text on user avatar (img element) — Critical
473
- 2. Color contrast ratio 3.8:1 on secondary text — Moderate
474
- 3. Missing aria-label on icon-only button — Moderate
51
+ - 原始失败如何复现。
52
+ - 修复后如何证明失败不再发生。
475
53
 
476
- ### Console Errors
477
- - None (clean)
54
+ ## 验收记录格式
478
55
 
479
- ### Network Issues
480
- - None (all requests 2xx)
56
+ 浏览器 QA 的结果必须能被复查:
481
57
 
482
- ### Recommendations
483
- 1. [Critical] Fix WebKit form validation display — blocks release
484
- 2. [Critical] Fix mobile viewport overflow on delete confirmation
485
- 3. [Moderate] Add missing alt text and aria-labels
486
- 4. [Low] Improve secondary text contrast ratio
58
+ ```text
59
+ Browser QA transcript:
60
+ - Target:
61
+ - Build/server:
62
+ - Paths tested:
63
+ - Data setup:
64
+ - Evidence:
65
+ - Console/network:
66
+ - Screenshots/traces:
67
+ - Result:
68
+ - Follow-up:
487
69
  ```
488
70
 
489
- ## Integration with Other Skills
71
+ 没有证据的“我点过了”不算完成。
490
72
 
491
- ### With `frontend-ui-engineering`
73
+ ## 最小检查清单
492
74
 
493
- Development → QA feedback loop:
75
+ - 页面加载成功,没有白屏或阻塞性错误。
76
+ - 关键按钮、输入框、菜单、弹窗可访问。
77
+ - 主流程成功结果可见。
78
+ - 失败路径有用户可理解的错误反馈。
79
+ - 控制台没有与本次改动相关的新错误。
80
+ - 网络请求状态和错误处理符合预期。
81
+ - 关键视口下文本和控件不重叠。
494
82
 
495
- ```
496
- Build component → Run QA → Fix issues → Re-run QA → Approve
497
- ```
83
+ ## 与自动化测试的关系
498
84
 
499
- QA tests validate everything the frontend skill specifies: accessibility, responsive behavior, loading/error/empty states.
85
+ - 已有稳定 E2E:优先运行并补充必要断言。
86
+ - 没有 E2E:先做最小浏览器走查,再决定是否把路径沉淀为 Playwright 测试。
87
+ - 一次性验证:可以只保留 transcript 和截图。
88
+ - 高风险回归:应补自动化测试,避免下次靠人工记忆。
500
89
 
501
- ### With `test-driven-development`
90
+ ## 常见失败处理
502
91
 
503
- TDD covers unit and integration layers. Browser QA adds the E2E layer:
92
+ - 白屏:先看控制台、构建输出和入口资源 404。
93
+ - 点击无效:检查元素是否被遮挡、disabled、事件未绑定或异步状态未完成。
94
+ - 表单失败:检查校验、提交 payload、接口响应和错误反馈。
95
+ - 布局错位:截 desktop/mobile 两个视口,定位固定宽度、溢出和层级遮挡。
96
+ - 间歇失败:避免 `sleep`,使用明确的可见性、URL、网络或状态等待条件。
504
97
 
505
- ```
506
- Unit tests (TDD) → Function-level correctness
507
- Integration tests → Module interaction
508
- Browser QA tests → User-facing experience (this skill)
509
- ```
98
+ ## 边界
510
99
 
511
- ### With `verification-before-completion`
100
+ - 不把浏览器 QA 当成完整可访问性审计;需要深挖时转专项工具。
101
+ - 不把视觉主观偏好当成阻塞问题,除非它影响可用性或验收标准。
102
+ - 不连接生产数据做破坏性动作。
103
+ - 不在没有目标路径的情况下机械铺满长尾场景。
512
104
 
513
- QA test results serve as concrete verification evidence:
105
+ ## 推荐输出
514
106
 
107
+ ```text
108
+ Recommendation: <放行 / 修复后重测 / 补自动化测试> because <浏览器证据、失败影响和替代方案 trade-off>。
515
109
  ```
516
- Verification evidence:
517
- - 24/24 browser tests passing
518
- - Zero console errors
519
- - Zero accessibility violations
520
- - Screenshots attached for visual confirmation
521
- ```
522
-
523
- ## Common Rationalizations
524
-
525
- | Rationalization | Reality |
526
- |---|---|
527
- | "Unit tests are enough" | Unit tests can't catch a broken layout, a missing button, or a form that submits empty data. |
528
- | "Manual QA is faster" | Manual QA is faster once. Automated QA is faster every time after that — and it doesn't forget edge cases. |
529
- | "E2E tests are too slow" | A focused suite of 20-30 critical-path tests runs in under 2 minutes. That's faster than debugging a production incident. |
530
- | "We'll add browser tests later" | Later never comes. The cost of writing tests increases as the app grows. Start with the critical paths now. |
531
- | "It works on my machine" | Browser tests run in consistent environments. They catch the cross-browser and viewport issues you won't see on your dev setup. |
532
-
533
- ## Red Flags
534
-
535
- - No browser tests exist for user-facing features
536
- - QA is only done manually before releases (no automation)
537
- - Tests use arbitrary `sleep()` / `waitForTimeout()` instead of proper element assertions
538
- - Screenshot baselines haven't been updated in months (everything is ignored)
539
- - Accessibility audits have never been run
540
- - Console errors are ignored ("it's just a warning")
541
- - Tests only run in one browser (skipping Firefox/WebKit/mobile)
542
- - No test data seeding — tests depend on production data or shared environments
543
-
544
- ## Verification
545
-
546
- After QA testing is complete:
547
110
 
548
- - [ ] All Priority 1 (critical path) tests pass across target browsers
549
- - [ ] Zero unhandled console errors in the browser
550
- - [ ] Accessibility audit shows zero critical violations
551
- - [ ] Visual screenshots are captured and reviewed
552
- - [ ] Failed tests have filed bugs with reproduction steps
553
- - [ ] Regression tests are written for any bugs discovered
554
- - [ ] QA report is generated with pass/fail summary and evidence
111
+ 推荐必须说明证据来自哪条路径,以及未覆盖风险是什么。