@arcadialdev/arcality 2.2.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 (97) hide show
  1. package/.agents/skills/e2e-testing-expert/SKILL.md +28 -0
  2. package/.agents/skills/frontend-design/LICENSE.txt +177 -0
  3. package/.agents/skills/frontend-design/SKILL.md +42 -0
  4. package/.agents/skills/nodejs-backend-patterns/SKILL.md +639 -0
  5. package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
  6. package/.agents/skills/playwright-best-practices/LICENSE.md +7 -0
  7. package/.agents/skills/playwright-best-practices/README.md +147 -0
  8. package/.agents/skills/playwright-best-practices/SKILL.md +303 -0
  9. package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +360 -0
  10. package/.agents/skills/playwright-best-practices/advanced/authentication.md +871 -0
  11. package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +364 -0
  12. package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +409 -0
  13. package/.agents/skills/playwright-best-practices/advanced/multi-context.md +288 -0
  14. package/.agents/skills/playwright-best-practices/advanced/multi-user.md +393 -0
  15. package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +452 -0
  16. package/.agents/skills/playwright-best-practices/advanced/third-party.md +464 -0
  17. package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +363 -0
  18. package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +369 -0
  19. package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +383 -0
  20. package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +391 -0
  21. package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +403 -0
  22. package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +504 -0
  23. package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +403 -0
  24. package/.agents/skills/playwright-best-practices/core/annotations.md +424 -0
  25. package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +361 -0
  26. package/.agents/skills/playwright-best-practices/core/configuration.md +452 -0
  27. package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +417 -0
  28. package/.agents/skills/playwright-best-practices/core/global-setup.md +434 -0
  29. package/.agents/skills/playwright-best-practices/core/locators.md +242 -0
  30. package/.agents/skills/playwright-best-practices/core/page-object-model.md +315 -0
  31. package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +453 -0
  32. package/.agents/skills/playwright-best-practices/core/test-data.md +492 -0
  33. package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +361 -0
  34. package/.agents/skills/playwright-best-practices/core/test-tags.md +298 -0
  35. package/.agents/skills/playwright-best-practices/debugging/console-errors.md +420 -0
  36. package/.agents/skills/playwright-best-practices/debugging/debugging.md +504 -0
  37. package/.agents/skills/playwright-best-practices/debugging/error-testing.md +360 -0
  38. package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +496 -0
  39. package/.agents/skills/playwright-best-practices/frameworks/angular.md +530 -0
  40. package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +469 -0
  41. package/.agents/skills/playwright-best-practices/frameworks/react.md +531 -0
  42. package/.agents/skills/playwright-best-practices/frameworks/vue.md +574 -0
  43. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +468 -0
  44. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +283 -0
  45. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +546 -0
  46. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +397 -0
  47. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +521 -0
  48. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +371 -0
  49. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +453 -0
  50. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +424 -0
  51. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +497 -0
  52. package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +359 -0
  53. package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +719 -0
  54. package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +506 -0
  55. package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +493 -0
  56. package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +500 -0
  57. package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +576 -0
  58. package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +509 -0
  59. package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +377 -0
  60. package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +562 -0
  61. package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +561 -0
  62. package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +331 -0
  63. package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +508 -0
  64. package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +476 -0
  65. package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +430 -0
  66. package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +634 -0
  67. package/.env.example +21 -0
  68. package/README.md +30 -0
  69. package/bin/arcality.mjs +86 -0
  70. package/package.json +66 -0
  71. package/playwright.config.ts +12 -0
  72. package/scripts/cleanup-qmsdev.mjs +63 -0
  73. package/scripts/discover-view.mjs +52 -0
  74. package/scripts/extract-view.mjs +64 -0
  75. package/scripts/gen-and-run.mjs +838 -0
  76. package/scripts/init.mjs +290 -0
  77. package/scripts/migrate-to-central-out.mjs +157 -0
  78. package/scripts/postinstall.mjs +63 -0
  79. package/scripts/rebrand-report.mjs +241 -0
  80. package/scripts/setup.mjs +166 -0
  81. package/src/KnowledgeService.ts +239 -0
  82. package/src/arcalityClient.mjs +266 -0
  83. package/src/configLoader.mjs +179 -0
  84. package/src/configManager.mjs +172 -0
  85. package/src/consoleBanner.ts +32 -0
  86. package/src/envSetup.ts +205 -0
  87. package/src/index.ts +25 -0
  88. package/src/projectInspector.ts +42 -0
  89. package/src/services/collectiveMemoryService.ts +178 -0
  90. package/src/testRunner.ts +201 -0
  91. package/tests/_helpers/ArcalityReporter.ts +490 -0
  92. package/tests/_helpers/agentic-runner.spec.ts +741 -0
  93. package/tests/_helpers/ai-agent-helper.ts +1573 -0
  94. package/tests/_helpers/discover-view.spec.ts +238 -0
  95. package/tests/_helpers/extract-view.spec.ts +118 -0
  96. package/tests/_helpers/qa-tools.ts +333 -0
  97. package/tests/_helpers/smart-action.spec.ts +1458 -0
