start-vibing 2.0.11 → 2.0.13

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 (131) hide show
  1. package/README.md +177 -177
  2. package/dist/cli.js +19 -2
  3. package/package.json +42 -42
  4. package/template/.claude/CLAUDE.md +174 -174
  5. package/template/.claude/agents/01-orchestration/agent-selector.md +130 -130
  6. package/template/.claude/agents/01-orchestration/checkpoint-manager.md +142 -142
  7. package/template/.claude/agents/01-orchestration/context-manager.md +138 -138
  8. package/template/.claude/agents/01-orchestration/error-recovery.md +182 -182
  9. package/template/.claude/agents/01-orchestration/orchestrator.md +114 -114
  10. package/template/.claude/agents/01-orchestration/parallel-coordinator.md +141 -141
  11. package/template/.claude/agents/01-orchestration/task-decomposer.md +121 -121
  12. package/template/.claude/agents/01-orchestration/workflow-router.md +114 -114
  13. package/template/.claude/agents/02-typescript/bun-runtime-expert.md +197 -197
  14. package/template/.claude/agents/02-typescript/esm-resolver.md +193 -193
  15. package/template/.claude/agents/02-typescript/import-alias-enforcer.md +158 -158
  16. package/template/.claude/agents/02-typescript/ts-generics-helper.md +183 -183
  17. package/template/.claude/agents/02-typescript/ts-migration-helper.md +238 -238
  18. package/template/.claude/agents/02-typescript/ts-strict-checker.md +180 -180
  19. package/template/.claude/agents/02-typescript/ts-types-analyzer.md +199 -199
  20. package/template/.claude/agents/02-typescript/type-definition-writer.md +187 -187
  21. package/template/.claude/agents/02-typescript/zod-schema-designer.md +212 -212
  22. package/template/.claude/agents/02-typescript/zod-validator.md +158 -158
  23. package/template/.claude/agents/03-testing/playwright-assertions.md +265 -265
  24. package/template/.claude/agents/03-testing/playwright-e2e.md +247 -247
  25. package/template/.claude/agents/03-testing/playwright-fixtures.md +234 -234
  26. package/template/.claude/agents/03-testing/playwright-multi-viewport.md +256 -256
  27. package/template/.claude/agents/03-testing/playwright-page-objects.md +247 -247
  28. package/template/.claude/agents/03-testing/test-cleanup-manager.md +248 -248
  29. package/template/.claude/agents/03-testing/test-data-generator.md +254 -254
  30. package/template/.claude/agents/03-testing/tester-integration.md +278 -278
  31. package/template/.claude/agents/03-testing/tester-unit.md +207 -207
  32. package/template/.claude/agents/03-testing/vitest-config.md +287 -287
  33. package/template/.claude/agents/04-docker/container-health.md +255 -255
  34. package/template/.claude/agents/04-docker/deployment-validator.md +225 -225
  35. package/template/.claude/agents/04-docker/docker-compose-designer.md +281 -281
  36. package/template/.claude/agents/04-docker/docker-env-manager.md +235 -235
  37. package/template/.claude/agents/04-docker/docker-multi-stage.md +241 -241
  38. package/template/.claude/agents/04-docker/dockerfile-optimizer.md +208 -208
  39. package/template/.claude/agents/05-database/database-seeder.md +273 -273
  40. package/template/.claude/agents/05-database/mongodb-query-optimizer.md +230 -230
  41. package/template/.claude/agents/05-database/mongoose-aggregation.md +306 -306
  42. package/template/.claude/agents/05-database/mongoose-index-optimizer.md +182 -182
  43. package/template/.claude/agents/05-database/mongoose-schema-designer.md +267 -267
  44. package/template/.claude/agents/06-security/auth-session-validator.md +68 -68
  45. package/template/.claude/agents/06-security/input-sanitizer.md +80 -80
  46. package/template/.claude/agents/06-security/owasp-checker.md +97 -97
  47. package/template/.claude/agents/06-security/permission-auditor.md +100 -100
  48. package/template/.claude/agents/06-security/security-auditor.md +84 -84
  49. package/template/.claude/agents/06-security/sensitive-data-scanner.md +83 -83
  50. package/template/.claude/agents/07-documentation/api-documenter.md +136 -136
  51. package/template/.claude/agents/07-documentation/changelog-manager.md +105 -105
  52. package/template/.claude/agents/07-documentation/documenter.md +76 -76
  53. package/template/.claude/agents/07-documentation/domain-updater.md +81 -81
  54. package/template/.claude/agents/07-documentation/jsdoc-generator.md +114 -114
  55. package/template/.claude/agents/07-documentation/readme-generator.md +135 -135
  56. package/template/.claude/agents/08-git/branch-manager.md +58 -58
  57. package/template/.claude/agents/08-git/commit-manager.md +63 -63
  58. package/template/.claude/agents/08-git/pr-creator.md +76 -76
  59. package/template/.claude/agents/09-quality/code-reviewer.md +71 -71
  60. package/template/.claude/agents/09-quality/quality-checker.md +67 -67
  61. package/template/.claude/agents/10-research/best-practices-finder.md +89 -89
  62. package/template/.claude/agents/10-research/competitor-analyzer.md +106 -106
  63. package/template/.claude/agents/10-research/pattern-researcher.md +93 -93
  64. package/template/.claude/agents/10-research/research-cache-manager.md +76 -76
  65. package/template/.claude/agents/10-research/research-web.md +98 -98
  66. package/template/.claude/agents/10-research/tech-evaluator.md +101 -101
  67. package/template/.claude/agents/11-ui-ux/accessibility-auditor.md +136 -136
  68. package/template/.claude/agents/11-ui-ux/design-system-enforcer.md +125 -125
  69. package/template/.claude/agents/11-ui-ux/skeleton-generator.md +118 -118
  70. package/template/.claude/agents/11-ui-ux/ui-desktop.md +132 -132
  71. package/template/.claude/agents/11-ui-ux/ui-mobile.md +98 -98
  72. package/template/.claude/agents/11-ui-ux/ui-tablet.md +110 -110
  73. package/template/.claude/agents/12-performance/api-latency-analyzer.md +156 -156
  74. package/template/.claude/agents/12-performance/bundle-analyzer.md +113 -113
  75. package/template/.claude/agents/12-performance/memory-leak-detector.md +137 -137
  76. package/template/.claude/agents/12-performance/performance-profiler.md +115 -115
  77. package/template/.claude/agents/12-performance/query-optimizer.md +124 -124
  78. package/template/.claude/agents/12-performance/render-optimizer.md +154 -154
  79. package/template/.claude/agents/13-debugging/build-error-fixer.md +207 -207
  80. package/template/.claude/agents/13-debugging/debugger.md +149 -149
  81. package/template/.claude/agents/13-debugging/error-stack-analyzer.md +141 -141
  82. package/template/.claude/agents/13-debugging/network-debugger.md +208 -208
  83. package/template/.claude/agents/13-debugging/runtime-error-fixer.md +181 -181
  84. package/template/.claude/agents/13-debugging/type-error-resolver.md +185 -185
  85. package/template/.claude/agents/14-validation/final-validator.md +93 -93
  86. package/template/.claude/agents/_backup/analyzer.md +134 -134
  87. package/template/.claude/agents/_backup/code-reviewer.md +279 -279
  88. package/template/.claude/agents/_backup/commit-manager.md +219 -219
  89. package/template/.claude/agents/_backup/debugger.md +280 -280
  90. package/template/.claude/agents/_backup/documenter.md +237 -237
  91. package/template/.claude/agents/_backup/domain-updater.md +197 -197
  92. package/template/.claude/agents/_backup/final-validator.md +169 -169
  93. package/template/.claude/agents/_backup/orchestrator.md +149 -149
  94. package/template/.claude/agents/_backup/performance.md +232 -232
  95. package/template/.claude/agents/_backup/quality-checker.md +240 -240
  96. package/template/.claude/agents/_backup/research.md +315 -315
  97. package/template/.claude/agents/_backup/security-auditor.md +192 -192
  98. package/template/.claude/agents/_backup/tester.md +566 -566
  99. package/template/.claude/agents/_backup/ui-ux-reviewer.md +247 -247
  100. package/template/.claude/config/README.md +30 -30
  101. package/template/.claude/config/mcp-config.json +344 -344
  102. package/template/.claude/config/project-config.json +53 -53
  103. package/template/.claude/config/quality-gates.json +46 -46
  104. package/template/.claude/config/security-rules.json +45 -45
  105. package/template/.claude/config/testing-config.json +164 -164
  106. package/template/.claude/hooks/SETUP.md +126 -126
  107. package/template/.claude/hooks/run-hook.ts +176 -176
  108. package/template/.claude/hooks/stop-validator.ts +914 -824
  109. package/template/.claude/hooks/user-prompt-submit.ts +886 -886
  110. package/template/.claude/scripts/mcp-quick-install.ts +151 -151
  111. package/template/.claude/scripts/setup-mcps.ts +651 -651
  112. package/template/.claude/settings.json +275 -275
  113. package/template/.claude/skills/bun-runtime/SKILL.md +430 -430
  114. package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +431 -431
  115. package/template/.claude/skills/codebase-knowledge/domains/mcp-integration.md +295 -295
  116. package/template/.claude/skills/debugging-patterns/SKILL.md +485 -485
  117. package/template/.claude/skills/docker-patterns/SKILL.md +555 -555
  118. package/template/.claude/skills/git-workflow/SKILL.md +454 -454
  119. package/template/.claude/skills/mongoose-patterns/SKILL.md +499 -499
  120. package/template/.claude/skills/nextjs-app-router/SKILL.md +327 -327
  121. package/template/.claude/skills/performance-patterns/SKILL.md +547 -547
  122. package/template/.claude/skills/playwright-automation/SKILL.md +438 -438
  123. package/template/.claude/skills/react-patterns/SKILL.md +389 -389
  124. package/template/.claude/skills/research-cache/SKILL.md +222 -222
  125. package/template/.claude/skills/shadcn-ui/SKILL.md +511 -511
  126. package/template/.claude/skills/tailwind-patterns/SKILL.md +465 -465
  127. package/template/.claude/skills/test-coverage/SKILL.md +467 -467
  128. package/template/.claude/skills/trpc-api/SKILL.md +434 -434
  129. package/template/.claude/skills/typescript-strict/SKILL.md +367 -367
  130. package/template/.claude/skills/zod-validation/SKILL.md +403 -403
  131. package/template/CLAUDE.md +117 -117
