ima-claude 2.9.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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +463 -0
  3. package/dist/cli.js +1064 -0
  4. package/package.json +49 -0
  5. package/platforms/claude/adapter.ts +115 -0
  6. package/platforms/junie/adapter.ts +254 -0
  7. package/platforms/junie/agents-template.md +113 -0
  8. package/platforms/junie/hook-translations.md +84 -0
  9. package/platforms/shared/detector.ts +27 -0
  10. package/platforms/shared/installer.ts +202 -0
  11. package/platforms/shared/types.ts +78 -0
  12. package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
  13. package/plugins/ima-claude/agents/explorer.md +30 -0
  14. package/plugins/ima-claude/agents/implementer.md +30 -0
  15. package/plugins/ima-claude/agents/memory.md +42 -0
  16. package/plugins/ima-claude/agents/reviewer.md +53 -0
  17. package/plugins/ima-claude/agents/tester.md +33 -0
  18. package/plugins/ima-claude/agents/wp-developer.md +46 -0
  19. package/plugins/ima-claude/hooks/README.md +145 -0
  20. package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
  21. package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
  22. package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
  23. package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
  24. package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
  25. package/plugins/ima-claude/hooks/docs_organization.py +104 -0
  26. package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
  27. package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
  28. package/plugins/ima-claude/hooks/hook_logger.py +69 -0
  29. package/plugins/ima-claude/hooks/hooks.json +239 -0
  30. package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
  31. package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
  32. package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
  33. package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
  34. package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
  35. package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
  36. package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
  37. package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
  38. package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
  39. package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
  40. package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
  41. package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
  42. package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
  43. package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
  44. package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
  45. package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
  46. package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
  47. package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
  48. package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
  49. package/plugins/ima-claude/personalities/README.md +45 -0
  50. package/plugins/ima-claude/personalities/enable-40k.md +69 -0
  51. package/plugins/ima-claude/personalities/enable-templars.md +69 -0
  52. package/plugins/ima-claude/skills/.research-summary.md +340 -0
  53. package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
  54. package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
  55. package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
  56. package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
  57. package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
  58. package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
  59. package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
  60. package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
  61. package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
  62. package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
  63. package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
  64. package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
  65. package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
  66. package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
  67. package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
  68. package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
  69. package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
  70. package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
  71. package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
  72. package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
  73. package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
  74. package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
  75. package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
  76. package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
  77. package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
  78. package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
  79. package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
  80. package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
  81. package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
  82. package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
  83. package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
  84. package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
  85. package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
  86. package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
  87. package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
  88. package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
  89. package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
  90. package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
  91. package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
  92. package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
  93. package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
  94. package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
  95. package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
  96. package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
  97. package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
  98. package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
  99. package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
  100. package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
  101. package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
  102. package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
  103. package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
  104. package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
  105. package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
  106. package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
  107. package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
  108. package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
  109. package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
  110. package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
  111. package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
  112. package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
  113. package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
  114. package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
  115. package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
  116. package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
  117. package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
  118. package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
  119. package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
  120. package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
  121. package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
  122. package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
  123. package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
  124. package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
  125. package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
  126. package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
  127. package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
  128. package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
  129. package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
  130. package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
  131. package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
  132. package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
  133. package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
  134. package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
  135. package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
  136. package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
  137. package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
  138. package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
  139. package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
  140. package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
  141. package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
  142. package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
  143. package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
  144. package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
  145. package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
  146. package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
  147. package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
  148. package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
  149. package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
  150. package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
  151. package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
  152. package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
  153. package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
  154. package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
  155. package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
  156. package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
  157. package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
  158. package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
  159. package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
  160. package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
  161. package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
  162. package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
  163. package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
  164. package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
  165. package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
  166. package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
  167. package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
  168. package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
  169. package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
  170. package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
  171. package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
  172. package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
  173. package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
  174. package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
  175. package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
  176. package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
  177. package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
  178. package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
  179. package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
  180. package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
  181. package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
  182. package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
