@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,391 @@
1
+ # Browser APIs: Geolocation, Permissions & More
2
+
3
+ ## Table of Contents
4
+
5
+ 1. [Geolocation](#geolocation)
6
+ 2. [Permissions](#permissions)
7
+ 3. [Clipboard](#clipboard)
8
+ 4. [Notifications](#notifications)
9
+ 5. [Camera & Microphone](#camera--microphone)
10
+
11
+ ## Geolocation
12
+
13
+ ### Mock Location
14
+
15
+ ```typescript
16
+ test("shows nearby stores", async ({ context }) => {
17
+ // Grant permission and set location
18
+ await context.grantPermissions(["geolocation"]);
19
+ await context.setGeolocation({ latitude: 37.7749, longitude: -122.4194 }); // San Francisco
20
+
21
+ const page = await context.newPage();
22
+ await page.goto("/store-finder");
23
+ await page.getByRole("button", { name: "Find Nearby" }).click();
24
+
25
+ await expect(page.getByText("San Francisco")).toBeVisible();
26
+ });
27
+ ```
28
+
29
+ ### Geolocation Fixture
30
+
31
+ ```typescript
32
+ // fixtures/geolocation.fixture.ts
33
+ import { test as base } from "@playwright/test";
34
+
35
+ type Coordinates = { latitude: number; longitude: number; accuracy?: number };
36
+
37
+ type GeoFixtures = {
38
+ setLocation: (coords: Coordinates) => Promise<void>;
39
+ };
40
+
41
+ export const test = base.extend<GeoFixtures>({
42
+ setLocation: async ({ context }, use) => {
43
+ await context.grantPermissions(["geolocation"]);
44
+
45
+ await use(async (coords) => {
46
+ await context.setGeolocation({
47
+ latitude: coords.latitude,
48
+ longitude: coords.longitude,
49
+ accuracy: coords.accuracy ?? 100,
50
+ });
51
+ });
52
+ },
53
+ });
54
+
55
+ // Usage
56
+ test("delivery zone check", async ({ page, setLocation }) => {
57
+ await setLocation({ latitude: 40.7128, longitude: -74.006 }); // NYC
58
+
59
+ await page.goto("/delivery");
60
+
61
+ await expect(page.getByText("Delivery available")).toBeVisible();
62
+ });
63
+ ```
64
+
65
+ ### Test Location Changes
66
+
67
+ ```typescript
68
+ test("tracks location updates", async ({ context }) => {
69
+ await context.grantPermissions(["geolocation"]);
70
+
71
+ const page = await context.newPage();
72
+ await page.goto("/tracking");
73
+
74
+ // Initial location
75
+ await context.setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
76
+ await page.getByRole("button", { name: "Start Tracking" }).click();
77
+
78
+ await expect(page.getByTestId("location")).toContainText("37.7749");
79
+
80
+ // Move to new location
81
+ await context.setGeolocation({ latitude: 37.8044, longitude: -122.2712 });
82
+
83
+ // Trigger location update
84
+ await page.evaluate(() => {
85
+ navigator.geolocation.getCurrentPosition(() => {});
86
+ });
87
+
88
+ await expect(page.getByTestId("location")).toContainText("37.8044");
89
+ });
90
+ ```
91
+
92
+ ### Test Geolocation Denial
93
+
94
+ ```typescript
95
+ test("handles location denied", async ({ browser }) => {
96
+ // Create context without geolocation permission
97
+ const context = await browser.newContext({
98
+ permissions: [], // No permissions
99
+ });
100
+
101
+ const page = await context.newPage();
102
+ await page.goto("/store-finder");
103
+ await page.getByRole("button", { name: "Find Nearby" }).click();
104
+
105
+ await expect(page.getByText("Location access denied")).toBeVisible();
106
+ await expect(page.getByLabel("Enter ZIP code")).toBeVisible();
107
+
108
+ await context.close();
109
+ });
110
+ ```
111
+
112
+ ## Permissions
113
+
114
+ ### Grant Permissions
115
+
116
+ ```typescript
117
+ test("notifications with permission", async ({ context }) => {
118
+ await context.grantPermissions(["notifications"]);
119
+
120
+ const page = await context.newPage();
121
+ await page.goto("/alerts");
122
+
123
+ // Notification API should work
124
+ const permission = await page.evaluate(() => Notification.permission);
125
+ expect(permission).toBe("granted");
126
+ });
127
+ ```
128
+
129
+ ### Test Permission Denied
130
+
131
+ ```typescript
132
+ test("handles notification permission denied", async ({ browser }) => {
133
+ const context = await browser.newContext({
134
+ permissions: [], // Deny all
135
+ });
136
+
137
+ const page = await context.newPage();
138
+ await page.goto("/notifications");
139
+
140
+ await page.getByRole("button", { name: "Enable Notifications" }).click();
141
+
142
+ await expect(page.getByText("Please enable notifications")).toBeVisible();
143
+
144
+ await context.close();
145
+ });
146
+ ```
147
+
148
+ ### Multiple Permissions
149
+
150
+ ```typescript
151
+ test("video call with permissions", async ({ context }) => {
152
+ await context.grantPermissions(["camera", "microphone", "notifications"]);
153
+
154
+ const page = await context.newPage();
155
+ await page.goto("/video-call");
156
+
157
+ // All permissions should be granted
158
+ const permissions = await page.evaluate(async () => ({
159
+ camera: await navigator.permissions.query({
160
+ name: "camera" as PermissionName,
161
+ }),
162
+ microphone: await navigator.permissions.query({
163
+ name: "microphone" as PermissionName,
164
+ }),
165
+ }));
166
+
167
+ expect(permissions.camera.state).toBe("granted");
168
+ expect(permissions.microphone.state).toBe("granted");
169
+ });
170
+ ```
171
+
172
+ ## Clipboard
173
+
174
+ ### Test Copy to Clipboard
175
+
176
+ ```typescript
177
+ test("copy button works", async ({ page, context }) => {
178
+ // Grant clipboard permissions
179
+ await context.grantPermissions(["clipboard-read", "clipboard-write"]);
180
+
181
+ await page.goto("/share");
182
+
183
+ await page.getByRole("button", { name: "Copy Link" }).click();
184
+
185
+ // Read clipboard content
186
+ const clipboardContent = await page.evaluate(() =>
187
+ navigator.clipboard.readText(),
188
+ );
189
+
190
+ expect(clipboardContent).toContain("https://example.com/share/");
191
+ });
192
+ ```
193
+
194
+ ### Test Paste from Clipboard
195
+
196
+ ```typescript
197
+ test("paste from clipboard", async ({ page, context }) => {
198
+ await context.grantPermissions(["clipboard-read", "clipboard-write"]);
199
+
200
+ await page.goto("/editor");
201
+
202
+ // Write to clipboard
203
+ await page.evaluate(() => navigator.clipboard.writeText("Pasted content"));
204
+
205
+ // Trigger paste
206
+ await page.getByLabel("Content").focus();
207
+ await page.keyboard.press("Control+V");
208
+
209
+ await expect(page.getByLabel("Content")).toHaveValue("Pasted content");
210
+ });
211
+ ```
212
+
213
+ ### Clipboard Fixture
214
+
215
+ ```typescript
216
+ // fixtures/clipboard.fixture.ts
217
+ import { test as base } from "@playwright/test";
218
+
219
+ type ClipboardFixtures = {
220
+ clipboard: {
221
+ write: (text: string) => Promise<void>;
222
+ read: () => Promise<string>;
223
+ };
224
+ };
225
+
226
+ export const test = base.extend<ClipboardFixtures>({
227
+ clipboard: async ({ page, context }, use) => {
228
+ await context.grantPermissions(["clipboard-read", "clipboard-write"]);
229
+
230
+ await use({
231
+ write: async (text) => {
232
+ await page.evaluate((t) => navigator.clipboard.writeText(t), text);
233
+ },
234
+ read: async () => {
235
+ return page.evaluate(() => navigator.clipboard.readText());
236
+ },
237
+ });
238
+ },
239
+ });
240
+ ```
241
+
242
+ ## Notifications
243
+
244
+ ### Mock Notification API
245
+
246
+ ```typescript
247
+ test("shows browser notification", async ({ page }) => {
248
+ const notifications: any[] = [];
249
+
250
+ // Mock Notification constructor
251
+ await page.addInitScript(() => {
252
+ (window as any).__notifications = [];
253
+ (window as any).Notification = class {
254
+ constructor(title: string, options?: NotificationOptions) {
255
+ (window as any).__notifications.push({ title, ...options });
256
+ }
257
+ static permission = "granted";
258
+ static requestPermission = async () => "granted";
259
+ };
260
+ });
261
+
262
+ await page.goto("/alerts");
263
+ await page.getByRole("button", { name: "Notify Me" }).click();
264
+
265
+ // Check notification was created
266
+ const created = await page.evaluate(() => (window as any).__notifications);
267
+ expect(created).toHaveLength(1);
268
+ expect(created[0].title).toBe("New Alert");
269
+ });
270
+ ```
271
+
272
+ ### Test Notification Click
273
+
274
+ ```typescript
275
+ test("notification click handler", async ({ page }) => {
276
+ await page.addInitScript(() => {
277
+ (window as any).Notification = class {
278
+ onclick: (() => void) | null = null;
279
+ constructor(title: string) {
280
+ // Simulate click after creation
281
+ setTimeout(() => this.onclick?.(), 100);
282
+ }
283
+ static permission = "granted";
284
+ static requestPermission = async () => "granted";
285
+ };
286
+ });
287
+
288
+ await page.goto("/messages");
289
+ await page.evaluate(() => {
290
+ new Notification("New Message");
291
+ });
292
+
293
+ // Should navigate to messages when notification clicked
294
+ await expect(page).toHaveURL(/\/messages/);
295
+ });
296
+ ```
297
+
298
+ ## Camera & Microphone
299
+
300
+ ### Mock Media Devices
301
+
302
+ ```typescript
303
+ test("video preview works", async ({ page, context }) => {
304
+ await context.grantPermissions(["camera"]);
305
+
306
+ // Mock getUserMedia
307
+ await page.addInitScript(() => {
308
+ navigator.mediaDevices.getUserMedia = async () => {
309
+ const canvas = document.createElement("canvas");
310
+ canvas.width = 640;
311
+ canvas.height = 480;
312
+ return canvas.captureStream();
313
+ };
314
+ });
315
+
316
+ await page.goto("/video-settings");
317
+ await page.getByRole("button", { name: "Start Camera" }).click();
318
+
319
+ await expect(page.getByTestId("video-preview")).toBeVisible();
320
+ });
321
+ ```
322
+
323
+ ### Test Media Device Selection
324
+
325
+ ```typescript
326
+ test("switch camera", async ({ page }) => {
327
+ await page.addInitScript(() => {
328
+ navigator.mediaDevices.enumerateDevices = async () =>
329
+ [
330
+ {
331
+ deviceId: "cam1",
332
+ kind: "videoinput",
333
+ label: "Front Camera",
334
+ groupId: "1",
335
+ },
336
+ {
337
+ deviceId: "cam2",
338
+ kind: "videoinput",
339
+ label: "Back Camera",
340
+ groupId: "2",
341
+ },
342
+ ] as MediaDeviceInfo[];
343
+
344
+ navigator.mediaDevices.getUserMedia = async () => {
345
+ const canvas = document.createElement("canvas");
346
+ return canvas.captureStream();
347
+ };
348
+ });
349
+
350
+ await page.goto("/camera");
351
+
352
+ // Should show camera options
353
+ await expect(page.getByRole("combobox", { name: "Camera" })).toBeVisible();
354
+ await expect(page.getByText("Front Camera")).toBeVisible();
355
+ await expect(page.getByText("Back Camera")).toBeVisible();
356
+ });
357
+ ```
358
+
359
+ ### Test Media Errors
360
+
361
+ ```typescript
362
+ test("handles camera access error", async ({ page }) => {
363
+ await page.addInitScript(() => {
364
+ navigator.mediaDevices.getUserMedia = async () => {
365
+ throw new DOMException("Permission denied", "NotAllowedError");
366
+ };
367
+ });
368
+
369
+ await page.goto("/video-call");
370
+ await page.getByRole("button", { name: "Join Call" }).click();
371
+
372
+ await expect(page.getByText("Camera access denied")).toBeVisible();
373
+ await expect(
374
+ page.getByRole("button", { name: "Join Audio Only" }),
375
+ ).toBeVisible();
376
+ });
377
+ ```
378
+
379
+ ## Anti-Patterns to Avoid
380
+
381
+ | Anti-Pattern | Problem | Solution |
382
+ | ----------------------------- | --------------------------------- | ----------------------------------- |
383
+ | Not granting permissions | Tests fail with permission errors | Use `context.grantPermissions()` |
384
+ | Testing real geolocation | Flaky, environment-dependent | Mock with `setGeolocation()` |
385
+ | Not testing permission denial | Misses error handling | Test both granted and denied states |
386
+ | Using real camera/mic | CI has no devices | Mock `getUserMedia` |
387
+
388
+ ## Related References
389
+
390
+ - **Fixtures**: See [fixtures-hooks.md](../core/fixtures-hooks.md) for context fixtures
391
+ - **Mobile**: See [mobile-testing.md](../advanced/mobile-testing.md) for device emulation