@mmerterden/multi-agent-pipeline 20.36.0 → 20.37.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 (222) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/docs/facts.json +2 -2
  3. package/docs/features.md +1 -1
  4. package/docs/recovery-guide.md +1 -1
  5. package/install/catalog-history.json +1 -1
  6. package/manifest.json +225 -148
  7. package/package.json +1 -1
  8. package/pipeline/commands/multi-agent/SKILL.md +33 -154
  9. package/pipeline/commands/multi-agent/analysis/SKILL.md +14 -68
  10. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +5 -8
  11. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +38 -109
  12. package/pipeline/commands/multi-agent/channels/SKILL.md +38 -167
  13. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +37 -144
  14. package/pipeline/commands/multi-agent/design-check/SKILL.md +27 -131
  15. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +22 -48
  16. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +37 -180
  17. package/pipeline/commands/multi-agent/jira/SKILL.md +16 -46
  18. package/pipeline/commands/multi-agent/manual-test/SKILL.md +12 -7
  19. package/pipeline/commands/multi-agent/refactor/SKILL.md +23 -184
  20. package/pipeline/commands/multi-agent/resume/SKILL.md +30 -136
  21. package/pipeline/commands/multi-agent/review/SKILL.md +24 -199
  22. package/pipeline/commands/multi-agent/setup/SKILL.md +25 -181
  23. package/pipeline/commands/multi-agent/stack/SKILL.md +9 -53
  24. package/pipeline/commands/multi-agent/status/SKILL.md +13 -2
  25. package/pipeline/commands/multi-agent/store-ready/SKILL.md +27 -226
  26. package/pipeline/commands/multi-agent/sync/SKILL.md +35 -164
  27. package/pipeline/commands/multi-agent/test-gen/SKILL.md +2 -4
  28. package/pipeline/commands/multi-agent/update/SKILL.md +18 -60
  29. package/pipeline/contract/CHANGELOG.md +9 -0
  30. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  31. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  32. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  33. package/pipeline/contract/fixtures/runs-awaiting-question.json +1 -1
  34. package/pipeline/contract/fixtures/runs-empty.json +1 -1
  35. package/pipeline/contract/fixtures/runs-failed.json +1 -1
  36. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
  37. package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
  38. package/pipeline/contract/fixtures/runs-running.json +1 -1
  39. package/pipeline/contract/manifest.json +5 -5
  40. package/pipeline/contract/types/index.d.ts +3 -2
  41. package/pipeline/multi-agent-refs/audit-guide.md +20 -0
  42. package/pipeline/multi-agent-refs/autopilot-on/details.md +148 -0
  43. package/pipeline/multi-agent-refs/channels/generator.md +14 -0
  44. package/pipeline/multi-agent-refs/channels/preview.md +13 -0
  45. package/pipeline/multi-agent-refs/channels/reference.md +46 -0
  46. package/pipeline/multi-agent-refs/complaint-analysis/phases.md +159 -0
  47. package/pipeline/multi-agent-refs/design-check/export.md +1 -0
  48. package/pipeline/multi-agent-refs/design-check/init-inventory.md +1 -1
  49. package/pipeline/multi-agent-refs/design-check/scope-and-ledger.md +64 -0
  50. package/pipeline/multi-agent-refs/features/analysis-command-notes.md +53 -0
  51. package/pipeline/multi-agent-refs/features/commit-multi-repo.md +63 -0
  52. package/pipeline/multi-agent-refs/features/dev-multi-repo.md +51 -0
  53. package/pipeline/multi-agent-refs/features/test-gap.md +40 -0
  54. package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
  55. package/pipeline/multi-agent-refs/garbage-collect/phases.md +60 -0
  56. package/pipeline/multi-agent-refs/ios-coding-standard/plan.md +71 -0
  57. package/pipeline/multi-agent-refs/ios-coding-standard/resolve-and-scan.md +135 -0
  58. package/pipeline/multi-agent-refs/jira/picker-detail.md +71 -0
  59. package/pipeline/multi-agent-refs/orchestrator/copilot-pipeline.md +88 -0
  60. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +96 -1
  61. package/pipeline/multi-agent-refs/orchestrator/phase-3-user-test.md +12 -9
  62. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +4 -4
  63. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +8 -47
  64. package/pipeline/multi-agent-refs/phases/phase-3-review.md +21 -65
  65. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +9 -59
  66. package/pipeline/multi-agent-refs/phases/phase-5-report.md +0 -31
  67. package/pipeline/multi-agent-refs/refactor/sweep.md +190 -0
  68. package/pipeline/multi-agent-refs/resume/details.md +115 -2
  69. package/pipeline/multi-agent-refs/review/inputs.md +33 -1
  70. package/pipeline/multi-agent-refs/review/module-guides.md +9 -1
  71. package/pipeline/multi-agent-refs/review/panel.md +75 -0
  72. package/pipeline/multi-agent-refs/review/valven.md +5 -1
  73. package/pipeline/multi-agent-refs/rules.md +1 -1
  74. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +4 -0
  75. package/pipeline/multi-agent-refs/setup/token-save-flow.md +13 -0
  76. package/pipeline/multi-agent-refs/stack/background.md +72 -0
  77. package/pipeline/multi-agent-refs/store-ready/gates.md +139 -0
  78. package/pipeline/multi-agent-refs/store-ready/report.md +40 -2
  79. package/pipeline/multi-agent-refs/sync/office.md +10 -0
  80. package/pipeline/multi-agent-refs/sync/overview.md +61 -0
  81. package/pipeline/multi-agent-refs/sync/repo.md +91 -0
  82. package/pipeline/multi-agent-refs/update/details.md +83 -0
  83. package/pipeline/office/index.html +6 -3
  84. package/pipeline/office/toolkit.json +1 -1
  85. package/pipeline/rules/figma-pipeline.md +6 -3
  86. package/pipeline/schemas/prefs.schema.json +1 -1
  87. package/pipeline/schemas/runs-index.schema.json +2 -1
  88. package/pipeline/scripts/_memory-policy.mjs +27 -5
  89. package/pipeline/scripts/checkpoint-fold.sh +59 -0
  90. package/pipeline/scripts/contract-server.mjs +1 -1
  91. package/pipeline/scripts/gate-ledger.mjs +1 -1
  92. package/pipeline/scripts/office-control.mjs +41 -15
  93. package/pipeline/scripts/offload-ref.sh +1 -1
  94. package/pipeline/scripts/rework-rulings.mjs +5 -3
  95. package/pipeline/scripts/runs-index.mjs +34 -7
  96. package/pipeline/scripts/scope-check-gate.mjs +15 -2
  97. package/pipeline/scripts/status-overview.mjs +401 -0
  98. package/pipeline/scripts/user-test-handoff.sh +203 -0
  99. package/pipeline/scripts/validate-planning.mjs +5 -3
  100. package/pipeline/scripts/validate-triage.mjs +2 -1
  101. package/pipeline/scripts/write-state.mjs +13 -4
  102. package/pipeline/skills/.skill-manifest.json +64 -64
  103. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +7 -70
  104. package/pipeline/skills/shared/core/apple-archive-compliance/references/examples.md +67 -0
  105. package/pipeline/skills/shared/core/apple-archive-compliance/references/version-history.md +8 -0
  106. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +10 -72
  107. package/pipeline/skills/shared/core/google-play-compliance/references/examples.md +69 -0
  108. package/pipeline/skills/shared/core/google-play-compliance/references/notes.md +7 -0
  109. package/pipeline/skills/shared/core/google-play-compliance/references/version-history.md +5 -0
  110. package/pipeline/skills/shared/core/multi-agent/SKILL.md +39 -262
  111. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +35 -73
  112. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +37 -337
  113. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +27 -122
  114. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +8 -340
  115. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +37 -180
  116. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +12 -7
  117. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +23 -184
  118. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +14 -82
  119. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +25 -277
  120. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +13 -2
  121. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +73 -217
  122. package/pipeline/skills/shared/external/alarmkit/SKILL.md +11 -162
  123. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-code.md +257 -0
  124. package/pipeline/skills/shared/external/android-architecture/SKILL.md +7 -58
  125. package/pipeline/skills/shared/external/android-architecture/references/code-examples.md +68 -0
  126. package/pipeline/skills/shared/external/app-intents/SKILL.md +3 -45
  127. package/pipeline/skills/shared/external/app-intents/references/code-examples.md +54 -0
  128. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +5 -81
  129. package/pipeline/skills/shared/external/app-store-optimization/references/engagement-and-localization.md +96 -0
  130. package/pipeline/skills/shared/external/app-store-review/SKILL.md +6 -112
  131. package/pipeline/skills/shared/external/app-store-review/references/monetization-and-submission.md +138 -0
  132. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +10 -117
  133. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models-code.md +186 -0
  134. package/pipeline/skills/shared/external/authentication/SKILL.md +3 -50
  135. package/pipeline/skills/shared/external/authentication/references/code-examples.md +59 -0
  136. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +3 -84
  137. package/pipeline/skills/shared/external/callkit-voip/references/code-examples.md +93 -0
  138. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +7 -263
  139. package/pipeline/skills/shared/external/ci-cd-pipelines/references/pipeline-examples.md +281 -0
  140. package/pipeline/skills/shared/external/clean-code/SKILL.md +8 -41
  141. package/pipeline/skills/shared/external/clean-code/references/code-examples.md +56 -0
  142. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +8 -146
  143. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-code.md +214 -0
  144. package/pipeline/skills/shared/external/compose-components/SKILL.md +6 -80
  145. package/pipeline/skills/shared/external/compose-components/references/code-examples.md +89 -0
  146. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +5 -64
  147. package/pipeline/skills/shared/external/compose-navigation/references/code-examples.md +70 -0
  148. package/pipeline/skills/shared/external/core-data/SKILL.md +9 -157
  149. package/pipeline/skills/shared/external/core-data/references/core-data-code.md +221 -0
  150. package/pipeline/skills/shared/external/core-nfc/SKILL.md +3 -89
  151. package/pipeline/skills/shared/external/core-nfc/references/code-examples.md +98 -0
  152. package/pipeline/skills/shared/external/coreml/SKILL.md +17 -133
  153. package/pipeline/skills/shared/external/coreml/references/coreml-code.md +208 -0
  154. package/pipeline/skills/shared/external/css-modern/SKILL.md +8 -131
  155. package/pipeline/skills/shared/external/css-modern/references/code-examples.md +142 -0
  156. package/pipeline/skills/shared/external/database-patterns/SKILL.md +6 -103
  157. package/pipeline/skills/shared/external/database-patterns/references/orm-examples.md +112 -0
  158. package/pipeline/skills/shared/external/html-semantic/SKILL.md +7 -48
  159. package/pipeline/skills/shared/external/html-semantic/references/code-examples.md +54 -0
  160. package/pipeline/skills/shared/external/humanizer/SKILL.md +6 -19
  161. package/pipeline/skills/shared/external/humanizer/references/voice.md +24 -0
  162. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +13 -170
  163. package/pipeline/skills/shared/external/ios-accessibility/references/assistive-tech-review.md +224 -0
  164. package/pipeline/skills/shared/external/ios-localization/SKILL.md +2 -24
  165. package/pipeline/skills/shared/external/ios-localization/references/code-examples.md +30 -0
  166. package/pipeline/skills/shared/external/ios-networking/SKILL.md +3 -58
  167. package/pipeline/skills/shared/external/ios-networking/references/code-examples.md +67 -0
  168. package/pipeline/skills/shared/external/ios-security/SKILL.md +4 -64
  169. package/pipeline/skills/shared/external/ios-security/references/code-examples.md +74 -0
  170. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -90
  171. package/pipeline/skills/shared/external/live-activities/references/code-examples.md +108 -0
  172. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -23
  173. package/pipeline/skills/shared/external/localization-reuse-map/references/project-settings.md +22 -0
  174. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +5 -95
  175. package/pipeline/skills/shared/external/mapkit-location/references/code-examples.md +117 -0
  176. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +7 -106
  177. package/pipeline/skills/shared/external/nextjs-app-router/references/app-router-examples.md +124 -0
  178. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -31
  179. package/pipeline/skills/shared/external/permissionkit/references/code-examples.md +37 -0
  180. package/pipeline/skills/shared/external/play-store-review/SKILL.md +6 -74
  181. package/pipeline/skills/shared/external/play-store-review/references/signing-and-policies.md +83 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -125
  183. package/pipeline/skills/shared/external/push-notifications/references/notification-code.md +176 -0
  184. package/pipeline/skills/shared/external/python-patterns/SKILL.md +7 -158
  185. package/pipeline/skills/shared/external/python-patterns/references/python-examples.md +176 -0
  186. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +7 -157
  187. package/pipeline/skills/shared/external/rest-api-design/references/api-examples.md +175 -0
  188. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +11 -230
  189. package/pipeline/skills/shared/external/swift-architecture/references/pattern-examples.md +295 -0
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +17 -149
  191. package/pipeline/skills/shared/external/swift-codable/references/codable-recipes.md +207 -0
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +12 -99
  193. package/pipeline/skills/shared/external/swift-concurrency/references/code-examples.md +100 -0
  194. package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-additions.md +18 -0
  195. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +9 -78
  196. package/pipeline/skills/shared/external/swift-formatstyle/references/formatstyle-examples.md +113 -0
  197. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -56
  198. package/pipeline/skills/shared/external/swift-language/references/code-examples.md +65 -0
  199. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +1 -0
  200. package/pipeline/skills/shared/external/swiftdata/SKILL.md +6 -122
  201. package/pipeline/skills/shared/external/swiftdata/references/code-examples.md +140 -0
  202. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +12 -139
  203. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/interop-code.md +198 -0
  204. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +9 -81
  205. package/pipeline/skills/shared/external/tailwind-css/references/code-examples.md +91 -0
  206. package/pipeline/skills/shared/external/testing-backend/SKILL.md +7 -207
  207. package/pipeline/skills/shared/external/testing-backend/references/testing-examples.md +225 -0
  208. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +8 -89
  209. package/pipeline/skills/shared/external/typescript-patterns/references/code-examples.md +100 -0
  210. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -20
  211. package/pipeline/skills/shared/external/vision-framework/references/code-examples.md +26 -0
  212. package/pipeline/skills/shared/external/vue-composition/SKILL.md +7 -169
  213. package/pipeline/skills/shared/external/vue-composition/references/vue-examples.md +187 -0
  214. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +7 -174
  215. package/pipeline/skills/shared/external/web-accessibility/references/a11y-examples.md +192 -0
  216. package/pipeline/skills/shared/external/web-performance/SKILL.md +8 -66
  217. package/pipeline/skills/shared/external/web-performance/references/code-examples.md +77 -0
  218. package/pipeline/skills/shared/external/web-testing/SKILL.md +11 -186
  219. package/pipeline/skills/shared/external/web-testing/references/testing-examples.md +213 -0
  220. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/format-and-output.md +0 -0
  221. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/publish-and-snapshot.md +0 -0
  222. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/sources-and-recipes.md +0 -0