@@ -1,438 +1,438 @@
1
- ---
2
- name: playwright-automation
3
- description: Playwright testing automation patterns. E2E tests, browser automation, visual testing, API testing. Use when writing automated tests with Playwright.
4
- allowed-tools: Read, Write, Edit, Bash, Grep, Glob
5
- ---
6
-
7
- # Playwright Automation - E2E Testing Patterns
8
-
9
- ## Purpose
10
-
11
- Expert guidance for Playwright:
12
-
13
- - **E2E Testing** - Full user journey tests
14
- - **Browser Automation** - Cross-browser testing
15
- - **Visual Testing** - Screenshots and comparisons
16
- - **API Testing** - Request mocking and validation
17
- - **Page Object Model** - Maintainable test architecture
18
-
19
- ---
20
-
21
- ## Project Structure
22
-
23
- ```
24
- tests/
25
- ├── e2e/
26
- │ ├── fixtures/
27
- │ │ ├── index.ts # Custom fixtures
28
- │ │ ├── auth.fixture.ts # Auth helpers
29
- │ │ └── db.fixture.ts # Database helpers
30
- │ ├── pages/
31
- │ │ ├── base.page.ts # Base page object
32
- │ │ ├── login.page.ts
33
- │ │ └── dashboard.page.ts
34
- │ ├── flows/
35
- │ │ ├── auth.spec.ts # Auth flow tests
36
- │ │ └── crud.spec.ts # CRUD flow tests
37
- │ └── api/
38
- │ └── endpoints.spec.ts # API-only tests
39
- ├── playwright.config.ts
40
- └── global-setup.ts
41
- ```
42
-
43
- ---
44
-
45
- ## Configuration
46
-
47
- ```typescript
48
- // playwright.config.ts
49
- import { defineConfig, devices } from '@playwright/test';
50
-
51
- export default defineConfig({
52
- testDir: './tests/e2e',
53
- fullyParallel: true,
54
- forbidOnly: !!process.env['CI'],
55
- retries: process.env['CI'] ? 2 : 0,
56
- workers: process.env['CI'] ? 1 : undefined,
57
- reporter: 'html',
58
-
59
- use: {
60
- baseURL: 'http://localhost:3000',
61
- trace: 'on-first-retry',
62
- screenshot: 'only-on-failure',
63
- },
64
-
65
- projects: [
66
- // Desktop browsers
67
- { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
68
- { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
69
- { name: 'webkit', use: { ...devices['Desktop Safari'] } },
70
-
71
- // Mobile viewports
72
- { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
73
- { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } },
74
-
75
- // Tablet
76
- { name: 'iPad', use: { ...devices['iPad Pro 11'] } },
77
- ],
78
-
79
- webServer: {
80
- command: 'bun run dev',
81
- url: 'http://localhost:3000',
82
- reuseExistingServer: !process.env['CI'],
83
- },
84
- });
85
- ```
86
-
87
- ---
88
-
89
- ## Page Object Model
90
-
91
- ### Base Page
92
-
93
- ```typescript
94
- // tests/e2e/pages/base.page.ts
95
- import { type Page, type Locator, expect } from '@playwright/test';
96
-
97
- export abstract class BasePage {
98
- protected readonly page: Page;
99
-
100
- constructor(page: Page) {
101
- this.page = page;
102
- }
103
-
104
- // Common elements
105
- get loadingSpinner(): Locator {
106
- return this.page.getByTestId('loading-spinner');
107
- }
108
-
109
- get errorMessage(): Locator {
110
- return this.page.getByTestId('error-message');
111
- }
112
-
113
- get successMessage(): Locator {
114
- return this.page.getByTestId('success-message');
115
- }
116
-
117
- // Common actions
118
- async waitForLoad(): Promise<void> {
119
- await this.loadingSpinner.waitFor({ state: 'hidden' });
120
- }
121
-
122
- async expectError(message: string): Promise<void> {
123
- await expect(this.errorMessage).toContainText(message);
124
- }
125
-
126
- async expectSuccess(message: string): Promise<void> {
127
- await expect(this.successMessage).toContainText(message);
128
- }
129
-
130
- // Navigation
131
- async goto(path: string): Promise<void> {
132
- await this.page.goto(path);
133
- await this.waitForLoad();
134
- }
135
- }
136
- ```
137
-
138
- ### Login Page
139
-
140
- ```typescript
141
- // tests/e2e/pages/login.page.ts
142
- import { type Page, type Locator } from '@playwright/test';
143
- import { BasePage } from './base.page';
144
-
145
- export class LoginPage extends BasePage {
146
- readonly emailInput: Locator;
147
- readonly passwordInput: Locator;
148
- readonly submitButton: Locator;
149
- readonly forgotPasswordLink: Locator;
150
-
151
- constructor(page: Page) {
152
- super(page);
153
- this.emailInput = page.getByTestId('email-input');
154
- this.passwordInput = page.getByTestId('password-input');
155
- this.submitButton = page.getByTestId('submit-button');
156
- this.forgotPasswordLink = page.getByRole('link', { name: /forgot/i });
157
- }
158
-
159
- async goto(): Promise<void> {
160
- await super.goto('/auth/login');
161
- }
162
-
163
- async login(email: string, password: string): Promise<void> {
164
- await this.emailInput.fill(email);
165
- await this.passwordInput.fill(password);
166
- await this.submitButton.click();
167
- }
168
- }
169
- ```
170
-
171
- ---
172
-
173
- ## Custom Fixtures
174
-
175
- ### Auth Fixture
176
-
177
- ```typescript
178
- // tests/e2e/fixtures/auth.fixture.ts
179
- import { test as base, type Page } from '@playwright/test';
180
-
181
- export interface TestUser {
182
- name: string;
183
- email: string;
184
- password: string;
185
- }
186
-
187
- export function generateTestUser(): TestUser {
188
- const timestamp = Date.now();
189
- const random = Math.random().toString(36).substring(7);
190
- return {
191
- name: `Test User ${timestamp}`,
192
- email: `testuser_${timestamp}_${random}@test.com`,
193
- password: 'TestPassword123!',
194
- };
195
- }
196
-
197
- export async function registerUser(page: Page, user: TestUser): Promise<void> {
198
- await page.goto('/auth/register');
199
- await page.getByTestId('name-input').fill(user.name);
200
- await page.getByTestId('email-input').fill(user.email);
201
- await page.getByTestId('password-input').fill(user.password);
202
- await page.getByTestId('confirm-password-input').fill(user.password);
203
- await page.getByTestId('submit-button').click();
204
- await page.waitForURL(/\/app/, { timeout: 10000 });
205
- }
206
-
207
- export async function loginUser(page: Page, user: TestUser): Promise<void> {
208
- await page.goto('/auth/login');
209
- await page.getByTestId('email-input').fill(user.email);
210
- await page.getByTestId('password-input').fill(user.password);
211
- await page.getByTestId('submit-button').click();
212
- await page.waitForURL(/\/app/, { timeout: 10000 });
213
- }
214
- ```
215
-
216
- ### Database Cleanup Fixture
217
-
218
- ```typescript
219
- // tests/e2e/fixtures/db.fixture.ts
220
- import { test as base } from '@playwright/test';
221
- import { MongoClient, type Db, type ObjectId } from 'mongodb';
222
-
223
- type CleanupFixtures = {
224
- db: Db;
225
- createdIds: Map<string, ObjectId[]>;
226
- trackCreated: (collection: string, id: ObjectId) => void;
227
- };
228
-
229
- export const test = base.extend<CleanupFixtures>({
230
- db: async ({}, use) => {
231
- const client = await MongoClient.connect(process.env['MONGODB_URI']!);
232
- const db = client.db();
233
- await use(db);
234
- await client.close();
235
- },
236
-
237
- createdIds: async ({}, use) => {
238
- await use(new Map());
239
- },
240
-
241
- trackCreated: async ({ createdIds }, use) => {
242
- await use((collection: string, id: ObjectId) => {
243
- const existing = createdIds.get(collection) || [];
244
- existing.push(id);
245
- createdIds.set(collection, existing);
246
- });
247
- },
248
- });
249
-
250
- // Auto-cleanup after each test
251
- test.afterEach(async ({ db, createdIds }) => {
252
- for (const [collection, ids] of createdIds.entries()) {
253
- if (ids.length > 0) {
254
- await db.collection(collection).deleteMany({ _id: { $in: ids } });
255
- }
256
- }
257
- });
258
-
259
- export { expect } from '@playwright/test';
260
- ```
261
-
262
- ---
263
-
264
- ## Test Patterns
265
-
266
- ### Auth Flow Test
267
-
268
- ```typescript
269
- // tests/e2e/flows/auth.spec.ts
270
- import { test, expect } from '../fixtures';
271
- import { generateTestUser, registerUser, loginUser } from '../fixtures/auth.fixture';
272
- import { LoginPage } from '../pages/login.page';
273
-
274
- test.describe('Authentication Flow', () => {
275
- test('complete registration and login journey', async ({ page, db, trackCreated }) => {
276
- const user = generateTestUser();
277
-
278
- // 1. Register
279
- await registerUser(page, user);
280
-
281
- // 2. Verify in database
282
- const dbUser = await db.collection('users').findOne({ email: user.email });
283
- expect(dbUser).toBeTruthy();
284
- trackCreated('users', dbUser!._id);
285
-
286
- // 3. Logout
287
- await page.getByTestId('logout-button').click();
288
- await expect(page).toHaveURL('/auth/login');
289
-
290
- // 4. Login again
291
- await loginUser(page, user);
292
- await expect(page).toHaveURL(/\/app/);
293
- });
294
-
295
- test('shows error for invalid credentials', async ({ page }) => {
296
- const loginPage = new LoginPage(page);
297
- await loginPage.goto();
298
-
299
- await loginPage.login('invalid@email.com', 'wrongpassword');
300
-
301
- await loginPage.expectError('Invalid credentials');
302
- });
303
- });
304
- ```
305
-
306
- ### Multi-Viewport Test
307
-
308
- ```typescript
309
- // tests/e2e/flows/responsive.spec.ts
310
- import { test, expect } from '@playwright/test';
311
-
312
- const viewports = [
313
- { name: 'mobile', width: 375, height: 667 },
314
- { name: 'tablet', width: 768, height: 1024 },
315
- { name: 'desktop', width: 1280, height: 800 },
316
- ] as const;
317
-
318
- for (const viewport of viewports) {
319
- test.describe(`Responsive - ${viewport.name}`, () => {
320
- test.use({ viewport: { width: viewport.width, height: viewport.height } });
321
-
322
- test('navigation adapts to viewport', async ({ page }) => {
323
- await page.goto('/');
324
-
325
- if (viewport.width < 768) {
326
- // Mobile: hamburger menu
327
- await expect(page.getByTestId('hamburger-menu')).toBeVisible();
328
- await expect(page.getByTestId('sidebar')).toBeHidden();
329
-
330
- // Open mobile menu
331
- await page.getByTestId('hamburger-menu').click();
332
- await expect(page.getByTestId('mobile-nav')).toBeVisible();
333
- } else {
334
- // Desktop: sidebar visible
335
- await expect(page.getByTestId('sidebar')).toBeVisible();
336
- await expect(page.getByTestId('hamburger-menu')).toBeHidden();
337
- }
338
- });
339
- });
340
- }
341
- ```
342
-
343
- ### API Testing
344
-
345
- ```typescript
346
- // tests/e2e/api/endpoints.spec.ts
347
- import { test, expect } from '@playwright/test';
348
-
349
- test.describe('API Endpoints', () => {
350
- test('requires authentication', async ({ request }) => {
351
- const response = await request.get('/api/users');
352
- expect(response.status()).toBe(401);
353
- });
354
-
355
- test('validates request body', async ({ request }) => {
356
- const response = await request.post('/api/users', {
357
- data: { email: 'invalid-email' },
358
- });
359
- expect(response.status()).toBe(400);
360
-
361
- const body = await response.json();
362
- expect(body.errors).toBeDefined();
363
- });
364
-
365
- test('creates user with valid data', async ({ request }) => {
366
- const response = await request.post('/api/users', {
367
- data: {
368
- name: 'Test User',
369
- email: 'test@example.com',
370
- password: 'Password123!',
371
- },
372
- });
373
- expect(response.status()).toBe(201);
374
-
375
- const user = await response.json();
376
- expect(user.id).toBeDefined();
377
- expect(user.email).toBe('test@example.com');
378
- });
379
- });
380
- ```
381
-
382
- ---
383
-
384
- ## Commands
385
-
386
- ```bash
387
- # Run all tests
388
- bunx playwright test
389
-
390
- # Run with UI
391
- bunx playwright test --ui
392
-
393
- # Run specific file
394
- bunx playwright test auth.spec.ts
395
-
396
- # Run specific project (viewport)
397
- bunx playwright test --project="Mobile Chrome"
398
-
399
- # Debug mode
400
- bunx playwright test --debug
401
-
402
- # Generate report
403
- bunx playwright show-report
404
-
405
- # Update snapshots
406
- bunx playwright test --update-snapshots
407
-
408
- # Trace viewer
409
- bunx playwright show-trace trace.zip
410
- ```
411
-
412
- ---
413
-
414
- ## Agent Integration
415
-
416
- This skill is used by:
417
-
418
- - **playwright-e2e** agent
419
- - **playwright-fixtures** agent
420
- - **playwright-page-objects** agent
421
- - **playwright-multi-viewport** agent
422
- - **test-coverage** skill
423
-
424
- ---
425
-
426
- ## FORBIDDEN
427
-
428
- 1. **Hardcoded test data** - Generate unique data
429
- 2. **Skipped tests** - Never use `.skip()` or `.only()`
430
- 3. **No cleanup** - Always clean up test data
431
- 4. **Mocked auth** - Use real authentication
432
- 5. **Single viewport** - Test all viewports
433
-
434
- ---
435
-
436
- ## Version
437
-
438
- - **v1.0.0** - Initial implementation based on Playwright best practices
1
+ ---
2
+ name: playwright-automation
3
+ description: Playwright testing automation patterns. E2E tests, browser automation, visual testing, API testing. Use when writing automated tests with Playwright.
4
+ allowed-tools: Read, Write, Edit, Bash, Grep, Glob
5
+ ---
6
+
7
+ # Playwright Automation - E2E Testing Patterns
8
+
9
+ ## Purpose
10
+
11
+ Expert guidance for Playwright:
12
+
13
+ - **E2E Testing** - Full user journey tests
14
+ - **Browser Automation** - Cross-browser testing
15
+ - **Visual Testing** - Screenshots and comparisons
16
+ - **API Testing** - Request mocking and validation
17
+ - **Page Object Model** - Maintainable test architecture
18
+
19
+ ---
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ tests/
25
+ ├── e2e/
26
+ │ ├── fixtures/
27
+ │ │ ├── index.ts # Custom fixtures
28
+ │ │ ├── auth.fixture.ts # Auth helpers
29
+ │ │ └── db.fixture.ts # Database helpers
30
+ │ ├── pages/
31
+ │ │ ├── base.page.ts # Base page object
32
+ │ │ ├── login.page.ts
33
+ │ │ └── dashboard.page.ts
34
+ │ ├── flows/
35
+ │ │ ├── auth.spec.ts # Auth flow tests
36
+ │ │ └── crud.spec.ts # CRUD flow tests
37
+ │ └── api/
38
+ │ └── endpoints.spec.ts # API-only tests
39
+ ├── playwright.config.ts
40
+ └── global-setup.ts
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Configuration
46
+
47
+ ```typescript
48
+ // playwright.config.ts
49
+ import { defineConfig, devices } from '@playwright/test';
50
+
51
+ export default defineConfig({
52
+ testDir: './tests/e2e',
53
+ fullyParallel: true,
54
+ forbidOnly: !!process.env['CI'],
55
+ retries: process.env['CI'] ? 2 : 0,
56
+ workers: process.env['CI'] ? 1 : undefined,
57
+ reporter: 'html',
58
+
59
+ use: {
60
+ baseURL: 'http://localhost:3000',
61
+ trace: 'on-first-retry',
62
+ screenshot: 'only-on-failure',
63
+ },
64
+
65
+ projects: [
66
+ // Desktop browsers
67
+ { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
68
+ { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
69
+ { name: 'webkit', use: { ...devices['Desktop Safari'] } },
70
+
71
+ // Mobile viewports
72
+ { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
73
+ { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } },
74
+
75
+ // Tablet
76
+ { name: 'iPad', use: { ...devices['iPad Pro 11'] } },
77
+ ],
78
+
79
+ webServer: {
80
+ command: 'bun run dev',
81
+ url: 'http://localhost:3000',
82
+ reuseExistingServer: !process.env['CI'],
83
+ },
84
+ });
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Page Object Model
90
+
91
+ ### Base Page
92
+
93
+ ```typescript
94
+ // tests/e2e/pages/base.page.ts
95
+ import { type Page, type Locator, expect } from '@playwright/test';
96
+
97
+ export abstract class BasePage {
98
+ protected readonly page: Page;
99
+
100
+ constructor(page: Page) {
101
+ this.page = page;
102
+ }
103
+
104
+ // Common elements
105
+ get loadingSpinner(): Locator {
106
+ return this.page.getByTestId('loading-spinner');
107
+ }
108
+
109
+ get errorMessage(): Locator {
110
+ return this.page.getByTestId('error-message');
111
+ }
112
+
113
+ get successMessage(): Locator {
114
+ return this.page.getByTestId('success-message');
115
+ }
116
+
117
+ // Common actions
118
+ async waitForLoad(): Promise<void> {
119
+ await this.loadingSpinner.waitFor({ state: 'hidden' });
120
+ }
121
+
122
+ async expectError(message: string): Promise<void> {
123
+ await expect(this.errorMessage).toContainText(message);
124
+ }
125
+
126
+ async expectSuccess(message: string): Promise<void> {
127
+ await expect(this.successMessage).toContainText(message);
128
+ }
129
+
130
+ // Navigation
131
+ async goto(path: string): Promise<void> {
132
+ await this.page.goto(path);
133
+ await this.waitForLoad();
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Login Page
139
+
140
+ ```typescript
141
+ // tests/e2e/pages/login.page.ts
142
+ import { type Page, type Locator } from '@playwright/test';
143
+ import { BasePage } from './base.page';
144
+
145
+ export class LoginPage extends BasePage {
146
+ readonly emailInput: Locator;
147
+ readonly passwordInput: Locator;
148
+ readonly submitButton: Locator;
149
+ readonly forgotPasswordLink: Locator;
150
+
151
+ constructor(page: Page) {
152
+ super(page);
153
+ this.emailInput = page.getByTestId('email-input');
154
+ this.passwordInput = page.getByTestId('password-input');
155
+ this.submitButton = page.getByTestId('submit-button');
156
+ this.forgotPasswordLink = page.getByRole('link', { name: /forgot/i });
157
+ }
158
+
159
+ async goto(): Promise<void> {
160
+ await super.goto('/auth/login');
161
+ }
162
+
163
+ async login(email: string, password: string): Promise<void> {
164
+ await this.emailInput.fill(email);
165
+ await this.passwordInput.fill(password);
166
+ await this.submitButton.click();
167
+ }
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Custom Fixtures
174
+
175
+ ### Auth Fixture
176
+
177
+ ```typescript
178
+ // tests/e2e/fixtures/auth.fixture.ts
179
+ import { test as base, type Page } from '@playwright/test';
180
+
181
+ export interface TestUser {
182
+ name: string;
183
+ email: string;
184
+ password: string;
185
+ }
186
+
187
+ export function generateTestUser(): TestUser {
188
+ const timestamp = Date.now();
189
+ const random = Math.random().toString(36).substring(7);
190
+ return {
191
+ name: `Test User ${timestamp}`,
192
+ email: `testuser_${timestamp}_${random}@test.com`,
193
+ password: 'TestPassword123!',
194
+ };
195
+ }
196
+
197
+ export async function registerUser(page: Page, user: TestUser): Promise<void> {
198
+ await page.goto('/auth/register');
199
+ await page.getByTestId('name-input').fill(user.name);
200
+ await page.getByTestId('email-input').fill(user.email);
201
+ await page.getByTestId('password-input').fill(user.password);
202
+ await page.getByTestId('confirm-password-input').fill(user.password);
203
+ await page.getByTestId('submit-button').click();
204
+ await page.waitForURL(/\/app/, { timeout: 10000 });
205
+ }
206
+
207
+ export async function loginUser(page: Page, user: TestUser): Promise<void> {
208
+ await page.goto('/auth/login');
209
+ await page.getByTestId('email-input').fill(user.email);
210
+ await page.getByTestId('password-input').fill(user.password);
211
+ await page.getByTestId('submit-button').click();
212
+ await page.waitForURL(/\/app/, { timeout: 10000 });
213
+ }
214
+ ```
215
+
216
+ ### Database Cleanup Fixture
217
+
218
+ ```typescript
219
+ // tests/e2e/fixtures/db.fixture.ts
220
+ import { test as base } from '@playwright/test';
221
+ import { MongoClient, type Db, type ObjectId } from 'mongodb';
222
+
223
+ type CleanupFixtures = {
224
+ db: Db;
225
+ createdIds: Map<string, ObjectId[]>;
226
+ trackCreated: (collection: string, id: ObjectId) => void;
227
+ };
228
+
229
+ export const test = base.extend<CleanupFixtures>({
230
+ db: async ({}, use) => {
231
+ const client = await MongoClient.connect(process.env['MONGODB_URI']!);
232
+ const db = client.db();
233
+ await use(db);
234
+ await client.close();
235
+ },
236
+
237
+ createdIds: async ({}, use) => {
238
+ await use(new Map());
239
+ },
240
+
241
+ trackCreated: async ({ createdIds }, use) => {
242
+ await use((collection: string, id: ObjectId) => {
243
+ const existing = createdIds.get(collection) || [];
244
+ existing.push(id);
245
+ createdIds.set(collection, existing);
246
+ });
247
+ },
248
+ });
249
+
250
+ // Auto-cleanup after each test
251
+ test.afterEach(async ({ db, createdIds }) => {
252
+ for (const [collection, ids] of createdIds.entries()) {
253
+ if (ids.length > 0) {
254
+ await db.collection(collection).deleteMany({ _id: { $in: ids } });
255
+ }
256
+ }
257
+ });
258
+
259
+ export { expect } from '@playwright/test';
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Test Patterns
265
+
266
+ ### Auth Flow Test
267
+
268
+ ```typescript
269
+ // tests/e2e/flows/auth.spec.ts
270
+ import { test, expect } from '../fixtures';
271
+ import { generateTestUser, registerUser, loginUser } from '../fixtures/auth.fixture';
272
+ import { LoginPage } from '../pages/login.page';
273
+
274
+ test.describe('Authentication Flow', () => {
275
+ test('complete registration and login journey', async ({ page, db, trackCreated }) => {
276
+ const user = generateTestUser();
277
+
278
+ // 1. Register
279
+ await registerUser(page, user);
280
+
281
+ // 2. Verify in database
282
+ const dbUser = await db.collection('users').findOne({ email: user.email });
283
+ expect(dbUser).toBeTruthy();
284
+ trackCreated('users', dbUser!._id);
285
+
286
+ // 3. Logout
287
+ await page.getByTestId('logout-button').click();
288
+ await expect(page).toHaveURL('/auth/login');
289
+
290
+ // 4. Login again
291
+ await loginUser(page, user);
292
+ await expect(page).toHaveURL(/\/app/);
293
+ });
294
+
295
+ test('shows error for invalid credentials', async ({ page }) => {
296
+ const loginPage = new LoginPage(page);
297
+ await loginPage.goto();
298
+
299
+ await loginPage.login('invalid@email.com', 'wrongpassword');
300
+
301
+ await loginPage.expectError('Invalid credentials');
302
+ });
303
+ });
304
+ ```
305
+
306
+ ### Multi-Viewport Test
307
+
308
+ ```typescript
309
+ // tests/e2e/flows/responsive.spec.ts
310
+ import { test, expect } from '@playwright/test';
311
+
312
+ const viewports = [
313
+ { name: 'mobile', width: 375, height: 667 },
314
+ { name: 'tablet', width: 768, height: 1024 },
315
+ { name: 'desktop', width: 1280, height: 800 },
316
+ ] as const;
317
+
318
+ for (const viewport of viewports) {
319
+ test.describe(`Responsive - ${viewport.name}`, () => {
320
+ test.use({ viewport: { width: viewport.width, height: viewport.height } });
321
+
322
+ test('navigation adapts to viewport', async ({ page }) => {
323
+ await page.goto('/');
324
+
325
+ if (viewport.width < 768) {
326
+ // Mobile: hamburger menu
327
+ await expect(page.getByTestId('hamburger-menu')).toBeVisible();
328
+ await expect(page.getByTestId('sidebar')).toBeHidden();
329
+
330
+ // Open mobile menu
331
+ await page.getByTestId('hamburger-menu').click();
332
+ await expect(page.getByTestId('mobile-nav')).toBeVisible();
333
+ } else {
334
+ // Desktop: sidebar visible
335
+ await expect(page.getByTestId('sidebar')).toBeVisible();
336
+ await expect(page.getByTestId('hamburger-menu')).toBeHidden();
337
+ }
338
+ });
339
+ });
340
+ }
341
+ ```
342
+
343
+ ### API Testing
344
+
345
+ ```typescript
346
+ // tests/e2e/api/endpoints.spec.ts
347
+ import { test, expect } from '@playwright/test';
348
+
349
+ test.describe('API Endpoints', () => {
350
+ test('requires authentication', async ({ request }) => {
351
+ const response = await request.get('/api/users');
352
+ expect(response.status()).toBe(401);
353
+ });
354
+
355
+ test('validates request body', async ({ request }) => {
356
+ const response = await request.post('/api/users', {
357
+ data: { email: 'invalid-email' },
358
+ });
359
+ expect(response.status()).toBe(400);
360
+
361
+ const body = await response.json();
362
+ expect(body.errors).toBeDefined();
363
+ });
364
+
365
+ test('creates user with valid data', async ({ request }) => {
366
+ const response = await request.post('/api/users', {
367
+ data: {
368
+ name: 'Test User',
369
+ email: 'test@example.com',
370
+ password: 'Password123!',
371
+ },
372
+ });
373
+ expect(response.status()).toBe(201);
374
+
375
+ const user = await response.json();
376
+ expect(user.id).toBeDefined();
377
+ expect(user.email).toBe('test@example.com');
378
+ });
379
+ });
380
+ ```
381
+
382
+ ---
383
+
384
+ ## Commands
385
+
386
+ ```bash
387
+ # Run all tests
388
+ bunx playwright test
389
+
390
+ # Run with UI
391
+ bunx playwright test --ui
392
+
393
+ # Run specific file
394
+ bunx playwright test auth.spec.ts
395
+
396
+ # Run specific project (viewport)
397
+ bunx playwright test --project="Mobile Chrome"
398
+
399
+ # Debug mode
400
+ bunx playwright test --debug
401
+
402
+ # Generate report
403
+ bunx playwright show-report
404
+
405
+ # Update snapshots
406
+ bunx playwright test --update-snapshots
407
+
408
+ # Trace viewer
409
+ bunx playwright show-trace trace.zip
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Agent Integration
415
+
416
+ This skill is used by:
417
+
418
+ - **playwright-e2e** agent
419
+ - **playwright-fixtures** agent
420
+ - **playwright-page-objects** agent
421
+ - **playwright-multi-viewport** agent
422
+ - **test-coverage** skill
423
+
424
+ ---
425
+
426
+ ## FORBIDDEN
427
+
428
+ 1. **Hardcoded test data** - Generate unique data
429
+ 2. **Skipped tests** - Never use `.skip()` or `.only()`
430
+ 3. **No cleanup** - Always clean up test data
431
+ 4. **Mocked auth** - Use real authentication
432
+ 5. **Single viewport** - Test all viewports
433
+
434
+ ---
435
+
436
+ ## Version
437
+
438
+ - **v1.0.0** - Initial implementation based on Playwright best practices