@@ -0,0 +1,434 @@
1
+ ---
2
+ name: "playwright"
3
+ description: "End-to-end testing and QA automation with Playwright + TypeScript. Test strategy, locators, fixtures, POM, assertions, network mocking, visual regression, accessibility, and CI/CD. Use when: writing E2E tests, creating page objects, setting up test fixtures, mocking API responses, visual regression testing, accessibility audits, configuring Playwright projects, debugging flaky tests, or when user mentions Playwright, E2E, end-to-end, browser testing, test automation, QA automation, getByRole, locator, toBeVisible, toHaveScreenshot, or page.route."
4
+ ---
5
+
6
+ # Playwright + QA Automation
7
+
8
+ E2E testing with Playwright and TypeScript. Combines QA strategy (what/why to test) with Playwright implementation (how to test).
9
+
10
+ ## QA Strategy Layer
11
+
12
+ ### Test Pyramid for E2E
13
+
14
+ E2E tests are expensive. Use them strategically:
15
+
16
+ - **Test critical user journeys** — login, checkout, signup, core workflows
17
+ - **Don't duplicate unit test coverage** — if business logic is tested in unit tests, don't re-test it through the UI
18
+ - **Test integration points** — where frontend meets backend, where data flows between systems
19
+ - **Test what users actually do** — real workflows, not implementation details
20
+
21
+ ### What Makes a Good E2E Test
22
+
23
+ ```typescript
24
+ // GOOD: Tests a real user journey with meaningful assertions
25
+ test('user completes checkout flow', async ({ page }) => {
26
+ await page.goto('/products')
27
+ await page.getByRole('button', { name: 'Add to cart' }).first().click()
28
+ await page.getByRole('link', { name: 'Cart' }).click()
29
+ await page.getByRole('button', { name: 'Checkout' }).click()
30
+ await expect(page.getByText('Order confirmed')).toBeVisible()
31
+ })
32
+
33
+ // BAD: Tests implementation details, brittle selectors
34
+ test('checkout works', async ({ page }) => {
35
+ await page.goto('/products')
36
+ await page.click('#product-123 > .btn-primary') // brittle
37
+ await page.waitForTimeout(2000) // never do this
38
+ expect(await page.locator('.cart-count').innerText()).toBe('1') // manual assertion
39
+ })
40
+ ```
41
+
42
+ ### Test Independence
43
+
44
+ Each test must be self-contained:
45
+ - Set up its own data (via API calls, not UI when possible)
46
+ - Clean up after itself (or use fresh browser contexts — Playwright's default)
47
+ - Never depend on another test's state or execution order
48
+
49
+ ## Locator Strategy
50
+
51
+ **Priority order** (most resilient to least):
52
+
53
+ | Priority | Locator | Example | Why |
54
+ |----------|---------|---------|-----|
55
+ | 1 | Role | `getByRole('button', { name: 'Submit' })` | Semantic, accessible |
56
+ | 2 | Label | `getByLabel('Email address')` | User-facing text |
57
+ | 3 | Placeholder | `getByPlaceholder('Enter email')` | User-facing text |
58
+ | 4 | Text | `getByText('Welcome back')` | User-visible content |
59
+ | 5 | Test ID | `getByTestId('submit-btn')` | Stable, explicit contract |
60
+ | 6 | CSS/XPath | `locator('.btn-primary')` | Last resort only |
61
+
62
+ ```typescript
63
+ // Prefer semantic locators
64
+ await page.getByRole('button', { name: 'Save changes' }).click()
65
+ await page.getByLabel('Email').fill('user@example.com')
66
+
67
+ // Use test IDs when no semantic option exists
68
+ await page.getByTestId('chart-container').isVisible()
69
+
70
+ // Scoped locators for disambiguation
71
+ const dialog = page.getByRole('dialog')
72
+ await dialog.getByRole('button', { name: 'Confirm' }).click()
73
+
74
+ // Filter locators for lists
75
+ await page.getByRole('listitem').filter({ hasText: 'Product A' }).click()
76
+ ```
77
+
78
+ ## Assertions
79
+
80
+ **Always use web-first assertions** — they auto-wait and retry.
81
+
82
+ ```typescript
83
+ // CORRECT: Web-first assertions (auto-wait + retry)
84
+ await expect(page.getByText('Success')).toBeVisible()
85
+ await expect(page.getByRole('heading')).toHaveText('Dashboard')
86
+ await expect(page).toHaveURL(/\/dashboard/)
87
+ await expect(page).toHaveTitle('My App - Dashboard')
88
+
89
+ // WRONG: Manual assertions (race conditions, flaky)
90
+ expect(await page.getByText('Success').isVisible()).toBe(true)
91
+ const text = await page.locator('h1').innerText()
92
+ expect(text).toBe('Dashboard')
93
+ ```
94
+
95
+ ### Key Assertions
96
+
97
+ ```typescript
98
+ // Visibility
99
+ await expect(locator).toBeVisible()
100
+ await expect(locator).toBeHidden()
101
+
102
+ // Text content
103
+ await expect(locator).toHaveText('exact text')
104
+ await expect(locator).toContainText('partial')
105
+
106
+ // Input state
107
+ await expect(locator).toHaveValue('test@example.com')
108
+ await expect(locator).toBeChecked()
109
+ await expect(locator).toBeDisabled()
110
+
111
+ // Count
112
+ await expect(page.getByRole('listitem')).toHaveCount(3)
113
+
114
+ // Page-level
115
+ await expect(page).toHaveURL(/dashboard/)
116
+ await expect(page).toHaveTitle(/Dashboard/)
117
+ ```
118
+
119
+ ## Page Object Model
120
+
121
+ Encapsulate page interactions in classes. Tests read like user stories.
122
+
123
+ ```typescript
124
+ // pages/LoginPage.ts
125
+ import { type Page, type Locator, expect } from '@playwright/test'
126
+
127
+ export class LoginPage {
128
+ readonly emailInput: Locator
129
+ readonly passwordInput: Locator
130
+ readonly submitButton: Locator
131
+ readonly errorMessage: Locator
132
+
133
+ constructor(private readonly page: Page) {
134
+ this.emailInput = page.getByLabel('Email')
135
+ this.passwordInput = page.getByLabel('Password')
136
+ this.submitButton = page.getByRole('button', { name: 'Sign in' })
137
+ this.errorMessage = page.getByRole('alert')
138
+ }
139
+
140
+ async goto() {
141
+ await this.page.goto('/login')
142
+ }
143
+
144
+ async login(email: string, password: string) {
145
+ await this.emailInput.fill(email)
146
+ await this.passwordInput.fill(password)
147
+ await this.submitButton.click()
148
+ }
149
+
150
+ async expectError(message: string) {
151
+ await expect(this.errorMessage).toContainText(message)
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### Register Page Objects as Fixtures
157
+
158
+ ```typescript
159
+ // fixtures.ts
160
+ import { test as base } from '@playwright/test'
161
+ import { LoginPage } from './pages/LoginPage'
162
+ import { DashboardPage } from './pages/DashboardPage'
163
+
164
+ type Fixtures = {
165
+ loginPage: LoginPage
166
+ dashboardPage: DashboardPage
167
+ }
168
+
169
+ export const test = base.extend<Fixtures>({
170
+ loginPage: async ({ page }, use) => {
171
+ await use(new LoginPage(page))
172
+ },
173
+ dashboardPage: async ({ page }, use) => {
174
+ await use(new DashboardPage(page))
175
+ },
176
+ })
177
+
178
+ export { expect } from '@playwright/test'
179
+ ```
180
+
181
+ ```typescript
182
+ // tests/login.spec.ts
183
+ import { test, expect } from '../fixtures'
184
+
185
+ test('successful login redirects to dashboard', async ({ loginPage, dashboardPage }) => {
186
+ await loginPage.goto()
187
+ await loginPage.login('user@example.com', 'password123')
188
+ await expect(dashboardPage.heading).toBeVisible()
189
+ })
190
+
191
+ test('invalid credentials show error', async ({ loginPage }) => {
192
+ await loginPage.goto()
193
+ await loginPage.login('user@example.com', 'wrong')
194
+ await loginPage.expectError('Invalid credentials')
195
+ })
196
+ ```
197
+
198
+ ## Custom Fixtures
199
+
200
+ Fixtures provide reusable setup/teardown. Use them instead of beforeEach/afterEach.
201
+
202
+ ```typescript
203
+ // fixtures.ts — authenticated user fixture
204
+ export const test = base.extend<{
205
+ authenticatedPage: Page
206
+ }>({
207
+ authenticatedPage: async ({ browser }, use) => {
208
+ const context = await browser.newContext({
209
+ storageState: 'auth/user.json' // pre-saved auth state
210
+ })
211
+ const page = await context.newPage()
212
+ await use(page)
213
+ await context.close()
214
+ },
215
+ })
216
+ ```
217
+
218
+ ### Save Auth State (Global Setup)
219
+
220
+ ```typescript
221
+ // global-setup.ts
222
+ import { chromium, type FullConfig } from '@playwright/test'
223
+
224
+ export default async function globalSetup(config: FullConfig) {
225
+ const browser = await chromium.launch()
226
+ const page = await browser.newPage()
227
+ await page.goto('/login')
228
+ await page.getByLabel('Email').fill(process.env.TEST_USER!)
229
+ await page.getByLabel('Password').fill(process.env.TEST_PASSWORD!)
230
+ await page.getByRole('button', { name: 'Sign in' }).click()
231
+ await page.waitForURL('/dashboard')
232
+ await page.context().storageState({ path: 'auth/user.json' })
233
+ await browser.close()
234
+ }
235
+ ```
236
+
237
+ ## Project Structure
238
+
239
+ ```
240
+ tests/
241
+ ├── e2e/
242
+ │ ├── auth/
243
+ │ │ ├── login.spec.ts
244
+ │ │ └── signup.spec.ts
245
+ │ ├── checkout/
246
+ │ │ └── purchase-flow.spec.ts
247
+ │ └── dashboard/
248
+ │ └── widgets.spec.ts
249
+ ├── pages/
250
+ │ ├── LoginPage.ts
251
+ │ ├── DashboardPage.ts
252
+ │ └── CheckoutPage.ts
253
+ ├── components/
254
+ │ ├── Modal.ts
255
+ │ ├── DataTable.ts
256
+ │ └── Navigation.ts
257
+ ├── fixtures.ts
258
+ ├── global-setup.ts
259
+ └── playwright.config.ts
260
+ ```
261
+
262
+ **Guidelines**:
263
+ - One page object per page/major section
264
+ - Shared components (modals, tables, nav) get their own classes in `components/`
265
+ - Tests grouped by feature area
266
+ - Single `fixtures.ts` exports the extended `test` object
267
+
268
+ ## Configuration
269
+
270
+ ```typescript
271
+ // playwright.config.ts
272
+ import { defineConfig, devices } from '@playwright/test'
273
+
274
+ export default defineConfig({
275
+ testDir: './tests/e2e',
276
+ fullyParallel: true,
277
+ forbidOnly: !!process.env.CI,
278
+ retries: process.env.CI ? 2 : 0,
279
+ workers: process.env.CI ? 1 : undefined,
280
+ reporter: process.env.CI ? 'blob' : 'html',
281
+ globalSetup: './tests/global-setup.ts',
282
+
283
+ use: {
284
+ baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
285
+ trace: 'on-first-retry',
286
+ screenshot: 'only-on-failure',
287
+ video: 'retain-on-failure',
288
+ },
289
+
290
+ projects: [
291
+ { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
292
+ { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
293
+ { name: 'webkit', use: { ...devices['Desktop Safari'] } },
294
+ { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
295
+ { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
296
+ ],
297
+
298
+ webServer: {
299
+ command: 'npm run dev',
300
+ url: 'http://localhost:3000',
301
+ reuseExistingServer: !process.env.CI,
302
+ },
303
+ })
304
+ ```
305
+
306
+ ## Network Mocking (Quick Reference)
307
+
308
+ ```typescript
309
+ // Mock an API endpoint
310
+ await page.route('**/api/users', route => route.fulfill({
311
+ status: 200,
312
+ contentType: 'application/json',
313
+ body: JSON.stringify([{ id: 1, name: 'Test User' }]),
314
+ }))
315
+
316
+ // Modify a real response
317
+ await page.route('**/api/products', async route => {
318
+ const response = await route.fetch()
319
+ const json = await response.json()
320
+ json.push({ id: 999, name: 'Test Product' })
321
+ await route.fulfill({ response, json })
322
+ })
323
+
324
+ // Block resources (speed up tests)
325
+ await page.route('**/*.{png,jpg,gif}', route => route.abort())
326
+
327
+ // Add auth headers
328
+ await page.route('**/api/**', route => {
329
+ route.continue({
330
+ headers: { ...route.request().headers(), Authorization: 'Bearer test-token' },
331
+ })
332
+ })
333
+ ```
334
+
335
+ For advanced mocking patterns (HAR recording, API-first setup, error simulation), see [references/network-mocking.md](references/network-mocking.md).
336
+
337
+ ## Visual Regression (Quick Reference)
338
+
339
+ ```typescript
340
+ // Full page screenshot comparison
341
+ await expect(page).toHaveScreenshot()
342
+
343
+ // Element-level comparison
344
+ await expect(page.getByTestId('chart')).toHaveScreenshot('chart.png')
345
+
346
+ // With tolerance for minor rendering differences
347
+ await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.01 })
348
+
349
+ // Update baselines: npx playwright test --update-snapshots
350
+ ```
351
+
352
+ For deterministic screenshots, animation handling, and CI considerations, see [references/visual-regression.md](references/visual-regression.md).
353
+
354
+ ## Debugging
355
+
356
+ ```bash
357
+ # Run with UI mode (interactive debugging)
358
+ npx playwright test --ui
359
+
360
+ # Run with headed browser
361
+ npx playwright test --headed
362
+
363
+ # Run with step-by-step trace viewer
364
+ npx playwright test --trace on
365
+
366
+ # Debug a specific test
367
+ npx playwright test -g "login" --debug
368
+
369
+ # View last test report
370
+ npx playwright show-report
371
+ ```
372
+
373
+ ```typescript
374
+ // Pause execution for manual inspection
375
+ await page.pause()
376
+
377
+ // Slow down actions for visual debugging
378
+ // In config: use: { launchOptions: { slowMo: 500 } }
379
+ ```
380
+
381
+ ## Anti-Patterns
382
+
383
+ ```typescript
384
+ // NEVER: Hard-coded waits
385
+ await page.waitForTimeout(3000) // Use auto-waiting instead
386
+
387
+ // NEVER: Brittle CSS selectors
388
+ await page.click('#app > div:nth-child(2) > button.btn-primary')
389
+
390
+ // NEVER: Manual assertions without retry
391
+ const text = await page.locator('.status').innerText()
392
+ expect(text).toBe('Ready') // Race condition — use web-first assertions
393
+
394
+ // NEVER: Testing third-party dependencies
395
+ await page.goto('https://external-service.com/verify') // Mock it instead
396
+
397
+ // NEVER: Shared mutable state between tests
398
+ let sharedUser // Each test gets its own state via fixtures
399
+
400
+ // NEVER: Skipping cleanup
401
+ // Use fixtures — they handle teardown automatically
402
+ ```
403
+
404
+ ## Linting
405
+
406
+ Use `eslint-plugin-playwright` to catch common mistakes:
407
+
408
+ ```bash
409
+ npm install -D eslint-plugin-playwright
410
+ ```
411
+
412
+ Key rules it catches:
413
+ - Missing `await` on async Playwright calls
414
+ - Using `page.waitForTimeout` (prefer auto-waiting)
415
+ - Manual assertions instead of web-first assertions
416
+ - Using forbidden selectors (nth-child, etc.)
417
+
418
+ ## Reference Files
419
+
420
+ ### Network Mocking Patterns
421
+ **File**: [references/network-mocking.md](references/network-mocking.md)
422
+ **When**: Mocking APIs, HAR recording, intercepting requests, simulating errors, API-first test setup
423
+
424
+ ### Visual Regression Testing
425
+ **File**: [references/visual-regression.md](references/visual-regression.md)
426
+ **When**: Screenshot comparisons, deterministic rendering, CI screenshot strategies, animation handling
427
+
428
+ ### Accessibility Testing
429
+ **File**: [references/accessibility-testing.md](references/accessibility-testing.md)
430
+ **When**: WCAG compliance audits, axe-core integration, accessibility fixtures, automated a11y checks
431
+
432
+ ### CI/CD Integration
433
+ **File**: [references/ci-cd.md](references/ci-cd.md)
434
+ **When**: GitHub Actions setup, sharding, parallelism, artifact management, Docker, reporting strategies
@@ -0,0 +1,153 @@
1
+ # Accessibility Testing
2
+
3
+ Automated WCAG compliance checks using Playwright with axe-core.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Setup](#setup)
8
+ - [Basic Scanning](#basic-scanning)
9
+ - [Fixtures for Reusable Config](#fixtures-for-reusable-config)
10
+ - [Targeted Scanning](#targeted-scanning)
11
+ - [Common Violations](#common-violations)
12
+ - [Integration with E2E Tests](#integration-with-e2e-tests)
13
+
14
+ ## Setup
15
+
16
+ ```bash
17
+ npm install -D @axe-core/playwright
18
+ ```
19
+
20
+ ## Basic Scanning
21
+
22
+ ```typescript
23
+ import { test, expect } from '@playwright/test'
24
+ import AxeBuilder from '@axe-core/playwright'
25
+
26
+ test('homepage has no a11y violations', async ({ page }) => {
27
+ await page.goto('/')
28
+
29
+ const results = await new AxeBuilder({ page }).analyze()
30
+
31
+ expect(results.violations).toEqual([])
32
+ })
33
+ ```
34
+
35
+ ## Fixtures for Reusable Config
36
+
37
+ Create a shared axe fixture with consistent WCAG rules across all tests.
38
+
39
+ ```typescript
40
+ // fixtures.ts
41
+ import { test as base } from '@playwright/test'
42
+ import AxeBuilder from '@axe-core/playwright'
43
+
44
+ type A11yFixtures = {
45
+ makeAxeBuilder: () => AxeBuilder
46
+ }
47
+
48
+ export const test = base.extend<A11yFixtures>({
49
+ makeAxeBuilder: async ({ page }, use) => {
50
+ await use(() =>
51
+ new AxeBuilder({ page })
52
+ .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
53
+ )
54
+ },
55
+ })
56
+
57
+ export { expect } from '@playwright/test'
58
+ ```
59
+
60
+ ```typescript
61
+ // tests/a11y/pages.spec.ts
62
+ import { test, expect } from '../../fixtures'
63
+
64
+ test('login page is accessible', async ({ page, makeAxeBuilder }) => {
65
+ await page.goto('/login')
66
+ const results = await makeAxeBuilder().analyze()
67
+ expect(results.violations).toEqual([])
68
+ })
69
+
70
+ test('dashboard is accessible', async ({ page, makeAxeBuilder }) => {
71
+ await page.goto('/dashboard')
72
+ const results = await makeAxeBuilder().analyze()
73
+ expect(results.violations).toEqual([])
74
+ })
75
+ ```
76
+
77
+ ## Targeted Scanning
78
+
79
+ ### Scan Specific Sections
80
+
81
+ ```typescript
82
+ // Only scan the main content area
83
+ const results = await new AxeBuilder({ page })
84
+ .include('#main-content')
85
+ .analyze()
86
+
87
+ // Scan everything except a known-broken third-party widget
88
+ const results = await new AxeBuilder({ page })
89
+ .exclude('.third-party-chat-widget')
90
+ .analyze()
91
+ ```
92
+
93
+ ### Specific Rule Sets
94
+
95
+ ```typescript
96
+ // Only check color contrast
97
+ const results = await new AxeBuilder({ page })
98
+ .withRules(['color-contrast'])
99
+ .analyze()
100
+
101
+ // Disable specific rules (with justification)
102
+ const results = await new AxeBuilder({ page })
103
+ .disableRules(['color-contrast']) // Third-party component, tracked in JIRA-123
104
+ .analyze()
105
+ ```
106
+
107
+ ## Common Violations
108
+
109
+ | Violation | Fix | Impact |
110
+ |-----------|-----|--------|
111
+ | Missing alt text | Add `alt` attribute to `<img>` tags | Critical |
112
+ | Missing form labels | Associate `<label>` with inputs via `for`/`id` | Critical |
113
+ | Insufficient contrast | Adjust foreground/background colors to meet 4.5:1 ratio | Serious |
114
+ | Missing landmark regions | Wrap content in `<main>`, `<nav>`, `<header>` | Moderate |
115
+ | Missing page title | Add descriptive `<title>` element | Serious |
116
+ | Duplicate IDs | Ensure all `id` attributes are unique | Moderate |
117
+ | Missing language attribute | Add `lang` attribute to `<html>` | Serious |
118
+
119
+ ## Integration with E2E Tests
120
+
121
+ Run accessibility checks as part of existing E2E flows, not just standalone audits.
122
+
123
+ ```typescript
124
+ test('checkout flow is accessible at each step', async ({ page, makeAxeBuilder }) => {
125
+ // Step 1: Cart page
126
+ await page.goto('/cart')
127
+ let a11y = await makeAxeBuilder().analyze()
128
+ expect(a11y.violations).toEqual([])
129
+
130
+ // Step 2: Shipping form
131
+ await page.getByRole('button', { name: 'Proceed to shipping' }).click()
132
+ a11y = await makeAxeBuilder().analyze()
133
+ expect(a11y.violations).toEqual([])
134
+
135
+ // Step 3: Payment form
136
+ await page.getByRole('button', { name: 'Continue to payment' }).click()
137
+ a11y = await makeAxeBuilder().analyze()
138
+ expect(a11y.violations).toEqual([])
139
+ })
140
+ ```
141
+
142
+ ### Dedicated A11y Project
143
+
144
+ ```typescript
145
+ // playwright.config.ts — separate project for a11y tests
146
+ projects: [
147
+ {
148
+ name: 'accessibility',
149
+ testDir: './tests/a11y',
150
+ use: { ...devices['Desktop Chrome'] },
151
+ },
152
+ ],
153
+ ```