specweave 0.23.18 → 0.24.0

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 (167) hide show
  1. package/.claude-plugin/marketplace.json +93 -49
  2. package/CLAUDE.md +137 -4
  3. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts +89 -0
  4. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -0
  5. package/dist/src/cli/helpers/ado-area-path-mapper.js +213 -0
  6. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -0
  7. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts +29 -0
  8. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -0
  9. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +109 -0
  10. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -0
  11. package/dist/src/cli/helpers/issue-tracker/ado.d.ts +1 -0
  12. package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
  13. package/dist/src/cli/helpers/issue-tracker/ado.js +2 -0
  14. package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
  15. package/dist/src/cli/helpers/smart-filter.d.ts +83 -0
  16. package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -0
  17. package/dist/src/cli/helpers/smart-filter.js +265 -0
  18. package/dist/src/cli/helpers/smart-filter.js.map +1 -0
  19. package/dist/src/core/qa/quality-gate-decider.d.ts +1 -1
  20. package/dist/src/core/qa/quality-gate-decider.js +2 -2
  21. package/dist/src/core/qa/quality-gate-decider.js.map +1 -1
  22. package/dist/src/core/qa/risk-calculator.d.ts +2 -2
  23. package/dist/src/core/qa/risk-calculator.js +2 -2
  24. package/dist/src/core/validators/ac-presence-validator.d.ts +56 -0
  25. package/dist/src/core/validators/ac-presence-validator.d.ts.map +1 -0
  26. package/dist/src/core/validators/ac-presence-validator.js +149 -0
  27. package/dist/src/core/validators/ac-presence-validator.js.map +1 -0
  28. package/dist/src/integrations/ado/area-path-mapper.d.ts +137 -0
  29. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -0
  30. package/dist/src/integrations/ado/area-path-mapper.js +267 -0
  31. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -0
  32. package/dist/src/integrations/jira/filter-processor.d.ts +126 -0
  33. package/dist/src/integrations/jira/filter-processor.d.ts.map +1 -0
  34. package/dist/src/integrations/jira/filter-processor.js +207 -0
  35. package/dist/src/integrations/jira/filter-processor.js.map +1 -0
  36. package/dist/src/integrations/jira/jira-client.d.ts +13 -0
  37. package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
  38. package/dist/src/integrations/jira/jira-client.js +33 -0
  39. package/dist/src/integrations/jira/jira-client.js.map +1 -1
  40. package/dist/src/utils/ac-embedder.d.ts +63 -0
  41. package/dist/src/utils/ac-embedder.d.ts.map +1 -0
  42. package/dist/src/utils/ac-embedder.js +217 -0
  43. package/dist/src/utils/ac-embedder.js.map +1 -0
  44. package/dist/src/utils/env-manager.d.ts +86 -0
  45. package/dist/src/utils/env-manager.d.ts.map +1 -0
  46. package/dist/src/utils/env-manager.js +188 -0
  47. package/dist/src/utils/env-manager.js.map +1 -0
  48. package/package.json +1 -1
  49. package/plugins/specweave/.claude-plugin/plugin.json +1 -1
  50. package/plugins/specweave/agents/AGENTS-INDEX.md +1 -1
  51. package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +9 -9
  52. package/plugins/specweave/commands/specweave-do.md +37 -0
  53. package/plugins/specweave/commands/specweave-done.md +159 -0
  54. package/plugins/specweave/commands/specweave-embed-acs.md +446 -0
  55. package/plugins/specweave/commands/specweave-next.md +148 -3
  56. package/plugins/specweave/commands/specweave-qa.md +2 -2
  57. package/plugins/specweave/hooks/pre-increment-start.sh +168 -0
  58. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  59. package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
  60. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +331 -0
  61. package/plugins/specweave-alternatives/.claude-plugin/plugin.json +10 -0
  62. package/plugins/specweave-alternatives/commands/alternatives-analyze.md +336 -0
  63. package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +651 -0
  64. package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +420 -0
  65. package/plugins/specweave-alternatives/skills/spec-kit-expert/SKILL.md +487 -0
  66. package/plugins/specweave-backend/commands/api-scaffold.md +80 -0
  67. package/plugins/specweave-backend/commands/crud-generate.md +109 -0
  68. package/plugins/specweave-backend/commands/migration-generate.md +139 -0
  69. package/plugins/specweave-confluent/commands/connector-deploy.md +154 -0
  70. package/plugins/specweave-confluent/commands/ksqldb-query.md +179 -0
  71. package/plugins/specweave-confluent/commands/schema-register.md +123 -0
  72. package/plugins/specweave-core/.claude-plugin/plugin.json +21 -0
  73. package/plugins/specweave-core/commands/architecture-review.md +288 -0
  74. package/plugins/specweave-core/commands/code-review.md +213 -0
  75. package/plugins/specweave-core/commands/refactor-plan.md +249 -0
  76. package/plugins/specweave-core/skills/code-quality/SKILL.md +157 -0
  77. package/plugins/specweave-core/skills/design-patterns/SKILL.md +244 -0
  78. package/plugins/specweave-core/skills/software-architecture/SKILL.md +83 -0
  79. package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +22 -0
  80. package/plugins/specweave-cost-optimizer/commands/cost-analyze.md +360 -0
  81. package/plugins/specweave-cost-optimizer/commands/cost-optimize.md +480 -0
  82. package/plugins/specweave-cost-optimizer/skills/aws-cost-expert/SKILL.md +416 -0
  83. package/plugins/specweave-cost-optimizer/skills/cloud-pricing/SKILL.md +325 -0
  84. package/plugins/specweave-cost-optimizer/skills/cost-optimization/SKILL.md +337 -0
  85. package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
  86. package/plugins/specweave-diagrams/commands/diagrams-generate.md +168 -0
  87. package/plugins/specweave-docs/.claude-plugin/plugin.json +10 -0
  88. package/plugins/specweave-docs/commands/docs-generate.md +441 -0
  89. package/plugins/specweave-docs/commands/docs-init.md +334 -0
  90. package/plugins/specweave-docs/skills/docusaurus/SKILL.md +581 -0
  91. package/plugins/specweave-docs/skills/spec-driven-brainstorming/SKILL.md +689 -0
  92. package/plugins/specweave-docs/skills/technical-writing/SKILL.md +1039 -0
  93. package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
  94. package/plugins/specweave-figma/.claude-plugin/plugin.json +23 -0
  95. package/plugins/specweave-figma/commands/figma-import.md +690 -0
  96. package/plugins/specweave-figma/commands/figma-to-react.md +834 -0
  97. package/plugins/specweave-figma/commands/figma-tokens.md +815 -0
  98. package/plugins/specweave-frontend/.claude-plugin/plugin.json +21 -0
  99. package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +387 -0
  100. package/plugins/specweave-frontend/agents/frontend-architect/README.md +385 -0
  101. package/plugins/specweave-frontend/agents/frontend-architect/examples.md +590 -0
  102. package/plugins/specweave-frontend/agents/frontend-architect/templates/component-template.tsx +152 -0
  103. package/plugins/specweave-frontend/agents/frontend-architect/templates/hook-template.ts +311 -0
  104. package/plugins/specweave-frontend/agents/frontend-architect/templates/page-template.tsx +228 -0
  105. package/plugins/specweave-frontend/commands/component-generate.md +510 -0
  106. package/plugins/specweave-frontend/commands/design-system-init.md +494 -0
  107. package/plugins/specweave-frontend/commands/frontend-scaffold.md +207 -0
  108. package/plugins/specweave-frontend/commands/nextjs-setup.md +396 -0
  109. package/plugins/specweave-frontend/skills/design-system-architect/SKILL.md +278 -0
  110. package/plugins/specweave-frontend/skills/frontend/SKILL.md +420 -0
  111. package/plugins/specweave-frontend/skills/nextjs/SKILL.md +546 -0
  112. package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
  113. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +194 -0
  114. package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
  115. package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
  116. package/plugins/specweave-jira/commands/import-projects.js +183 -0
  117. package/plugins/specweave-jira/commands/import-projects.md +97 -0
  118. package/plugins/specweave-jira/commands/import-projects.ts +288 -0
  119. package/plugins/specweave-jira/commands/specweave-jira-import-projects.md +298 -0
  120. package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
  121. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
  122. package/plugins/specweave-kubernetes/commands/cluster-setup.md +262 -0
  123. package/plugins/specweave-kubernetes/commands/deployment-generate.md +242 -0
  124. package/plugins/specweave-kubernetes/commands/helm-scaffold.md +333 -0
  125. package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
  126. package/plugins/specweave-mobile/commands/app-scaffold.md +233 -0
  127. package/plugins/specweave-mobile/commands/build-config.md +256 -0
  128. package/plugins/specweave-mobile/commands/screen-generate.md +289 -0
  129. package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
  130. package/plugins/specweave-plugin-dev/.claude-plugin/plugin.json +13 -12
  131. package/plugins/specweave-plugin-dev/commands/plugin-create.md +333 -0
  132. package/plugins/specweave-plugin-dev/commands/plugin-publish.md +339 -0
  133. package/plugins/specweave-plugin-dev/commands/plugin-test.md +293 -0
  134. package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +162 -0
  135. package/plugins/specweave-plugin-dev/skills/marketplace-publishing/SKILL.md +263 -0
  136. package/plugins/specweave-plugin-dev/skills/plugin-development/SKILL.md +316 -0
  137. package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
  138. package/plugins/specweave-release/commands/specweave-release-npm.md +110 -0
  139. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +168 -0
  140. package/plugins/specweave-testing/.claude-plugin/plugin.json +21 -0
  141. package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +797 -0
  142. package/plugins/specweave-testing/agents/qa-engineer/README.md +443 -0
  143. package/plugins/specweave-testing/agents/qa-engineer/templates/playwright-e2e-test.ts +470 -0
  144. package/plugins/specweave-testing/agents/qa-engineer/templates/test-data-factory.ts +507 -0
  145. package/plugins/specweave-testing/agents/qa-engineer/templates/vitest-unit-test.ts +400 -0
  146. package/plugins/specweave-testing/agents/qa-engineer/test-strategies.md +726 -0
  147. package/plugins/specweave-testing/commands/e2e-setup.md +1081 -0
  148. package/plugins/specweave-testing/commands/test-coverage.md +979 -0
  149. package/plugins/specweave-testing/commands/test-generate.md +1156 -0
  150. package/plugins/specweave-testing/commands/test-init.md +409 -0
  151. package/plugins/specweave-testing/skills/e2e-playwright/SKILL.md +769 -0
  152. package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +934 -0
  153. package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +1011 -0
  154. package/plugins/specweave-tooling/.claude-plugin/plugin.json +22 -0
  155. package/plugins/specweave-tooling/commands/specweave-tooling-skill-create.md +691 -0
  156. package/plugins/specweave-tooling/commands/specweave-tooling-skill-package.md +751 -0
  157. package/plugins/specweave-tooling/commands/specweave-tooling-skill-validate.md +858 -0
  158. package/plugins/specweave-ui/.claude-plugin/plugin.json +10 -0
  159. package/plugins/specweave-ui/commands/ui-automate.md +199 -0
  160. package/plugins/specweave-ui/commands/ui-inspect.md +70 -0
  161. package/plugins/specweave-ui/skills/browser-automation/SKILL.md +314 -0
  162. package/plugins/specweave-ui/skills/ui-testing/SKILL.md +716 -0
  163. package/plugins/specweave-ui/skills/visual-regression/SKILL.md +728 -0
  164. package/plugins/specweave/commands/check-hooks.md +0 -257
  165. package/plugins/specweave/commands/specweave-archive-increments.md +0 -82
  166. package/plugins/specweave-plugin-dev/skills/plugin-expert/SKILL.md +0 -1231
  167. /package/plugins/specweave/{agents/code-reviewer.md → skills/code-reviewer/SKILL.md} +0 -0
