specweave 0.23.18 → 0.24.1

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 (174) hide show
  1. package/.claude-plugin/marketplace.json +144 -45
  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/repo-structure/repo-structure-manager.d.ts.map +1 -1
  25. package/dist/src/core/repo-structure/repo-structure-manager.js +76 -43
  26. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  27. package/dist/src/core/validators/ac-presence-validator.d.ts +56 -0
  28. package/dist/src/core/validators/ac-presence-validator.d.ts.map +1 -0
  29. package/dist/src/core/validators/ac-presence-validator.js +149 -0
  30. package/dist/src/core/validators/ac-presence-validator.js.map +1 -0
  31. package/dist/src/integrations/ado/area-path-mapper.d.ts +137 -0
  32. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -0
  33. package/dist/src/integrations/ado/area-path-mapper.js +267 -0
  34. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -0
  35. package/dist/src/integrations/jira/filter-processor.d.ts +126 -0
  36. package/dist/src/integrations/jira/filter-processor.d.ts.map +1 -0
  37. package/dist/src/integrations/jira/filter-processor.js +207 -0
  38. package/dist/src/integrations/jira/filter-processor.js.map +1 -0
  39. package/dist/src/integrations/jira/jira-client.d.ts +13 -0
  40. package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
  41. package/dist/src/integrations/jira/jira-client.js +33 -0
  42. package/dist/src/integrations/jira/jira-client.js.map +1 -1
  43. package/dist/src/utils/ac-embedder.d.ts +63 -0
  44. package/dist/src/utils/ac-embedder.d.ts.map +1 -0
  45. package/dist/src/utils/ac-embedder.js +217 -0
  46. package/dist/src/utils/ac-embedder.js.map +1 -0
  47. package/dist/src/utils/env-manager.d.ts +86 -0
  48. package/dist/src/utils/env-manager.d.ts.map +1 -0
  49. package/dist/src/utils/env-manager.js +188 -0
  50. package/dist/src/utils/env-manager.js.map +1 -0
  51. package/package.json +1 -1
  52. package/plugins/specweave/.claude-plugin/plugin.json +1 -1
  53. package/plugins/specweave/agents/AGENTS-INDEX.md +1 -1
  54. package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +9 -9
  55. package/plugins/specweave/commands/specweave-do.md +37 -0
  56. package/plugins/specweave/commands/specweave-done.md +159 -0
  57. package/plugins/specweave/commands/specweave-embed-acs.md +446 -0
  58. package/plugins/specweave/commands/specweave-next.md +148 -3
  59. package/plugins/specweave/commands/specweave-qa.md +2 -2
  60. package/plugins/specweave/hooks/pre-increment-start.sh +168 -0
  61. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  62. package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
  63. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +331 -0
  64. package/plugins/specweave-alternatives/.claude-plugin/plugin.json +10 -0
  65. package/plugins/specweave-alternatives/commands/alternatives-analyze.md +336 -0
  66. package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +651 -0
  67. package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +420 -0
  68. package/plugins/specweave-alternatives/skills/spec-kit-expert/SKILL.md +487 -0
  69. package/plugins/specweave-backend/commands/api-scaffold.md +80 -0
  70. package/plugins/specweave-backend/commands/crud-generate.md +109 -0
  71. package/plugins/specweave-backend/commands/migration-generate.md +139 -0
  72. package/plugins/specweave-confluent/commands/connector-deploy.md +154 -0
  73. package/plugins/specweave-confluent/commands/ksqldb-query.md +179 -0
  74. package/plugins/specweave-confluent/commands/schema-register.md +123 -0
  75. package/plugins/specweave-core/.claude-plugin/plugin.json +21 -0
  76. package/plugins/specweave-core/commands/architecture-review.md +288 -0
  77. package/plugins/specweave-core/commands/code-review.md +213 -0
  78. package/plugins/specweave-core/commands/refactor-plan.md +249 -0
  79. package/plugins/specweave-core/skills/code-quality/SKILL.md +157 -0
  80. package/plugins/specweave-core/skills/design-patterns/SKILL.md +244 -0
  81. package/plugins/specweave-core/skills/software-architecture/SKILL.md +83 -0
  82. package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +22 -0
  83. package/plugins/specweave-cost-optimizer/commands/cost-analyze.md +360 -0
  84. package/plugins/specweave-cost-optimizer/commands/cost-optimize.md +480 -0
  85. package/plugins/specweave-cost-optimizer/skills/aws-cost-expert/SKILL.md +416 -0
  86. package/plugins/specweave-cost-optimizer/skills/cloud-pricing/SKILL.md +325 -0
  87. package/plugins/specweave-cost-optimizer/skills/cost-optimization/SKILL.md +337 -0
  88. package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
  89. package/plugins/specweave-diagrams/commands/diagrams-generate.md +168 -0
  90. package/plugins/specweave-docs/.claude-plugin/plugin.json +10 -0
  91. package/plugins/specweave-docs/commands/docs-generate.md +441 -0
  92. package/plugins/specweave-docs/commands/docs-init.md +334 -0
  93. package/plugins/specweave-docs/skills/docusaurus/SKILL.md +581 -0
  94. package/plugins/specweave-docs/skills/spec-driven-brainstorming/SKILL.md +689 -0
  95. package/plugins/specweave-docs/skills/technical-writing/SKILL.md +1039 -0
  96. package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
  97. package/plugins/specweave-figma/.claude-plugin/plugin.json +23 -0
  98. package/plugins/specweave-figma/commands/figma-import.md +690 -0
  99. package/plugins/specweave-figma/commands/figma-to-react.md +834 -0
  100. package/plugins/specweave-figma/commands/figma-tokens.md +815 -0
  101. package/plugins/specweave-frontend/.claude-plugin/plugin.json +21 -0
  102. package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +408 -0
  103. package/plugins/specweave-frontend/agents/frontend-architect/README.md +385 -0
  104. package/plugins/specweave-frontend/agents/frontend-architect/examples.md +590 -0
  105. package/plugins/specweave-frontend/agents/frontend-architect/templates/component-template.tsx +152 -0
  106. package/plugins/specweave-frontend/agents/frontend-architect/templates/hook-template.ts +311 -0
  107. package/plugins/specweave-frontend/agents/frontend-architect/templates/page-template.tsx +228 -0
  108. package/plugins/specweave-frontend/commands/component-generate.md +510 -0
  109. package/plugins/specweave-frontend/commands/design-system-init.md +494 -0
  110. package/plugins/specweave-frontend/commands/frontend-scaffold.md +207 -0
  111. package/plugins/specweave-frontend/commands/nextjs-setup.md +396 -0
  112. package/plugins/specweave-frontend/skills/design-system-architect/SKILL.md +278 -0
  113. package/plugins/specweave-frontend/skills/frontend/SKILL.md +420 -0
  114. package/plugins/specweave-frontend/skills/nextjs/SKILL.md +546 -0
  115. package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
  116. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +212 -0
  117. package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
  118. package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
  119. package/plugins/specweave-jira/commands/import-projects.js +183 -0
  120. package/plugins/specweave-jira/commands/import-projects.md +97 -0
  121. package/plugins/specweave-jira/commands/import-projects.ts +288 -0
  122. package/plugins/specweave-jira/commands/specweave-jira-import-projects.md +298 -0
  123. package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
  124. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
  125. package/plugins/specweave-kubernetes/commands/cluster-setup.md +262 -0
  126. package/plugins/specweave-kubernetes/commands/deployment-generate.md +242 -0
  127. package/plugins/specweave-kubernetes/commands/helm-scaffold.md +333 -0
  128. package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
  129. package/plugins/specweave-mobile/commands/app-scaffold.md +233 -0
  130. package/plugins/specweave-mobile/commands/build-config.md +256 -0
  131. package/plugins/specweave-mobile/commands/screen-generate.md +289 -0
  132. package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
  133. package/plugins/specweave-payments/commands/stripe-setup.md +931 -0
  134. package/plugins/specweave-payments/commands/subscription-flow.md +1193 -0
  135. package/plugins/specweave-payments/commands/subscription-manage.md +386 -0
  136. package/plugins/specweave-payments/commands/webhook-setup.md +295 -0
  137. package/plugins/specweave-plugin-dev/.claude-plugin/plugin.json +13 -12
  138. package/plugins/specweave-plugin-dev/commands/plugin-create.md +333 -0
  139. package/plugins/specweave-plugin-dev/commands/plugin-publish.md +339 -0
  140. package/plugins/specweave-plugin-dev/commands/plugin-test.md +293 -0
  141. package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +162 -0
  142. package/plugins/specweave-plugin-dev/skills/marketplace-publishing/SKILL.md +263 -0
  143. package/plugins/specweave-plugin-dev/skills/plugin-development/SKILL.md +316 -0
  144. package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
  145. package/plugins/specweave-release/commands/specweave-release-npm.md +110 -0
  146. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +168 -0
  147. package/plugins/specweave-testing/.claude-plugin/plugin.json +21 -0
  148. package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +818 -0
  149. package/plugins/specweave-testing/agents/qa-engineer/README.md +443 -0
  150. package/plugins/specweave-testing/agents/qa-engineer/templates/playwright-e2e-test.ts +470 -0
  151. package/plugins/specweave-testing/agents/qa-engineer/templates/test-data-factory.ts +507 -0
  152. package/plugins/specweave-testing/agents/qa-engineer/templates/vitest-unit-test.ts +400 -0
  153. package/plugins/specweave-testing/agents/qa-engineer/test-strategies.md +726 -0
  154. package/plugins/specweave-testing/commands/e2e-setup.md +1081 -0
  155. package/plugins/specweave-testing/commands/test-coverage.md +979 -0
  156. package/plugins/specweave-testing/commands/test-generate.md +1156 -0
  157. package/plugins/specweave-testing/commands/test-init.md +409 -0
  158. package/plugins/specweave-testing/skills/e2e-playwright/SKILL.md +769 -0
  159. package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +934 -0
  160. package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +1011 -0
  161. package/plugins/specweave-tooling/.claude-plugin/plugin.json +22 -0
  162. package/plugins/specweave-tooling/commands/specweave-tooling-skill-create.md +691 -0
  163. package/plugins/specweave-tooling/commands/specweave-tooling-skill-package.md +751 -0
  164. package/plugins/specweave-tooling/commands/specweave-tooling-skill-validate.md +858 -0
  165. package/plugins/specweave-ui/.claude-plugin/plugin.json +10 -0
  166. package/plugins/specweave-ui/commands/ui-automate.md +199 -0
  167. package/plugins/specweave-ui/commands/ui-inspect.md +70 -0
  168. package/plugins/specweave-ui/skills/browser-automation/SKILL.md +314 -0
  169. package/plugins/specweave-ui/skills/ui-testing/SKILL.md +716 -0
  170. package/plugins/specweave-ui/skills/visual-regression/SKILL.md +728 -0
  171. package/plugins/specweave/commands/check-hooks.md +0 -257
  172. package/plugins/specweave/commands/specweave-archive-increments.md +0 -82
  173. package/plugins/specweave-plugin-dev/skills/plugin-expert/SKILL.md +0 -1231
  174. /package/plugins/specweave/{agents/code-reviewer.md → skills/code-reviewer/SKILL.md} +0 -0