@@ -209,150 +209,11 @@ describe('useCounter', () => {
209
209
 
210
210
  ## MSW (Mock Service Worker)
211
211
 
212
- ```typescript
213
- // src/mocks/handlers.ts
214
- import { http, HttpResponse } from 'msw';
215
-
216
- export const handlers = [
217
- http.get('/api/users', () => {
218
- return HttpResponse.json([
219
- { id: '1', name: 'Alice', email: 'alice@example.com' },
220
- { id: '2', name: 'Bob', email: 'bob@example.com' },
221
- ]);
222
- }),
223
-
224
- http.get('/api/users/:id', ({ params }) => {
225
- const { id } = params;
226
- if (id === '999') {
227
- return new HttpResponse(null, { status: 404 });
228
- }
229
- return HttpResponse.json({ id, name: 'Alice', email: 'alice@example.com' });
230
- }),
231
-
232
- http.post('/api/users', async ({ request }) => {
233
- const body = await request.json();
234
- return HttpResponse.json({ id: '3', ...body }, { status: 201 });
235
- }),
236
-
237
- http.delete('/api/users/:id', () => {
238
- return new HttpResponse(null, { status: 204 });
239
- }),
240
- ];
241
-
242
- // src/mocks/server.ts
243
- import { setupServer } from 'msw/node';
244
- import { handlers } from './handlers';
245
-
246
- export const server = setupServer(...handlers);
247
-
248
- // src/test/setup.ts
249
- import { server } from '../mocks/server';
250
-
251
- beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
252
- afterEach(() => server.resetHandlers());
253
- afterAll(() => server.close());
254
- ```
255
-
256
- ```tsx
257
- // Using MSW in tests with per-test overrides
258
- import { http, HttpResponse } from 'msw';
259
- import { server } from '../mocks/server';
260
-
261
- describe('UserList', () => {
262
- it('shows error state on API failure', async () => {
263
- // Override handler for this test only
264
- server.use(
265
- http.get('/api/users', () => {
266
- return new HttpResponse(null, { status: 500 });
267
- })
268
- );
269
-
270
- render(<UserList />);
271
- expect(await screen.findByText(/failed to load/i)).toBeInTheDocument();
272
- });
273
- });
274
- ```
212
+ Code for this section: [Web testing examples](references/testing-examples.md).
275
213
 
276
214
  ## Playwright (E2E Testing)
277
215
 
278
- ```typescript
279
- // playwright.config.ts
280
- import { defineConfig, devices } from '@playwright/test';
281
-
282
- export default defineConfig({
283
- testDir: './e2e',
284
- fullyParallel: true,
285
- forbidOnly: !!process.env.CI,
286
- retries: process.env.CI ? 2 : 0,
287
- workers: process.env.CI ? 1 : undefined,
288
- reporter: 'html',
289
- use: {
290
- baseURL: 'http://localhost:3000',
291
- trace: 'on-first-retry',
292
- screenshot: 'only-on-failure',
293
- },
294
- projects: [
295
- { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
296
- { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
297
- { name: 'mobile', use: { ...devices['iPhone 14'] } },
298
- ],
299
- webServer: {
300
- command: 'npm run dev',
301
- url: 'http://localhost:3000',
302
- reuseExistingServer: !process.env.CI,
303
- },
304
- });
305
- ```
306
-
307
- ```typescript
308
- // e2e/auth.spec.ts
309
- import { test, expect } from '@playwright/test';
310
-
311
- test.describe('Authentication', () => {
312
- test('successful login redirects to dashboard', async ({ page }) => {
313
- await page.goto('/login');
314
-
315
- await page.getByLabel('Email').fill('user@example.com');
316
- await page.getByLabel('Password').fill('password123');
317
- await page.getByRole('button', { name: 'Sign in' }).click();
318
-
319
- await expect(page).toHaveURL('/dashboard');
320
- await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
321
- });
322
-
323
- test('shows error for invalid credentials', async ({ page }) => {
324
- await page.goto('/login');
325
-
326
- await page.getByLabel('Email').fill('wrong@example.com');
327
- await page.getByLabel('Password').fill('wrongpass');
328
- await page.getByRole('button', { name: 'Sign in' }).click();
329
-
330
- await expect(page.getByText('Invalid credentials')).toBeVisible();
331
- await expect(page).toHaveURL('/login');
332
- });
333
- });
334
-
335
- // e2e/checkout.spec.ts
336
- test('completes checkout flow', async ({ page }) => {
337
- await page.goto('/products');
338
-
339
- // Add item to cart
340
- await page.getByRole('button', { name: 'Add to cart' }).first().click();
341
- await expect(page.getByTestId('cart-count')).toHaveText('1');
342
-
343
- // Navigate to checkout
344
- await page.getByRole('link', { name: 'Cart' }).click();
345
- await page.getByRole('button', { name: 'Checkout' }).click();
346
-
347
- // Fill shipping info
348
- await page.getByLabel('Address').fill('123 Main St');
349
- await page.getByLabel('City').fill('New York');
350
- await page.getByRole('button', { name: 'Place order' }).click();
351
-
352
- // Verify confirmation
353
- await expect(page.getByText('Order confirmed')).toBeVisible();
354
- });
355
- ```
216
+ Code for this section: [Web testing examples](references/testing-examples.md).
356
217
 
357
218
  ### Structure, error states and time
358
219
 
@@ -360,56 +221,16 @@ test('completes checkout flow', async ({ page }) => {
360
221
  is a subset by default: list what must be there, in order, and leave out the rest.
361
222
  Names take a regex, so localized copy does not break it.
362
223
 
363
- ```typescript
364
- test('orders page structure', async ({ page }) => {
365
- await page.goto('/orders');
366
- await expect(page.getByRole('main')).toMatchAriaSnapshot(`
367
- - heading "Orders" [level=1]
368
- - list:
369
- - listitem: /Order #\\d+/
370
- - button /Save|Kaydet/
371
- `);
372
- });
373
- ```
224
+ Error and empty states come from the network layer, not from a seeded backend.
374
225
 
375
- Error and empty states come from the network layer, not from a seeded backend:
376
-
377
- ```typescript
378
- test('shows the empty state', async ({ page }) => {
379
- await page.route('**/api/orders*', (route) => route.fulfill({ json: [] }));
380
- await page.goto('/orders');
381
- await expect(page.getByText('No orders yet')).toBeVisible();
382
- });
383
-
384
- test('shows the retry banner on a server error', async ({ page }) => {
385
- await page.route('**/api/orders*', (route) => route.fulfill({ status: 500, body: 'boom' }));
386
- await page.goto('/orders');
387
- await expect(page.getByRole('button', { name: 'Retry' })).toBeVisible();
388
- });
389
-
390
- test('goes offline gracefully', async ({ page, context }) => {
391
- await page.goto('/orders');
392
- await context.setOffline(true);
393
- await page.getByRole('button', { name: 'Refresh' }).click();
394
- await expect(page.getByText('You are offline')).toBeVisible();
395
- });
396
- ```
397
-
398
- Session expiry, countdowns and dates use the clock instead of waiting:
399
-
400
- ```typescript
401
- test('logs out after 30 idle minutes', async ({ page }) => {
402
- await page.clock.install({ time: new Date('2026-01-01T09:00:00') });
403
- await page.goto('/dashboard');
404
- await page.clock.fastForward('30:00');
405
- await expect(page).toHaveURL('/login');
406
- });
407
- ```
226
+ Session expiry, countdowns and dates use the clock instead of waiting.
408
227
 
409
228
  The multi-agent-toolkit MCP server exposes the same capabilities to an agent
410
229
  driving a live browser (`web_route`, `web_network_state`, `web_clock`,
411
230
  `web_assert_aria`); `web_generate_locator` turns a snapshot ref into the
412
- `getByRole` / `getByTestId` locator to paste into a spec like the ones above.
231
+ `getByRole` / `getByTestId` locator to paste into a spec like the ones in the reference.
232
+
233
+ Code for this section: [Web testing examples](references/testing-examples.md).
413
234
 
414
235
  ## Do's
415
236
 
@@ -443,3 +264,7 @@ driving a live browser (`web_route`, `web_network_state`, `web_clock`,
443
264
  | Playwright timeout | Slow page load or wrong selector | Increase timeout, use more specific locators |
444
265
  | Snapshot test breaks on every change | Testing too much visual detail | Narrow snapshot scope or use targeted assertions |
445
266
  | "act() warning" | State update outside act | Wrap state updates in `act()` or use `findBy` queries |
267
+
268
+ ## References
269
+
270
+ - [Web testing examples](references/testing-examples.md): open when setting up MSW handlers or writing Playwright tests.
@@ -0,0 +1,213 @@
1
+ # Web testing examples
2
+
3
+ <!-- toc -->
4
+ - [MSW (Mock Service Worker)](#msw-mock-service-worker)
5
+ - [Playwright (E2E Testing)](#playwright-e2e-testing)
6
+ - [Structure, error states and time](#structure-error-states-and-time)
7
+ <!-- /toc -->
8
+
9
+ Full code for MSW handlers and Playwright end-to-end tests, including page objects, error states and time control. SKILL.md keeps the pyramid, the rules and troubleshooting.
10
+
11
+ ## MSW (Mock Service Worker)
12
+
13
+ ```typescript
14
+ // src/mocks/handlers.ts
15
+ import { http, HttpResponse } from 'msw';
16
+
17
+ export const handlers = [
18
+ http.get('/api/users', () => {
19
+ return HttpResponse.json([
20
+ { id: '1', name: 'Alice', email: 'alice@example.com' },
21
+ { id: '2', name: 'Bob', email: 'bob@example.com' },
22
+ ]);
23
+ }),
24
+
25
+ http.get('/api/users/:id', ({ params }) => {
26
+ const { id } = params;
27
+ if (id === '999') {
28
+ return new HttpResponse(null, { status: 404 });
29
+ }
30
+ return HttpResponse.json({ id, name: 'Alice', email: 'alice@example.com' });
31
+ }),
32
+
33
+ http.post('/api/users', async ({ request }) => {
34
+ const body = await request.json();
35
+ return HttpResponse.json({ id: '3', ...body }, { status: 201 });
36
+ }),
37
+
38
+ http.delete('/api/users/:id', () => {
39
+ return new HttpResponse(null, { status: 204 });
40
+ }),
41
+ ];
42
+
43
+ // src/mocks/server.ts
44
+ import { setupServer } from 'msw/node';
45
+ import { handlers } from './handlers';
46
+
47
+ export const server = setupServer(...handlers);
48
+
49
+ // src/test/setup.ts
50
+ import { server } from '../mocks/server';
51
+
52
+ beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
53
+ afterEach(() => server.resetHandlers());
54
+ afterAll(() => server.close());
55
+ ```
56
+
57
+ ```tsx
58
+ // Using MSW in tests with per-test overrides
59
+ import { http, HttpResponse } from 'msw';
60
+ import { server } from '../mocks/server';
61
+
62
+ describe('UserList', () => {
63
+ it('shows error state on API failure', async () => {
64
+ // Override handler for this test only
65
+ server.use(
66
+ http.get('/api/users', () => {
67
+ return new HttpResponse(null, { status: 500 });
68
+ })
69
+ );
70
+
71
+ render(<UserList />);
72
+ expect(await screen.findByText(/failed to load/i)).toBeInTheDocument();
73
+ });
74
+ });
75
+ ```
76
+
77
+ ## Playwright (E2E Testing)
78
+
79
+ ```typescript
80
+ // playwright.config.ts
81
+ import { defineConfig, devices } from '@playwright/test';
82
+
83
+ export default defineConfig({
84
+ testDir: './e2e',
85
+ fullyParallel: true,
86
+ forbidOnly: !!process.env.CI,
87
+ retries: process.env.CI ? 2 : 0,
88
+ workers: process.env.CI ? 1 : undefined,
89
+ reporter: 'html',
90
+ use: {
91
+ baseURL: 'http://localhost:3000',
92
+ trace: 'on-first-retry',
93
+ screenshot: 'only-on-failure',
94
+ },
95
+ projects: [
96
+ { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
97
+ { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
98
+ { name: 'mobile', use: { ...devices['iPhone 14'] } },
99
+ ],
100
+ webServer: {
101
+ command: 'npm run dev',
102
+ url: 'http://localhost:3000',
103
+ reuseExistingServer: !process.env.CI,
104
+ },
105
+ });
106
+ ```
107
+
108
+ ```typescript
109
+ // e2e/auth.spec.ts
110
+ import { test, expect } from '@playwright/test';
111
+
112
+ test.describe('Authentication', () => {
113
+ test('successful login redirects to dashboard', async ({ page }) => {
114
+ await page.goto('/login');
115
+
116
+ await page.getByLabel('Email').fill('user@example.com');
117
+ await page.getByLabel('Password').fill('password123');
118
+ await page.getByRole('button', { name: 'Sign in' }).click();
119
+
120
+ await expect(page).toHaveURL('/dashboard');
121
+ await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
122
+ });
123
+
124
+ test('shows error for invalid credentials', async ({ page }) => {
125
+ await page.goto('/login');
126
+
127
+ await page.getByLabel('Email').fill('wrong@example.com');
128
+ await page.getByLabel('Password').fill('wrongpass');
129
+ await page.getByRole('button', { name: 'Sign in' }).click();
130
+
131
+ await expect(page.getByText('Invalid credentials')).toBeVisible();
132
+ await expect(page).toHaveURL('/login');
133
+ });
134
+ });
135
+
136
+ // e2e/checkout.spec.ts
137
+ test('completes checkout flow', async ({ page }) => {
138
+ await page.goto('/products');
139
+
140
+ // Add item to cart
141
+ await page.getByRole('button', { name: 'Add to cart' }).first().click();
142
+ await expect(page.getByTestId('cart-count')).toHaveText('1');
143
+
144
+ // Navigate to checkout
145
+ await page.getByRole('link', { name: 'Cart' }).click();
146
+ await page.getByRole('button', { name: 'Checkout' }).click();
147
+
148
+ // Fill shipping info
149
+ await page.getByLabel('Address').fill('123 Main St');
150
+ await page.getByLabel('City').fill('New York');
151
+ await page.getByRole('button', { name: 'Place order' }).click();
152
+
153
+ // Verify confirmation
154
+ await expect(page.getByText('Order confirmed')).toBeVisible();
155
+ });
156
+ ```
157
+
158
+ ### Structure, error states and time
159
+
160
+ `toMatchAriaSnapshot` checks a region's structure in one assertion. The template
161
+ is a subset by default: list what must be there, in order, and leave out the rest.
162
+ Names take a regex, so localized copy does not break it.
163
+
164
+ ```typescript
165
+ test('orders page structure', async ({ page }) => {
166
+ await page.goto('/orders');
167
+ await expect(page.getByRole('main')).toMatchAriaSnapshot(`
168
+ - heading "Orders" [level=1]
169
+ - list:
170
+ - listitem: /Order #\\d+/
171
+ - button /Save|Kaydet/
172
+ `);
173
+ });
174
+ ```
175
+
176
+ Error and empty states come from the network layer, not from a seeded backend:
177
+
178
+ ```typescript
179
+ test('shows the empty state', async ({ page }) => {
180
+ await page.route('**/api/orders*', (route) => route.fulfill({ json: [] }));
181
+ await page.goto('/orders');
182
+ await expect(page.getByText('No orders yet')).toBeVisible();
183
+ });
184
+
185
+ test('shows the retry banner on a server error', async ({ page }) => {
186
+ await page.route('**/api/orders*', (route) => route.fulfill({ status: 500, body: 'boom' }));
187
+ await page.goto('/orders');
188
+ await expect(page.getByRole('button', { name: 'Retry' })).toBeVisible();
189
+ });
190
+
191
+ test('goes offline gracefully', async ({ page, context }) => {
192
+ await page.goto('/orders');
193
+ await context.setOffline(true);
194
+ await page.getByRole('button', { name: 'Refresh' }).click();
195
+ await expect(page.getByText('You are offline')).toBeVisible();
196
+ });
197
+ ```
198
+
199
+ Session expiry, countdowns and dates use the clock instead of waiting:
200
+
201
+ ```typescript
202
+ test('logs out after 30 idle minutes', async ({ page }) => {
203
+ await page.clock.install({ time: new Date('2026-01-01T09:00:00') });
204
+ await page.goto('/dashboard');
205
+ await page.clock.fastForward('30:00');
206
+ await expect(page).toHaveURL('/login');
207
+ });
208
+ ```
209
+
210
+ The multi-agent-toolkit MCP server exposes the same capabilities to an agent
211
+ driving a live browser (`web_route`, `web_network_state`, `web_clock`,
212
+ `web_assert_aria`); `web_generate_locator` turns a snapshot ref into the
213
+ `getByRole` / `getByTestId` locator to paste into a spec like the ones above.