@@ -0,0 +1,504 @@
1
+ # Service Worker Testing
2
+
3
+ ## Table of Contents
4
+
5
+ 1. [Service Worker Basics](#service-worker-basics)
6
+ 2. [Registration & Lifecycle](#registration--lifecycle)
7
+ 3. [Cache Testing](#cache-testing)
8
+ 4. [Offline Testing](#offline-testing)
9
+ 5. [Push Notifications](#push-notifications)
10
+ 6. [Background Sync](#background-sync)
11
+
12
+ ## Service Worker Basics
13
+
14
+ ### Waiting for Service Worker Registration
15
+
16
+ ```typescript
17
+ test("service worker registers", async ({ page }) => {
18
+ await page.goto("/pwa-app");
19
+
20
+ // Wait for SW to register
21
+ const swRegistered = await page.evaluate(async () => {
22
+ if (!("serviceWorker" in navigator)) return false;
23
+
24
+ const registration = await navigator.serviceWorker.ready;
25
+ return !!registration.active;
26
+ });
27
+
28
+ expect(swRegistered).toBe(true);
29
+ });
30
+ ```
31
+
32
+ ### Getting Service Worker State
33
+
34
+ ```typescript
35
+ test("check SW state", async ({ page }) => {
36
+ await page.goto("/");
37
+
38
+ const swState = await page.evaluate(async () => {
39
+ const registration = await navigator.serviceWorker.getRegistration();
40
+ if (!registration) return null;
41
+
42
+ return {
43
+ installing: !!registration.installing,
44
+ waiting: !!registration.waiting,
45
+ active: !!registration.active,
46
+ scope: registration.scope,
47
+ };
48
+ });
49
+
50
+ expect(swState?.active).toBe(true);
51
+ expect(swState?.scope).toContain(page.url());
52
+ });
53
+ ```
54
+
55
+ ### Service Worker Context
56
+
57
+ ```typescript
58
+ test("access service worker", async ({ context, page }) => {
59
+ await page.goto("/pwa-app");
60
+
61
+ // Get all service workers in context
62
+ const workers = context.serviceWorkers();
63
+
64
+ // Wait for service worker if not yet available
65
+ if (workers.length === 0) {
66
+ await context.waitForEvent("serviceworker");
67
+ }
68
+
69
+ const sw = context.serviceWorkers()[0];
70
+ expect(sw.url()).toContain("sw.js");
71
+ });
72
+ ```
73
+
74
+ ## Registration & Lifecycle
75
+
76
+ ### Testing SW Update Flow
77
+
78
+ ```typescript
79
+ test("service worker updates", async ({ page }) => {
80
+ await page.goto("/pwa-app");
81
+
82
+ // Check for update
83
+ const hasUpdate = await page.evaluate(async () => {
84
+ const registration = await navigator.serviceWorker.ready;
85
+ await registration.update();
86
+
87
+ return new Promise<boolean>((resolve) => {
88
+ if (registration.waiting) {
89
+ resolve(true);
90
+ } else {
91
+ registration.addEventListener("updatefound", () => {
92
+ resolve(true);
93
+ });
94
+ // Timeout if no update
95
+ setTimeout(() => resolve(false), 5000);
96
+ }
97
+ });
98
+ });
99
+
100
+ // If update found, test skip waiting flow
101
+ if (hasUpdate) {
102
+ await page.evaluate(async () => {
103
+ const registration = await navigator.serviceWorker.ready;
104
+ registration.waiting?.postMessage({ type: "SKIP_WAITING" });
105
+ });
106
+
107
+ // Wait for controller change
108
+ await page.evaluate(() => {
109
+ return new Promise<void>((resolve) => {
110
+ navigator.serviceWorker.addEventListener("controllerchange", () => {
111
+ resolve();
112
+ });
113
+ });
114
+ });
115
+ }
116
+ });
117
+ ```
118
+
119
+ ### Testing SW Installation
120
+
121
+ ```typescript
122
+ test("verify SW install event", async ({ context, page }) => {
123
+ // Listen for service worker before navigating
124
+ const swPromise = context.waitForEvent("serviceworker");
125
+
126
+ await page.goto("/pwa-app");
127
+
128
+ const sw = await swPromise;
129
+
130
+ // Evaluate in SW context
131
+ const swVersion = await sw.evaluate(() => {
132
+ // Access SW globals
133
+ return (self as any).SW_VERSION || "unknown";
134
+ });
135
+
136
+ expect(swVersion).toBe("1.0.0");
137
+ });
138
+ ```
139
+
140
+ ### Unregistering Service Workers
141
+
142
+ ```typescript
143
+ test.beforeEach(async ({ page }) => {
144
+ await page.goto("/");
145
+
146
+ // Unregister all service workers for clean state
147
+ await page.evaluate(async () => {
148
+ const registrations = await navigator.serviceWorker.getRegistrations();
149
+ await Promise.all(registrations.map((r) => r.unregister()));
150
+ });
151
+
152
+ // Clear caches
153
+ await page.evaluate(async () => {
154
+ const cacheNames = await caches.keys();
155
+ await Promise.all(cacheNames.map((name) => caches.delete(name)));
156
+ });
157
+ });
158
+ ```
159
+
160
+ ## Cache Testing
161
+
162
+ ### Verifying Cached Resources
163
+
164
+ ```typescript
165
+ test("assets are cached", async ({ page }) => {
166
+ await page.goto("/pwa-app");
167
+
168
+ // Wait for SW to cache assets
169
+ await page.evaluate(async () => {
170
+ await navigator.serviceWorker.ready;
171
+ });
172
+
173
+ // Check cache contents
174
+ const cachedUrls = await page.evaluate(async () => {
175
+ const cache = await caches.open("app-cache-v1");
176
+ const requests = await cache.keys();
177
+ return requests.map((r) => r.url);
178
+ });
179
+
180
+ expect(cachedUrls).toContain(expect.stringContaining("/styles.css"));
181
+ expect(cachedUrls).toContain(expect.stringContaining("/app.js"));
182
+ });
183
+ ```
184
+
185
+ ### Testing Cache Strategies
186
+
187
+ ```typescript
188
+ test("cache-first strategy", async ({ page }) => {
189
+ await page.goto("/pwa-app");
190
+
191
+ // Wait for initial cache
192
+ await page.waitForFunction(async () => {
193
+ const cache = await caches.open("app-cache-v1");
194
+ const keys = await cache.keys();
195
+ return keys.length > 0;
196
+ });
197
+
198
+ // Block network for cached resources
199
+ await page.route("**/styles.css", (route) => route.abort());
200
+
201
+ // Reload - should work from cache
202
+ await page.reload();
203
+
204
+ // Verify page still styled (CSS loaded from cache)
205
+ const hasStyles = await page.evaluate(() => {
206
+ const body = document.body;
207
+ const styles = window.getComputedStyle(body);
208
+ return styles.fontFamily !== ""; // Has custom font from CSS
209
+ });
210
+
211
+ expect(hasStyles).toBe(true);
212
+ });
213
+ ```
214
+
215
+ ### Testing Cache Updates
216
+
217
+ ```typescript
218
+ test("cache updates on new version", async ({ page }) => {
219
+ await page.goto("/pwa-app");
220
+
221
+ // Get initial cache
222
+ const initialCacheKeys = await page.evaluate(async () => {
223
+ const cache = await caches.open("app-cache-v1");
224
+ const keys = await cache.keys();
225
+ return keys.map((r) => r.url);
226
+ });
227
+
228
+ // Simulate app update by mocking SW response
229
+ await page.route("**/sw.js", (route) => {
230
+ route.fulfill({
231
+ contentType: "application/javascript",
232
+ body: `
233
+ const VERSION = 'v2';
234
+ self.addEventListener('install', (e) => {
235
+ e.waitUntil(caches.open('app-cache-v2'));
236
+ self.skipWaiting();
237
+ });
238
+ `,
239
+ });
240
+ });
241
+
242
+ // Trigger update
243
+ await page.evaluate(async () => {
244
+ const reg = await navigator.serviceWorker.ready;
245
+ await reg.update();
246
+ });
247
+
248
+ // Verify new cache exists
249
+ await page.waitForFunction(async () => {
250
+ return await caches.has("app-cache-v2");
251
+ });
252
+ });
253
+ ```
254
+
255
+ ## Offline Testing
256
+
257
+ This section covers **offline-first apps (PWAs)** that are designed to work offline using service workers, caching, and background sync. For testing **unexpected network failures** (error recovery, graceful degradation), see [error-testing.md](error-testing.md#offline-testing).
258
+
259
+ ### Simulating Offline Mode
260
+
261
+ ```typescript
262
+ test("app works offline", async ({ page, context }) => {
263
+ await page.goto("/pwa-app");
264
+
265
+ // Ensure SW is active and content cached
266
+ await page.evaluate(async () => {
267
+ await navigator.serviceWorker.ready;
268
+ });
269
+ await page.waitForTimeout(1000); // Allow caching to complete
270
+
271
+ // Go offline
272
+ await context.setOffline(true);
273
+
274
+ // Navigate to cached page
275
+ await page.reload();
276
+
277
+ // Verify content loads
278
+ await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
279
+
280
+ // Verify offline indicator
281
+ await expect(page.locator(".offline-badge")).toBeVisible();
282
+
283
+ // Go back online
284
+ await context.setOffline(false);
285
+ await expect(page.locator(".offline-badge")).not.toBeVisible();
286
+ });
287
+ ```
288
+
289
+ ### Testing Offline Fallback
290
+
291
+ ```typescript
292
+ test("shows offline page for uncached routes", async ({ page, context }) => {
293
+ await page.goto("/pwa-app");
294
+ await page.evaluate(() => navigator.serviceWorker.ready);
295
+
296
+ // Go offline
297
+ await context.setOffline(true);
298
+
299
+ // Navigate to uncached page
300
+ await page.goto("/uncached-page");
301
+
302
+ // Should show offline fallback
303
+ await expect(page.getByText("You are offline")).toBeVisible();
304
+ await expect(page.getByRole("button", { name: "Retry" })).toBeVisible();
305
+ });
306
+ ```
307
+
308
+ ### Testing Offline Form Submission
309
+
310
+ ```typescript
311
+ test("queues form submission offline", async ({ page, context }) => {
312
+ await page.goto("/pwa-app/form");
313
+
314
+ // Go offline
315
+ await context.setOffline(true);
316
+
317
+ // Submit form
318
+ await page.getByLabel("Message").fill("Offline message");
319
+ await page.getByRole("button", { name: "Send" }).click();
320
+
321
+ // Should show queued status
322
+ await expect(page.getByText("Queued for sync")).toBeVisible();
323
+
324
+ // Go online
325
+ await context.setOffline(false);
326
+
327
+ // Trigger sync (or wait for automatic)
328
+ await page.evaluate(async () => {
329
+ const reg = await navigator.serviceWorker.ready;
330
+ // Manually trigger sync for testing
331
+ await (reg as any).sync?.register("form-sync");
332
+ });
333
+
334
+ // Verify submission completed
335
+ await expect(page.getByText("Message sent")).toBeVisible({ timeout: 10000 });
336
+ });
337
+ ```
338
+
339
+ ## Push Notifications
340
+
341
+ ### Mocking Push Subscription
342
+
343
+ ```typescript
344
+ test("handles push subscription", async ({ page, context }) => {
345
+ // Grant notification permission
346
+ await context.grantPermissions(["notifications"]);
347
+
348
+ await page.goto("/pwa-app");
349
+
350
+ // Subscribe to push
351
+ const subscription = await page.evaluate(async () => {
352
+ const reg = await navigator.serviceWorker.ready;
353
+ const sub = await reg.pushManager.subscribe({
354
+ userVisibleOnly: true,
355
+ applicationServerKey: "test-key",
356
+ });
357
+ return sub.toJSON();
358
+ });
359
+
360
+ expect(subscription.endpoint).toBeDefined();
361
+ });
362
+ ```
363
+
364
+ ### Testing Push Message Handling
365
+
366
+ ```typescript
367
+ test("handles push notification", async ({ context, page }) => {
368
+ await context.grantPermissions(["notifications"]);
369
+ await page.goto("/pwa-app");
370
+
371
+ // Wait for SW
372
+ const swPromise = context.waitForEvent("serviceworker");
373
+ const sw = await swPromise;
374
+
375
+ // Simulate push message to service worker
376
+ await sw.evaluate(async () => {
377
+ // Dispatch push event
378
+ const pushEvent = new PushEvent("push", {
379
+ data: new PushMessageData(
380
+ JSON.stringify({ title: "Test", body: "Push message" }),
381
+ ),
382
+ });
383
+ self.dispatchEvent(pushEvent);
384
+ });
385
+
386
+ // Note: Actual notification display testing is limited in Playwright
387
+ // Focus on verifying the SW handles the push correctly
388
+ });
389
+ ```
390
+
391
+ ### Testing Notification Click
392
+
393
+ ```typescript
394
+ test("notification click opens page", async ({ context, page }) => {
395
+ await context.grantPermissions(["notifications"]);
396
+ await page.goto("/pwa-app");
397
+
398
+ // Store notification URL target
399
+ let notificationUrl = "";
400
+
401
+ // Listen for new pages (notification click opens new page)
402
+ context.on("page", (newPage) => {
403
+ notificationUrl = newPage.url();
404
+ });
405
+
406
+ // Trigger notification via SW
407
+ await page.evaluate(async () => {
408
+ const reg = await navigator.serviceWorker.ready;
409
+ await reg.showNotification("Test", {
410
+ body: "Click me",
411
+ data: { url: "/notification-target" },
412
+ });
413
+ });
414
+
415
+ // Simulate clicking notification (via SW)
416
+ const sw = context.serviceWorkers()[0];
417
+ await sw.evaluate(() => {
418
+ self.dispatchEvent(
419
+ new NotificationEvent("notificationclick", {
420
+ notification: { data: { url: "/notification-target" } } as any,
421
+ }),
422
+ );
423
+ });
424
+
425
+ // Verify navigation occurred
426
+ await page.waitForTimeout(1000);
427
+ // Check if new page opened or current page navigated
428
+ });
429
+ ```
430
+
431
+ ## Background Sync
432
+
433
+ ### Testing Background Sync Registration
434
+
435
+ ```typescript
436
+ test("registers background sync", async ({ page }) => {
437
+ await page.goto("/pwa-app");
438
+
439
+ // Register sync
440
+ const syncRegistered = await page.evaluate(async () => {
441
+ const reg = await navigator.serviceWorker.ready;
442
+ if (!("sync" in reg)) return false;
443
+
444
+ await (reg as any).sync.register("my-sync");
445
+ return true;
446
+ });
447
+
448
+ expect(syncRegistered).toBe(true);
449
+ });
450
+ ```
451
+
452
+ ### Testing Sync Event
453
+
454
+ ```typescript
455
+ test("sync event fires when online", async ({ context, page }) => {
456
+ await page.goto("/pwa-app");
457
+
458
+ // Queue data while offline
459
+ await context.setOffline(true);
460
+
461
+ await page.evaluate(async () => {
462
+ // Store data in IndexedDB for sync
463
+ const db = await openDB();
464
+ await db.put("sync-queue", { id: 1, data: "test" });
465
+
466
+ // Register sync
467
+ const reg = await navigator.serviceWorker.ready;
468
+ await (reg as any).sync.register("data-sync");
469
+ });
470
+
471
+ // Track sync completion
472
+ await page.evaluate(() => {
473
+ window.syncCompleted = false;
474
+ navigator.serviceWorker.addEventListener("message", (e) => {
475
+ if (e.data.type === "SYNC_COMPLETE") {
476
+ window.syncCompleted = true;
477
+ }
478
+ });
479
+ });
480
+
481
+ // Go online
482
+ await context.setOffline(false);
483
+
484
+ // Wait for sync to complete
485
+ await page.waitForFunction(() => window.syncCompleted, { timeout: 10000 });
486
+ });
487
+ ```
488
+
489
+ ## Anti-Patterns to Avoid
490
+
491
+ | Anti-Pattern | Problem | Solution |
492
+ | ------------------------------ | ----------------------- | -------------------------------------------- |
493
+ | Not clearing SW between tests | Tests affect each other | Unregister SW in beforeEach |
494
+ | Not waiting for SW ready | Race conditions | Always await `navigator.serviceWorker.ready` |
495
+ | Testing in isolation only | Misses real SW behavior | Test with actual caching |
496
+ | Hardcoded timeouts for caching | Flaky tests | Wait for cache to populate |
497
+ | Ignoring SW update cycle | Missing update bugs | Test install, activate, update flows |
498
+
499
+ ## Related References
500
+
501
+ - **Network Failures**: See [error-testing.md](error-testing.md#offline-testing) for unexpected network failure patterns
502
+ - **Browser APIs**: See [browser-apis.md](browser-apis.md) for permissions
503
+ - **Network Mocking**: See [network-advanced.md](../advanced/network-advanced.md) for network interception
504
+ - **Browser Extensions**: See [browser-extensions.md](../testing-patterns/browser-extensions.md) for extension service worker patterns