@@ -0,0 +1,716 @@
1
+ ---
2
+ name: ui-testing
3
+ description: UI and end-to-end testing expert using Playwright Test, Cypress, Testing Library, and component testing frameworks. Covers test strategies, page object models, accessibility testing, CI integration, and test flakiness mitigation. Activates for UI testing, E2E testing, Playwright Test, Cypress, Testing Library, component tests, integration tests, accessibility testing, test flakiness, page object model, CI testing.
4
+ ---
5
+
6
+ # UI Testing Skill
7
+
8
+ Expert in UI and end-to-end (E2E) testing using modern frameworks like Playwright Test, Cypress, and Testing Library. Specializes in writing reliable, maintainable tests that catch bugs before production.
9
+
10
+ ## Core Testing Frameworks
11
+
12
+ ### 1. Playwright Test (Recommended for E2E)
13
+
14
+ **Why Playwright?**
15
+ - Multi-browser support (Chromium, Firefox, WebKit)
16
+ - Auto-wait (no manual `waitFor` needed)
17
+ - Fast parallel execution
18
+ - Built-in assertions and fixtures
19
+ - Network interception and mocking
20
+
21
+ #### Basic Test Structure
22
+
23
+ ```typescript
24
+ import { test, expect } from '@playwright/test';
25
+
26
+ test.describe('User Authentication', () => {
27
+ test('should login with valid credentials', async ({ page }) => {
28
+ // Navigate
29
+ await page.goto('https://example.com/login');
30
+
31
+ // Interact
32
+ await page.fill('input[name="email"]', 'user@example.com');
33
+ await page.fill('input[name="password"]', 'SecurePass123!');
34
+ await page.click('button[type="submit"]');
35
+
36
+ // Assert
37
+ await expect(page).toHaveURL('https://example.com/dashboard');
38
+ await expect(page.locator('h1')).toHaveText('Welcome, User');
39
+ });
40
+
41
+ test('should show error with invalid credentials', async ({ page }) => {
42
+ await page.goto('https://example.com/login');
43
+
44
+ await page.fill('input[name="email"]', 'wrong@example.com');
45
+ await page.fill('input[name="password"]', 'WrongPass');
46
+ await page.click('button[type="submit"]');
47
+
48
+ // Wait for error message
49
+ const errorMessage = page.locator('.error-message');
50
+ await expect(errorMessage).toBeVisible();
51
+ await expect(errorMessage).toHaveText('Invalid credentials');
52
+ });
53
+ });
54
+ ```
55
+
56
+ #### Fixtures (Reusable Setup)
57
+
58
+ ```typescript
59
+ // fixtures.ts
60
+ import { test as base } from '@playwright/test';
61
+
62
+ type Fixtures = {
63
+ authenticatedPage: Page;
64
+ };
65
+
66
+ export const test = base.extend<Fixtures>({
67
+ authenticatedPage: async ({ page }, use) => {
68
+ // Login before each test
69
+ await page.goto('https://example.com/login');
70
+ await page.fill('input[name="email"]', 'user@example.com');
71
+ await page.fill('input[name="password"]', 'SecurePass123!');
72
+ await page.click('button[type="submit"]');
73
+ await page.waitForURL('**/dashboard');
74
+
75
+ // Use the authenticated page
76
+ await use(page);
77
+
78
+ // Cleanup (logout)
79
+ await page.click('[data-testid="logout"]');
80
+ },
81
+ });
82
+
83
+ // tests/dashboard.spec.ts
84
+ import { test, expect } from './fixtures';
85
+
86
+ test('should display user dashboard', async ({ authenticatedPage }) => {
87
+ // Already logged in via fixture
88
+ await expect(authenticatedPage.locator('h1')).toHaveText('Dashboard');
89
+ });
90
+ ```
91
+
92
+ #### Page Object Model (POM)
93
+
94
+ ```typescript
95
+ // pages/LoginPage.ts
96
+ export class LoginPage {
97
+ constructor(private page: Page) {}
98
+
99
+ async goto() {
100
+ await this.page.goto('https://example.com/login');
101
+ }
102
+
103
+ async login(email: string, password: string) {
104
+ await this.page.fill('input[name="email"]', email);
105
+ await this.page.fill('input[name="password"]', password);
106
+ await this.page.click('button[type="submit"]');
107
+ }
108
+
109
+ async getErrorMessage() {
110
+ const errorElement = this.page.locator('.error-message');
111
+ return errorElement.textContent();
112
+ }
113
+
114
+ async isLoginButtonDisabled() {
115
+ return this.page.locator('button[type="submit"]').isDisabled();
116
+ }
117
+ }
118
+
119
+ // tests/login.spec.ts
120
+ import { LoginPage } from '../pages/LoginPage';
121
+
122
+ test('login with POM', async ({ page }) => {
123
+ const loginPage = new LoginPage(page);
124
+
125
+ await loginPage.goto();
126
+ await loginPage.login('user@example.com', 'SecurePass123!');
127
+
128
+ await expect(page).toHaveURL('**/dashboard');
129
+ });
130
+ ```
131
+
132
+ ### 2. Cypress (Alternative for E2E)
133
+
134
+ **Why Cypress?**
135
+ - Developer-friendly API
136
+ - Real-time reloading
137
+ - Time-travel debugging
138
+ - Screenshot/video recording
139
+ - Stubbing and mocking built-in
140
+
141
+ #### Basic Test
142
+
143
+ ```javascript
144
+ describe('User Authentication', () => {
145
+ it('should login with valid credentials', () => {
146
+ cy.visit('/login');
147
+
148
+ cy.get('input[name="email"]').type('user@example.com');
149
+ cy.get('input[name="password"]').type('SecurePass123!');
150
+ cy.get('button[type="submit"]').click();
151
+
152
+ cy.url().should('include', '/dashboard');
153
+ cy.get('h1').should('have.text', 'Welcome, User');
154
+ });
155
+
156
+ it('should show error with invalid credentials', () => {
157
+ cy.visit('/login');
158
+
159
+ cy.get('input[name="email"]').type('wrong@example.com');
160
+ cy.get('input[name="password"]').type('WrongPass');
161
+ cy.get('button[type="submit"]').click();
162
+
163
+ cy.get('.error-message')
164
+ .should('be.visible')
165
+ .and('have.text', 'Invalid credentials');
166
+ });
167
+ });
168
+ ```
169
+
170
+ #### Custom Commands (Reusable Actions)
171
+
172
+ ```javascript
173
+ // cypress/support/commands.js
174
+ Cypress.Commands.add('login', (email, password) => {
175
+ cy.visit('/login');
176
+ cy.get('input[name="email"]').type(email);
177
+ cy.get('input[name="password"]').type(password);
178
+ cy.get('button[type="submit"]').click();
179
+ cy.url().should('include', '/dashboard');
180
+ });
181
+
182
+ // Usage in tests
183
+ it('should display dashboard for logged-in user', () => {
184
+ cy.login('user@example.com', 'SecurePass123!');
185
+ cy.get('h1').should('have.text', 'Dashboard');
186
+ });
187
+ ```
188
+
189
+ #### API Mocking with Intercept
190
+
191
+ ```javascript
192
+ it('should display mocked user data', () => {
193
+ cy.intercept('GET', '/api/user', {
194
+ statusCode: 200,
195
+ body: {
196
+ id: 1,
197
+ name: 'Mock User',
198
+ email: 'mock@example.com',
199
+ },
200
+ }).as('getUser');
201
+
202
+ cy.visit('/profile');
203
+
204
+ cy.wait('@getUser');
205
+ cy.get('.user-name').should('have.text', 'Mock User');
206
+ });
207
+ ```
208
+
209
+ ### 3. React Testing Library (Component Tests)
210
+
211
+ **Why Testing Library?**
212
+ - User-centric queries (accessibility-first)
213
+ - Encourages best practices (testing behavior, not implementation)
214
+ - Works with React, Vue, Svelte, Angular
215
+
216
+ #### Component Test Example
217
+
218
+ ```typescript
219
+ import { render, screen, fireEvent } from '@testing-library/react';
220
+ import { LoginForm } from './LoginForm';
221
+
222
+ describe('LoginForm', () => {
223
+ it('should render email and password inputs', () => {
224
+ render(<LoginForm />);
225
+
226
+ expect(screen.getByLabelText('Email')).toBeInTheDocument();
227
+ expect(screen.getByLabelText('Password')).toBeInTheDocument();
228
+ });
229
+
230
+ it('should call onSubmit with email and password', async () => {
231
+ const handleSubmit = vi.fn();
232
+ render(<LoginForm onSubmit={handleSubmit} />);
233
+
234
+ // Type into inputs
235
+ fireEvent.change(screen.getByLabelText('Email'), {
236
+ target: { value: 'user@example.com' },
237
+ });
238
+ fireEvent.change(screen.getByLabelText('Password'), {
239
+ target: { value: 'SecurePass123!' },
240
+ });
241
+
242
+ // Submit form
243
+ fireEvent.click(screen.getByRole('button', { name: /login/i }));
244
+
245
+ // Verify callback
246
+ expect(handleSubmit).toHaveBeenCalledWith({
247
+ email: 'user@example.com',
248
+ password: 'SecurePass123!',
249
+ });
250
+ });
251
+
252
+ it('should show validation error for invalid email', async () => {
253
+ render(<LoginForm />);
254
+
255
+ fireEvent.change(screen.getByLabelText('Email'), {
256
+ target: { value: 'invalid-email' },
257
+ });
258
+ fireEvent.blur(screen.getByLabelText('Email'));
259
+
260
+ expect(await screen.findByText('Invalid email format')).toBeInTheDocument();
261
+ });
262
+ });
263
+ ```
264
+
265
+ #### User-Centric Queries (Preferred)
266
+
267
+ ```typescript
268
+ // ✅ GOOD: Accessible queries (user-facing)
269
+ screen.getByRole('button', { name: /submit/i });
270
+ screen.getByLabelText('Email');
271
+ screen.getByPlaceholderText('Enter your email');
272
+ screen.getByText('Welcome');
273
+
274
+ // ❌ BAD: Implementation-detail queries (fragile)
275
+ screen.getByClassName('btn-primary'); // Changes when CSS changes
276
+ screen.getByTestId('submit-button'); // Not user-facing
277
+ ```
278
+
279
+ ## Test Strategies
280
+
281
+ ### 1. Testing Pyramid
282
+
283
+ ```
284
+ /\
285
+ / \ E2E (10%)
286
+ /____\
287
+ / \ Integration (30%)
288
+ /________\
289
+ / \ Unit (60%)
290
+ /____________\
291
+ ```
292
+
293
+ **Unit Tests** (60%):
294
+ - Individual components in isolation
295
+ - Fast, cheap, many tests
296
+ - Mock external dependencies
297
+
298
+ **Integration Tests** (30%):
299
+ - Multiple components working together
300
+ - API integration, data flow
301
+ - Moderate speed, moderate cost
302
+
303
+ **E2E Tests** (10%):
304
+ - Full user journeys (login → checkout)
305
+ - Slowest, most expensive
306
+ - Critical paths only
307
+
308
+ ### 2. Test Coverage Strategy
309
+
310
+ **What to Test**:
311
+ - ✅ Happy paths (core user flows)
312
+ - ✅ Error states (validation, API failures)
313
+ - ✅ Edge cases (empty states, max limits)
314
+ - ✅ Accessibility (keyboard navigation, screen readers)
315
+ - ✅ Regression bugs (add test for each bug fix)
316
+
317
+ **What NOT to Test**:
318
+ - ❌ Third-party libraries (assume they work)
319
+ - ❌ Implementation details (internal state, CSS classes)
320
+ - ❌ Trivial code (getters, setters)
321
+
322
+ ### 3. Flakiness Mitigation
323
+
324
+ **Common Causes of Flaky Tests**:
325
+
326
+ 1. **Race Conditions**
327
+
328
+ ❌ **Bad**:
329
+ ```typescript
330
+ await page.click('button');
331
+ const text = await page.textContent('.result'); // May fail!
332
+ ```
333
+
334
+ ✅ **Good**:
335
+ ```typescript
336
+ await page.click('button');
337
+ await page.waitForSelector('.result'); // Wait for element
338
+ const text = await page.textContent('.result');
339
+ ```
340
+
341
+ 2. **Non-Deterministic Data**
342
+
343
+ ❌ **Bad**:
344
+ ```typescript
345
+ expect(page.locator('.user')).toHaveCount(5); // Depends on database state
346
+ ```
347
+
348
+ ✅ **Good**:
349
+ ```typescript
350
+ // Mock API to return deterministic data
351
+ await page.route('**/api/users', (route) =>
352
+ route.fulfill({
353
+ body: JSON.stringify([{ id: 1, name: 'User 1' }, { id: 2, name: 'User 2' }]),
354
+ })
355
+ );
356
+
357
+ expect(page.locator('.user')).toHaveCount(2); // Predictable
358
+ ```
359
+
360
+ 3. **Timing Issues**
361
+
362
+ ❌ **Bad**:
363
+ ```typescript
364
+ await page.waitForTimeout(3000); // Arbitrary wait
365
+ ```
366
+
367
+ ✅ **Good**:
368
+ ```typescript
369
+ await page.waitForSelector('.loaded'); // Wait for specific condition
370
+ await page.waitForLoadState('networkidle'); // Wait for network idle
371
+ ```
372
+
373
+ 4. **Test Interdependence**
374
+
375
+ ❌ **Bad**:
376
+ ```typescript
377
+ test('create user', async () => {
378
+ // Creates user in DB
379
+ });
380
+
381
+ test('login user', async () => {
382
+ // Depends on previous test creating user
383
+ });
384
+ ```
385
+
386
+ ✅ **Good**:
387
+ ```typescript
388
+ test.beforeEach(async () => {
389
+ // Each test creates its own user
390
+ await createTestUser();
391
+ });
392
+
393
+ test.afterEach(async () => {
394
+ await cleanupTestUsers();
395
+ });
396
+ ```
397
+
398
+ ## Accessibility Testing
399
+
400
+ ### 1. Automated Accessibility Tests (axe-core)
401
+
402
+ ```typescript
403
+ import { test, expect } from '@playwright/test';
404
+ import AxeBuilder from '@axe-core/playwright';
405
+
406
+ test('should have no accessibility violations', async ({ page }) => {
407
+ await page.goto('https://example.com');
408
+
409
+ const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
410
+
411
+ expect(accessibilityScanResults.violations).toEqual([]);
412
+ });
413
+ ```
414
+
415
+ ### 2. Keyboard Navigation
416
+
417
+ ```typescript
418
+ test('should navigate form with keyboard', async ({ page }) => {
419
+ await page.goto('/form');
420
+
421
+ // Tab through form fields
422
+ await page.keyboard.press('Tab');
423
+ await expect(page.locator('input[name="email"]')).toBeFocused();
424
+
425
+ await page.keyboard.press('Tab');
426
+ await expect(page.locator('input[name="password"]')).toBeFocused();
427
+
428
+ await page.keyboard.press('Tab');
429
+ await expect(page.locator('button[type="submit"]')).toBeFocused();
430
+
431
+ // Submit with Enter
432
+ await page.keyboard.press('Enter');
433
+ await expect(page).toHaveURL('**/dashboard');
434
+ });
435
+ ```
436
+
437
+ ### 3. Screen Reader Testing (aria-label, roles)
438
+
439
+ ```typescript
440
+ test('should have proper ARIA labels', async ({ page }) => {
441
+ await page.goto('/login');
442
+
443
+ // Verify accessible names
444
+ await expect(page.getByRole('textbox', { name: 'Email' })).toBeVisible();
445
+ await expect(page.getByRole('textbox', { name: 'Password' })).toBeVisible();
446
+ await expect(page.getByRole('button', { name: 'Login' })).toBeVisible();
447
+
448
+ // Verify error announcements (aria-live)
449
+ await page.fill('input[name="email"]', 'invalid-email');
450
+ await page.click('button[type="submit"]');
451
+
452
+ const errorRegion = page.locator('[role="alert"]');
453
+ await expect(errorRegion).toHaveText('Invalid email format');
454
+ });
455
+ ```
456
+
457
+ ## CI/CD Integration
458
+
459
+ ### 1. GitHub Actions (Playwright)
460
+
461
+ ```yaml
462
+ name: E2E Tests
463
+
464
+ on:
465
+ push:
466
+ branches: [main, develop]
467
+ pull_request:
468
+
469
+ jobs:
470
+ test:
471
+ runs-on: ubuntu-latest
472
+ steps:
473
+ - uses: actions/checkout@v3
474
+ - uses: actions/setup-node@v3
475
+ with:
476
+ node-version: 18
477
+
478
+ - name: Install dependencies
479
+ run: npm ci
480
+
481
+ - name: Install Playwright browsers
482
+ run: npx playwright install --with-deps
483
+
484
+ - name: Run Playwright tests
485
+ run: npx playwright test
486
+
487
+ - name: Upload test results
488
+ if: always()
489
+ uses: actions/upload-artifact@v3
490
+ with:
491
+ name: playwright-report
492
+ path: playwright-report/
493
+ ```
494
+
495
+ ### 2. Parallel Execution
496
+
497
+ ```typescript
498
+ // playwright.config.ts
499
+ export default defineConfig({
500
+ workers: process.env.CI ? 2 : undefined, // Parallel in CI
501
+ fullyParallel: true,
502
+ retries: process.env.CI ? 2 : 0, // Retry flaky tests in CI
503
+ reporter: process.env.CI ? 'github' : 'html',
504
+ });
505
+ ```
506
+
507
+ ### 3. Sharding (Large Test Suites)
508
+
509
+ ```bash
510
+ # Split tests across 4 machines
511
+ npx playwright test --shard=1/4
512
+ npx playwright test --shard=2/4
513
+ npx playwright test --shard=3/4
514
+ npx playwright test --shard=4/4
515
+ ```
516
+
517
+ ## Best Practices
518
+
519
+ ### 1. Use Data Attributes for Stable Selectors
520
+
521
+ ```html
522
+ <!-- ✅ GOOD: Stable selector -->
523
+ <button data-testid="submit-button">Submit</button>
524
+
525
+ <!-- ❌ BAD: Fragile selectors -->
526
+ <button class="btn btn-primary">Submit</button> <!-- CSS changes break tests -->
527
+ ```
528
+
529
+ ```typescript
530
+ // Test
531
+ await page.click('[data-testid="submit-button"]');
532
+ ```
533
+
534
+ ### 2. Test User Behavior, Not Implementation
535
+
536
+ ❌ **Bad**:
537
+ ```typescript
538
+ // Testing internal state
539
+ expect(component.state.isLoading).toBe(true);
540
+ ```
541
+
542
+ ✅ **Good**:
543
+ ```typescript
544
+ // Testing visible UI
545
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
546
+ ```
547
+
548
+ ### 3. Keep Tests Independent
549
+
550
+ ```typescript
551
+ // ✅ GOOD: Each test is independent
552
+ test.beforeEach(async ({ page }) => {
553
+ await page.goto('/');
554
+ await login(page, 'user@example.com', 'password');
555
+ });
556
+
557
+ test('test 1', async ({ page }) => {
558
+ // Fresh state
559
+ });
560
+
561
+ test('test 2', async ({ page }) => {
562
+ // Fresh state
563
+ });
564
+ ```
565
+
566
+ ### 4. Use Meaningful Assertions
567
+
568
+ ❌ **Bad**:
569
+ ```typescript
570
+ expect(true).toBe(true); // Useless assertion
571
+ ```
572
+
573
+ ✅ **Good**:
574
+ ```typescript
575
+ await expect(page.locator('.success-message')).toHaveText(
576
+ 'Order placed successfully'
577
+ );
578
+ ```
579
+
580
+ ### 5. Avoid Hard-Coded Waits
581
+
582
+ ❌ **Bad**:
583
+ ```typescript
584
+ await page.waitForTimeout(5000); // Slow, brittle
585
+ ```
586
+
587
+ ✅ **Good**:
588
+ ```typescript
589
+ await page.waitForSelector('.results'); // Wait for specific element
590
+ await expect(page.locator('.results')).toBeVisible(); // Built-in wait
591
+ ```
592
+
593
+ ## Debugging Tests
594
+
595
+ ### 1. Headed Mode (See Browser)
596
+
597
+ ```bash
598
+ npx playwright test --headed
599
+ npx playwright test --headed --debug # Pause on each step
600
+ ```
601
+
602
+ ### 2. Screenshot on Failure
603
+
604
+ ```typescript
605
+ test.afterEach(async ({ page }, testInfo) => {
606
+ if (testInfo.status !== 'passed') {
607
+ await page.screenshot({ path: `failure-${testInfo.title}.png` });
608
+ }
609
+ });
610
+ ```
611
+
612
+ ### 3. Trace Viewer (Time-Travel Debugging)
613
+
614
+ ```typescript
615
+ // playwright.config.ts
616
+ export default defineConfig({
617
+ use: {
618
+ trace: 'on-first-retry', // Record trace on retry
619
+ },
620
+ });
621
+ ```
622
+
623
+ ```bash
624
+ # View trace
625
+ npx playwright show-trace trace.zip
626
+ ```
627
+
628
+ ### 4. Console Logs
629
+
630
+ ```typescript
631
+ page.on('console', (msg) => console.log('Browser log:', msg.text()));
632
+ page.on('pageerror', (error) => console.error('Page error:', error));
633
+ ```
634
+
635
+ ## Common Patterns
636
+
637
+ ### 1. Testing Forms
638
+
639
+ ```typescript
640
+ test('should validate form fields', async ({ page }) => {
641
+ await page.goto('/form');
642
+
643
+ // Empty submission (validation)
644
+ await page.click('button[type="submit"]');
645
+ await expect(page.locator('.email-error')).toHaveText('Email is required');
646
+
647
+ // Invalid email
648
+ await page.fill('input[name="email"]', 'invalid');
649
+ await page.click('button[type="submit"]');
650
+ await expect(page.locator('.email-error')).toHaveText('Invalid email format');
651
+
652
+ // Valid submission
653
+ await page.fill('input[name="email"]', 'user@example.com');
654
+ await page.fill('input[name="password"]', 'SecurePass123!');
655
+ await page.click('button[type="submit"]');
656
+ await expect(page).toHaveURL('**/success');
657
+ });
658
+ ```
659
+
660
+ ### 2. Testing Modals
661
+
662
+ ```typescript
663
+ test('should open and close modal', async ({ page }) => {
664
+ await page.goto('/');
665
+
666
+ // Open modal
667
+ await page.click('[data-testid="open-modal"]');
668
+ await expect(page.locator('.modal')).toBeVisible();
669
+
670
+ // Close with X button
671
+ await page.click('.modal .close-button');
672
+ await expect(page.locator('.modal')).not.toBeVisible();
673
+
674
+ // Open again, close with Escape
675
+ await page.click('[data-testid="open-modal"]');
676
+ await page.keyboard.press('Escape');
677
+ await expect(page.locator('.modal')).not.toBeVisible();
678
+ });
679
+ ```
680
+
681
+ ### 3. Testing Drag and Drop
682
+
683
+ ```typescript
684
+ test('should drag and drop items', async ({ page }) => {
685
+ await page.goto('/kanban');
686
+
687
+ const todoItem = page.locator('[data-testid="item-1"]');
688
+ const doneColumn = page.locator('[data-testid="column-done"]');
689
+
690
+ // Drag item from TODO to DONE
691
+ await todoItem.dragTo(doneColumn);
692
+
693
+ // Verify item moved
694
+ await expect(doneColumn.locator('[data-testid="item-1"]')).toBeVisible();
695
+ });
696
+ ```
697
+
698
+ ## Resources
699
+
700
+ - [Playwright Documentation](https://playwright.dev/)
701
+ - [Cypress Documentation](https://docs.cypress.io/)
702
+ - [Testing Library](https://testing-library.com/)
703
+ - [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/WAI/WCAG21/quickref/)
704
+
705
+ ## Activation Keywords
706
+
707
+ Ask me about:
708
+ - "How to write E2E tests with Playwright"
709
+ - "Cypress test examples"
710
+ - "React Testing Library best practices"
711
+ - "Page Object Model for UI tests"
712
+ - "Accessibility testing with axe-core"
713
+ - "How to fix flaky tests"
714
+ - "CI/CD integration for UI tests"
715
+ - "Debugging Playwright tests"
716
+ - "Test automation strategies"