@@ -0,0 +1,769 @@
1
+ ---
2
+ name: e2e-playwright
3
+ description: Comprehensive Playwright end-to-end testing expertise covering browser automation, cross-browser testing, visual regression, API testing, mobile emulation, accessibility testing, test architecture, page object models, fixtures, parallel execution, CI/CD integration, debugging strategies, and production-grade E2E test patterns. Activates for playwright, e2e testing, end-to-end testing, browser automation, cross-browser testing, visual testing, screenshot testing, API testing, mobile testing, accessibility testing, test fixtures, page object model, POM, test architecture, parallel testing, playwright config, trace viewer, codegen, test debugging, flaky tests, CI integration, playwright best practices.
4
+ ---
5
+
6
+ # E2E Playwright Testing Expert
7
+
8
+ ## Core Expertise
9
+
10
+ ### 1. Playwright Fundamentals
11
+ **Browser Automation**:
12
+ - Multi-browser support (Chromium, Firefox, WebKit)
13
+ - Context isolation and parallel execution
14
+ - Auto-waiting and actionability checks
15
+ - Network interception and mocking
16
+ - File downloads and uploads
17
+ - Geolocation and permissions
18
+ - Authentication state management
19
+
20
+ **Test Structure**:
21
+ ```typescript
22
+ import { test, expect } from '@playwright/test';
23
+
24
+ test.describe('Authentication Flow', () => {
25
+ test.beforeEach(async ({ page }) => {
26
+ await page.goto('/login');
27
+ });
28
+
29
+ test('should login successfully', async ({ page }) => {
30
+ await page.getByLabel('Email').fill('user@example.com');
31
+ await page.getByLabel('Password').fill('password123');
32
+ await page.getByRole('button', { name: 'Login' }).click();
33
+
34
+ await expect(page).toHaveURL('/dashboard');
35
+ await expect(page.getByText('Welcome back')).toBeVisible();
36
+ });
37
+
38
+ test('should show validation errors', async ({ page }) => {
39
+ await page.getByRole('button', { name: 'Login' }).click();
40
+
41
+ await expect(page.getByText('Email is required')).toBeVisible();
42
+ await expect(page.getByText('Password is required')).toBeVisible();
43
+ });
44
+ });
45
+ ```
46
+
47
+ ### 2. Page Object Model (POM)
48
+ **Pattern**: Encapsulate page interactions for maintainability
49
+
50
+ ```typescript
51
+ // pages/LoginPage.ts
52
+ import { Page, Locator } from '@playwright/test';
53
+
54
+ export class LoginPage {
55
+ readonly page: Page;
56
+ readonly emailInput: Locator;
57
+ readonly passwordInput: Locator;
58
+ readonly loginButton: Locator;
59
+ readonly errorMessage: Locator;
60
+
61
+ constructor(page: Page) {
62
+ this.page = page;
63
+ this.emailInput = page.getByLabel('Email');
64
+ this.passwordInput = page.getByLabel('Password');
65
+ this.loginButton = page.getByRole('button', { name: 'Login' });
66
+ this.errorMessage = page.getByRole('alert');
67
+ }
68
+
69
+ async goto() {
70
+ await this.page.goto('/login');
71
+ }
72
+
73
+ async login(email: string, password: string) {
74
+ await this.emailInput.fill(email);
75
+ await this.passwordInput.fill(password);
76
+ await this.loginButton.click();
77
+ }
78
+
79
+ async loginWithGoogle() {
80
+ await this.page.getByRole('button', { name: 'Continue with Google' }).click();
81
+ // Handle OAuth popup
82
+ }
83
+
84
+ async expectError(message: string) {
85
+ await expect(this.errorMessage).toContainText(message);
86
+ }
87
+ }
88
+
89
+ // Usage in tests
90
+ test('login flow', async ({ page }) => {
91
+ const loginPage = new LoginPage(page);
92
+ await loginPage.goto();
93
+ await loginPage.login('user@example.com', 'password123');
94
+ await expect(page).toHaveURL('/dashboard');
95
+ });
96
+ ```
97
+
98
+ ### 3. Test Fixtures & Custom Contexts
99
+ **Fixtures**: Reusable setup/teardown logic
100
+
101
+ ```typescript
102
+ // fixtures/auth.fixture.ts
103
+ import { test as base } from '@playwright/test';
104
+ import { LoginPage } from '../pages/LoginPage';
105
+
106
+ type AuthFixtures = {
107
+ authenticatedPage: Page;
108
+ loginPage: LoginPage;
109
+ };
110
+
111
+ export const test = base.extend<AuthFixtures>({
112
+ authenticatedPage: async ({ page }, use) => {
113
+ // Setup: Login before test
114
+ await page.goto('/login');
115
+ await page.getByLabel('Email').fill('user@example.com');
116
+ await page.getByLabel('Password').fill('password123');
117
+ await page.getByRole('button', { name: 'Login' }).click();
118
+ await page.waitForURL('/dashboard');
119
+
120
+ await use(page);
121
+
122
+ // Teardown: Logout after test
123
+ await page.getByRole('button', { name: 'Logout' }).click();
124
+ },
125
+
126
+ loginPage: async ({ page }, use) => {
127
+ const loginPage = new LoginPage(page);
128
+ await loginPage.goto();
129
+ await use(loginPage);
130
+ },
131
+ });
132
+
133
+ export { expect } from '@playwright/test';
134
+
135
+ // Usage
136
+ test('authenticated user can view profile', async ({ authenticatedPage }) => {
137
+ await authenticatedPage.goto('/profile');
138
+ await expect(authenticatedPage.getByText('Profile Settings')).toBeVisible();
139
+ });
140
+ ```
141
+
142
+ ### 4. API Testing with Playwright
143
+ **Pattern**: Test backend APIs alongside E2E flows
144
+
145
+ ```typescript
146
+ import { test, expect } from '@playwright/test';
147
+
148
+ test.describe('API Testing', () => {
149
+ test('should fetch user data', async ({ request }) => {
150
+ const response = await request.get('/api/users/123');
151
+
152
+ expect(response.ok()).toBeTruthy();
153
+ expect(response.status()).toBe(200);
154
+
155
+ const data = await response.json();
156
+ expect(data).toMatchObject({
157
+ id: 123,
158
+ email: expect.any(String),
159
+ name: expect.any(String),
160
+ });
161
+ });
162
+
163
+ test('should handle authentication', async ({ request }) => {
164
+ const response = await request.post('/api/auth/login', {
165
+ data: {
166
+ email: 'user@example.com',
167
+ password: 'password123',
168
+ },
169
+ });
170
+
171
+ expect(response.ok()).toBeTruthy();
172
+ const { token } = await response.json();
173
+ expect(token).toBeTruthy();
174
+
175
+ // Use token in subsequent requests
176
+ const profileResponse = await request.get('/api/profile', {
177
+ headers: {
178
+ Authorization: `Bearer ${token}`,
179
+ },
180
+ });
181
+
182
+ expect(profileResponse.ok()).toBeTruthy();
183
+ });
184
+
185
+ test('should mock API responses', async ({ page }) => {
186
+ await page.route('/api/users', async (route) => {
187
+ await route.fulfill({
188
+ status: 200,
189
+ body: JSON.stringify([
190
+ { id: 1, name: 'John Doe' },
191
+ { id: 2, name: 'Jane Smith' },
192
+ ]),
193
+ });
194
+ });
195
+
196
+ await page.goto('/users');
197
+ await expect(page.getByText('John Doe')).toBeVisible();
198
+ await expect(page.getByText('Jane Smith')).toBeVisible();
199
+ });
200
+ });
201
+ ```
202
+
203
+ ### 5. Visual Regression Testing
204
+ **Pattern**: Screenshot comparison for UI changes
205
+
206
+ ```typescript
207
+ import { test, expect } from '@playwright/test';
208
+
209
+ test.describe('Visual Regression', () => {
210
+ test('homepage matches baseline', async ({ page }) => {
211
+ await page.goto('/');
212
+ await expect(page).toHaveScreenshot('homepage.png', {
213
+ fullPage: true,
214
+ animations: 'disabled',
215
+ });
216
+ });
217
+
218
+ test('component states', async ({ page }) => {
219
+ await page.goto('/components');
220
+
221
+ // Default state
222
+ const button = page.getByRole('button', { name: 'Submit' });
223
+ await expect(button).toHaveScreenshot('button-default.png');
224
+
225
+ // Hover state
226
+ await button.hover();
227
+ await expect(button).toHaveScreenshot('button-hover.png');
228
+
229
+ // Disabled state
230
+ await page.evaluate(() => {
231
+ document.querySelector('button')?.setAttribute('disabled', 'true');
232
+ });
233
+ await expect(button).toHaveScreenshot('button-disabled.png');
234
+ });
235
+
236
+ test('responsive screenshots', async ({ page }) => {
237
+ await page.goto('/');
238
+
239
+ // Desktop
240
+ await page.setViewportSize({ width: 1920, height: 1080 });
241
+ await expect(page).toHaveScreenshot('homepage-desktop.png');
242
+
243
+ // Tablet
244
+ await page.setViewportSize({ width: 768, height: 1024 });
245
+ await expect(page).toHaveScreenshot('homepage-tablet.png');
246
+
247
+ // Mobile
248
+ await page.setViewportSize({ width: 375, height: 667 });
249
+ await expect(page).toHaveScreenshot('homepage-mobile.png');
250
+ });
251
+ });
252
+ ```
253
+
254
+ ### 6. Mobile Emulation & Device Testing
255
+ **Pattern**: Test responsive behavior and touch interactions
256
+
257
+ ```typescript
258
+ import { test, expect, devices } from '@playwright/test';
259
+
260
+ test.use(devices['iPhone 13 Pro']);
261
+
262
+ test.describe('Mobile Experience', () => {
263
+ test('should render mobile navigation', async ({ page }) => {
264
+ await page.goto('/');
265
+
266
+ // Mobile menu should be visible
267
+ await expect(page.getByRole('button', { name: 'Menu' })).toBeVisible();
268
+
269
+ // Desktop nav should be hidden
270
+ await expect(page.getByRole('navigation').first()).toBeHidden();
271
+ });
272
+
273
+ test('touch gestures', async ({ page }) => {
274
+ await page.goto('/gallery');
275
+
276
+ const image = page.getByRole('img').first();
277
+
278
+ // Swipe left
279
+ await image.dispatchEvent('touchstart', { touches: [{ clientX: 300, clientY: 200 }] });
280
+ await image.dispatchEvent('touchmove', { touches: [{ clientX: 100, clientY: 200 }] });
281
+ await image.dispatchEvent('touchend');
282
+
283
+ await expect(page.getByText('Next Image')).toBeVisible();
284
+ });
285
+
286
+ test('landscape orientation', async ({ page }) => {
287
+ await page.setViewportSize({ width: 812, height: 375 }); // iPhone landscape
288
+ await page.goto('/video');
289
+
290
+ await expect(page.locator('video')).toHaveCSS('width', '100%');
291
+ });
292
+ });
293
+
294
+ // Test across multiple devices
295
+ for (const deviceName of ['iPhone 13', 'Pixel 5', 'iPad Pro']) {
296
+ test.describe(`Device: ${deviceName}`, () => {
297
+ test.use(devices[deviceName]);
298
+
299
+ test('critical user flow', async ({ page }) => {
300
+ await page.goto('/');
301
+ // Test critical flow on each device
302
+ });
303
+ });
304
+ }
305
+ ```
306
+
307
+ ### 7. Accessibility Testing
308
+ **Pattern**: Automated accessibility checks
309
+
310
+ ```typescript
311
+ import { test, expect } from '@playwright/test';
312
+ import AxeBuilder from '@axe-core/playwright';
313
+
314
+ test.describe('Accessibility', () => {
315
+ test('should not have accessibility violations', async ({ page }) => {
316
+ await page.goto('/');
317
+
318
+ const accessibilityScanResults = await new AxeBuilder({ page })
319
+ .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
320
+ .analyze();
321
+
322
+ expect(accessibilityScanResults.violations).toEqual([]);
323
+ });
324
+
325
+ test('keyboard navigation', async ({ page }) => {
326
+ await page.goto('/form');
327
+
328
+ // Tab through form fields
329
+ await page.keyboard.press('Tab');
330
+ await expect(page.getByLabel('Email')).toBeFocused();
331
+
332
+ await page.keyboard.press('Tab');
333
+ await expect(page.getByLabel('Password')).toBeFocused();
334
+
335
+ await page.keyboard.press('Tab');
336
+ await expect(page.getByRole('button', { name: 'Submit' })).toBeFocused();
337
+
338
+ // Submit with Enter
339
+ await page.keyboard.press('Enter');
340
+ });
341
+
342
+ test('screen reader support', async ({ page }) => {
343
+ await page.goto('/');
344
+
345
+ // Check ARIA labels
346
+ await expect(page.getByRole('navigation', { name: 'Main' })).toBeVisible();
347
+ await expect(page.getByRole('main')).toHaveAttribute('aria-label', 'Main content');
348
+
349
+ // Check alt text
350
+ const images = page.getByRole('img');
351
+ for (const img of await images.all()) {
352
+ await expect(img).toHaveAttribute('alt');
353
+ }
354
+ });
355
+ });
356
+ ```
357
+
358
+ ### 8. Performance Testing
359
+ **Pattern**: Monitor performance metrics
360
+
361
+ ```typescript
362
+ import { test, expect } from '@playwright/test';
363
+
364
+ test.describe('Performance', () => {
365
+ test('page load performance', async ({ page }) => {
366
+ await page.goto('/');
367
+
368
+ const performanceMetrics = await page.evaluate(() => {
369
+ const perfData = window.performance.timing;
370
+ return {
371
+ loadTime: perfData.loadEventEnd - perfData.navigationStart,
372
+ domContentLoaded: perfData.domContentLoadedEventEnd - perfData.navigationStart,
373
+ firstPaint: performance.getEntriesByType('paint')[0]?.startTime || 0,
374
+ };
375
+ });
376
+
377
+ expect(performanceMetrics.loadTime).toBeLessThan(3000); // 3s max
378
+ expect(performanceMetrics.domContentLoaded).toBeLessThan(2000); // 2s max
379
+ });
380
+
381
+ test('Core Web Vitals', async ({ page }) => {
382
+ await page.goto('/');
383
+
384
+ const vitals = await page.evaluate(() => {
385
+ return new Promise((resolve) => {
386
+ new PerformanceObserver((list) => {
387
+ const entries = list.getEntries();
388
+ const lcp = entries.find(e => e.entryType === 'largest-contentful-paint');
389
+ const fid = entries.find(e => e.entryType === 'first-input');
390
+ const cls = entries.find(e => e.entryType === 'layout-shift');
391
+
392
+ resolve({ lcp: lcp?.startTime, fid: fid?.processingStart, cls: cls?.value });
393
+ }).observe({ entryTypes: ['largest-contentful-paint', 'first-input', 'layout-shift'] });
394
+ });
395
+ });
396
+
397
+ expect(vitals.lcp).toBeLessThan(2500); // Good LCP
398
+ expect(vitals.fid).toBeLessThan(100); // Good FID
399
+ expect(vitals.cls).toBeLessThan(0.1); // Good CLS
400
+ });
401
+ });
402
+ ```
403
+
404
+ ### 9. Advanced Configuration
405
+ **playwright.config.ts**:
406
+
407
+ ```typescript
408
+ import { defineConfig, devices } from '@playwright/test';
409
+
410
+ export default defineConfig({
411
+ testDir: './e2e',
412
+ fullyParallel: true,
413
+ forbidOnly: !!process.env.CI,
414
+ retries: process.env.CI ? 2 : 0,
415
+ workers: process.env.CI ? 1 : undefined,
416
+ reporter: [
417
+ ['html'],
418
+ ['junit', { outputFile: 'test-results/junit.xml' }],
419
+ ['json', { outputFile: 'test-results/results.json' }],
420
+ ],
421
+ use: {
422
+ baseURL: process.env.BASE_URL || 'http://localhost:3000',
423
+ trace: 'on-first-retry',
424
+ screenshot: 'only-on-failure',
425
+ video: 'retain-on-failure',
426
+ },
427
+ projects: [
428
+ // Desktop browsers
429
+ {
430
+ name: 'chromium',
431
+ use: { ...devices['Desktop Chrome'] },
432
+ },
433
+ {
434
+ name: 'firefox',
435
+ use: { ...devices['Desktop Firefox'] },
436
+ },
437
+ {
438
+ name: 'webkit',
439
+ use: { ...devices['Desktop Safari'] },
440
+ },
441
+ // Mobile browsers
442
+ {
443
+ name: 'Mobile Chrome',
444
+ use: { ...devices['Pixel 5'] },
445
+ },
446
+ {
447
+ name: 'Mobile Safari',
448
+ use: { ...devices['iPhone 13'] },
449
+ },
450
+ // Tablet browsers
451
+ {
452
+ name: 'iPad',
453
+ use: { ...devices['iPad Pro'] },
454
+ },
455
+ ],
456
+ webServer: {
457
+ command: 'npm run dev',
458
+ url: 'http://localhost:3000',
459
+ reuseExistingServer: !process.env.CI,
460
+ timeout: 120 * 1000,
461
+ },
462
+ });
463
+ ```
464
+
465
+ ### 10. CI/CD Integration
466
+ **GitHub Actions**:
467
+
468
+ ```yaml
469
+ name: E2E Tests
470
+ on: [push, pull_request]
471
+
472
+ jobs:
473
+ test:
474
+ runs-on: ubuntu-latest
475
+ steps:
476
+ - uses: actions/checkout@v3
477
+ - uses: actions/setup-node@v3
478
+ with:
479
+ node-version: 18
480
+
481
+ - name: Install dependencies
482
+ run: npm ci
483
+
484
+ - name: Install Playwright browsers
485
+ run: npx playwright install --with-deps
486
+
487
+ - name: Run E2E tests
488
+ run: npm run test:e2e
489
+ env:
490
+ BASE_URL: https://staging.example.com
491
+
492
+ - name: Upload test results
493
+ if: always()
494
+ uses: actions/upload-artifact@v3
495
+ with:
496
+ name: playwright-report
497
+ path: playwright-report/
498
+ retention-days: 30
499
+
500
+ - name: Upload traces
501
+ if: failure()
502
+ uses: actions/upload-artifact@v3
503
+ with:
504
+ name: playwright-traces
505
+ path: test-results/
506
+ ```
507
+
508
+ ### 11. Debugging Strategies
509
+ **Tools & Techniques**:
510
+
511
+ ```typescript
512
+ // 1. Debug mode (headed browser + slow motion)
513
+ test('debug example', async ({ page }) => {
514
+ await page.goto('/');
515
+ await page.pause(); // Pauses execution, opens inspector
516
+ });
517
+
518
+ // 2. Console logs
519
+ test('capture console', async ({ page }) => {
520
+ page.on('console', msg => console.log(`Browser: ${msg.text()}`));
521
+ await page.goto('/');
522
+ });
523
+
524
+ // 3. Network inspection
525
+ test('inspect network', async ({ page }) => {
526
+ page.on('request', request => console.log('Request:', request.url()));
527
+ page.on('response', response => console.log('Response:', response.status()));
528
+ await page.goto('/');
529
+ });
530
+
531
+ // 4. Screenshots on failure
532
+ test.afterEach(async ({ page }, testInfo) => {
533
+ if (testInfo.status !== testInfo.expectedStatus) {
534
+ await page.screenshot({
535
+ path: `screenshots/${testInfo.title}.png`,
536
+ fullPage: true
537
+ });
538
+ }
539
+ });
540
+
541
+ // 5. Trace viewer
542
+ // Run: npx playwright test --trace on
543
+ // View: npx playwright show-trace trace.zip
544
+ ```
545
+
546
+ **Common Debugging Commands**:
547
+ ```bash
548
+ # Run in headed mode (see browser)
549
+ npx playwright test --headed
550
+
551
+ # Run with UI mode (interactive debugging)
552
+ npx playwright test --ui
553
+
554
+ # Run single test
555
+ npx playwright test tests/login.spec.ts
556
+
557
+ # Debug specific test
558
+ npx playwright test tests/login.spec.ts --debug
559
+
560
+ # Generate test code
561
+ npx playwright codegen http://localhost:3000
562
+ ```
563
+
564
+ ### 12. Handling Flaky Tests
565
+ **Patterns for Reliability**:
566
+
567
+ ```typescript
568
+ // 1. Proper waiting strategies
569
+ test('wait for content', async ({ page }) => {
570
+ await page.goto('/');
571
+
572
+ // ❌ BAD: Fixed delays
573
+ // await page.waitForTimeout(5000);
574
+
575
+ // ✅ GOOD: Wait for specific conditions
576
+ await page.waitForLoadState('networkidle');
577
+ await page.waitForSelector('.content', { state: 'visible' });
578
+ await page.getByText('Welcome').waitFor();
579
+ });
580
+
581
+ // 2. Retry logic for external dependencies
582
+ test('api with retry', async ({ page }) => {
583
+ await page.goto('/');
584
+
585
+ let retries = 3;
586
+ while (retries > 0) {
587
+ try {
588
+ const response = await page.waitForResponse(
589
+ response => response.url().includes('/api/data') && response.ok(),
590
+ { timeout: 5000 }
591
+ );
592
+ expect(response.ok()).toBeTruthy();
593
+ break;
594
+ } catch (error) {
595
+ retries--;
596
+ if (retries === 0) throw error;
597
+ await page.reload();
598
+ }
599
+ }
600
+ });
601
+
602
+ // 3. Test isolation
603
+ test.describe.configure({ mode: 'parallel' });
604
+
605
+ test.beforeEach(async ({ page }) => {
606
+ // Clear state before each test
607
+ await page.context().clearCookies();
608
+ await page.context().clearPermissions();
609
+ });
610
+
611
+ // 4. Deterministic test data
612
+ test('use fixtures', async ({ page }) => {
613
+ // Seed database with known data
614
+ await page.request.post('/api/test/seed', {
615
+ data: { userId: 'test-123', email: 'test@example.com' }
616
+ });
617
+
618
+ await page.goto('/users/test-123');
619
+ await expect(page.getByText('test@example.com')).toBeVisible();
620
+
621
+ // Cleanup
622
+ await page.request.delete('/api/test/users/test-123');
623
+ });
624
+ ```
625
+
626
+ ## Best Practices
627
+
628
+ ### Test Organization
629
+ ```
630
+ e2e/
631
+ ├── fixtures/
632
+ │ ├── auth.fixture.ts
633
+ │ ├── data.fixture.ts
634
+ │ └── mock.fixture.ts
635
+ ├── pages/
636
+ │ ├── LoginPage.ts
637
+ │ ├── DashboardPage.ts
638
+ │ └── ProfilePage.ts
639
+ ├── tests/
640
+ │ ├── auth/
641
+ │ │ ├── login.spec.ts
642
+ │ │ ├── signup.spec.ts
643
+ │ │ └── logout.spec.ts
644
+ │ ├── user/
645
+ │ │ ├── profile.spec.ts
646
+ │ │ └── settings.spec.ts
647
+ │ └── api/
648
+ │ ├── users.spec.ts
649
+ │ └── posts.spec.ts
650
+ └── playwright.config.ts
651
+ ```
652
+
653
+ ### Naming Conventions
654
+ - Test files: `*.spec.ts` or `*.test.ts`
655
+ - Page objects: `*Page.ts`
656
+ - Fixtures: `*.fixture.ts`
657
+ - Descriptive test names: `should allow user to login with valid credentials`
658
+
659
+ ### Performance Optimization
660
+ 1. **Parallel execution**: Run tests in parallel across workers
661
+ 2. **Test sharding**: Split tests across CI machines
662
+ 3. **Selective testing**: Use tags/annotations for smoke tests
663
+ 4. **Reuse authentication**: Save auth state, reuse across tests
664
+ 5. **Mock external APIs**: Reduce network latency and flakiness
665
+
666
+ ### Security Considerations
667
+ - Never commit credentials in test files
668
+ - Use environment variables for sensitive data
669
+ - Isolate test data from production
670
+ - Clear cookies/storage between tests
671
+ - Use disposable test accounts
672
+
673
+ ## Common Patterns
674
+
675
+ ### Authentication State Reuse
676
+ ```typescript
677
+ // global-setup.ts
678
+ import { chromium, FullConfig } from '@playwright/test';
679
+
680
+ async function globalSetup(config: FullConfig) {
681
+ const browser = await chromium.launch();
682
+ const page = await browser.newPage();
683
+ await page.goto('http://localhost:3000/login');
684
+ await page.getByLabel('Email').fill('user@example.com');
685
+ await page.getByLabel('Password').fill('password123');
686
+ await page.getByRole('button', { name: 'Login' }).click();
687
+ await page.waitForURL('http://localhost:3000/dashboard');
688
+
689
+ // Save signed-in state
690
+ await page.context().storageState({ path: 'auth.json' });
691
+ await browser.close();
692
+ }
693
+
694
+ export default globalSetup;
695
+
696
+ // playwright.config.ts
697
+ export default defineConfig({
698
+ globalSetup: require.resolve('./global-setup'),
699
+ use: {
700
+ storageState: 'auth.json',
701
+ },
702
+ });
703
+ ```
704
+
705
+ ### Multi-Tab/Window Testing
706
+ ```typescript
707
+ test('open in new tab', async ({ context }) => {
708
+ const page = await context.newPage();
709
+ await page.goto('/');
710
+
711
+ const [newPage] = await Promise.all([
712
+ context.waitForEvent('page'),
713
+ page.getByRole('link', { name: 'Open in new tab' }).click()
714
+ ]);
715
+
716
+ await newPage.waitForLoadState();
717
+ await expect(newPage).toHaveURL('/new-page');
718
+ });
719
+ ```
720
+
721
+ ### File Upload/Download
722
+ ```typescript
723
+ test('upload file', async ({ page }) => {
724
+ await page.goto('/upload');
725
+
726
+ const fileChooserPromise = page.waitForEvent('filechooser');
727
+ await page.getByRole('button', { name: 'Upload' }).click();
728
+ const fileChooser = await fileChooserPromise;
729
+ await fileChooser.setFiles('path/to/file.pdf');
730
+
731
+ await expect(page.getByText('file.pdf uploaded')).toBeVisible();
732
+ });
733
+
734
+ test('download file', async ({ page }) => {
735
+ await page.goto('/downloads');
736
+
737
+ const downloadPromise = page.waitForEvent('download');
738
+ await page.getByRole('link', { name: 'Download Report' }).click();
739
+ const download = await downloadPromise;
740
+
741
+ await download.saveAs(`/tmp/${download.suggestedFilename()}`);
742
+ expect(download.suggestedFilename()).toBe('report.pdf');
743
+ });
744
+ ```
745
+
746
+ ## Troubleshooting
747
+
748
+ ### Common Issues
749
+ 1. **Timeouts**: Increase timeout, use proper wait strategies
750
+ 2. **Flaky selectors**: Use stable locators (roles, labels, test IDs)
751
+ 3. **Race conditions**: Wait for network idle, use explicit waits
752
+ 4. **Authentication failures**: Clear cookies, check auth state
753
+ 5. **Screenshot mismatches**: Update baselines, disable animations
754
+
755
+ ### Debug Checklist
756
+ - [ ] Test passes locally in headed mode?
757
+ - [ ] Network requests succeed (check DevTools)?
758
+ - [ ] Selectors are stable and unique?
759
+ - [ ] Proper waits before assertions?
760
+ - [ ] Test data is deterministic?
761
+ - [ ] No race conditions with async operations?
762
+ - [ ] Traces/screenshots captured on failure?
763
+
764
+ ## Resources
765
+ - **Official Docs**: https://playwright.dev
766
+ - **API Reference**: https://playwright.dev/docs/api/class-playwright
767
+ - **Best Practices**: https://playwright.dev/docs/best-practices
768
+ - **Examples**: https://github.com/microsoft/playwright/tree/main/examples
769
+ - **Community**: https://github.com/microsoft/playwright/discussions