@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,364 @@
1
+ # Date, Time & Clock Mocking
2
+
3
+ ## Table of Contents
4
+
5
+ 1. [Clock API Basics](#clock-api-basics)
6
+ 2. [Fixed Time Testing](#fixed-time-testing)
7
+ 3. [Time Advancement](#time-advancement)
8
+ 4. [Timezone Testing](#timezone-testing)
9
+ 5. [Timer Mocking](#timer-mocking)
10
+
11
+ ## Clock API Basics
12
+
13
+ ### Install Clock
14
+
15
+ ```typescript
16
+ test("mock current time", async ({ page }) => {
17
+ // Install clock before navigating
18
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
19
+
20
+ await page.goto("/dashboard");
21
+
22
+ // Page sees January 15, 2025 as current date
23
+ await expect(page.getByText("January 15, 2025")).toBeVisible();
24
+ });
25
+ ```
26
+
27
+ ### Clock with Fixture
28
+
29
+ ```typescript
30
+ // fixtures/clock.fixture.ts
31
+ import { test as base } from "@playwright/test";
32
+
33
+ type ClockFixtures = {
34
+ mockTime: (date: Date | string) => Promise<void>;
35
+ };
36
+
37
+ export const test = base.extend<ClockFixtures>({
38
+ mockTime: async ({ page }, use) => {
39
+ await use(async (date) => {
40
+ const time = typeof date === "string" ? new Date(date) : date;
41
+ await page.clock.install({ time });
42
+ });
43
+ },
44
+ });
45
+
46
+ // Usage
47
+ test("subscription expiry", async ({ page, mockTime }) => {
48
+ await mockTime("2025-12-31T23:59:00");
49
+ await page.goto("/subscription");
50
+
51
+ await expect(page.getByText("Expires today")).toBeVisible();
52
+ });
53
+ ```
54
+
55
+ ## Fixed Time Testing
56
+
57
+ ### Test Date-Dependent Features
58
+
59
+ ```typescript
60
+ test("show holiday banner in December", async ({ page }) => {
61
+ await page.clock.install({ time: new Date("2025-12-20T10:00:00") });
62
+
63
+ await page.goto("/");
64
+
65
+ await expect(page.getByRole("banner", { name: /holiday/i })).toBeVisible();
66
+ });
67
+
68
+ test("no holiday banner in January", async ({ page }) => {
69
+ await page.clock.install({ time: new Date("2025-01-15T10:00:00") });
70
+
71
+ await page.goto("/");
72
+
73
+ await expect(page.getByRole("banner", { name: /holiday/i })).toBeHidden();
74
+ });
75
+ ```
76
+
77
+ ### Test Relative Time Display
78
+
79
+ ```typescript
80
+ test("shows relative time correctly", async ({ page }) => {
81
+ // Fix time to control "posted 2 hours ago" text
82
+ await page.clock.install({ time: new Date("2025-06-15T14:00:00") });
83
+
84
+ // Mock API to return post with known timestamp
85
+ await page.route("**/api/posts/1", (route) =>
86
+ route.fulfill({
87
+ json: {
88
+ id: 1,
89
+ title: "Test Post",
90
+ createdAt: "2025-06-15T12:00:00Z", // 2 hours before mock time
91
+ },
92
+ }),
93
+ );
94
+
95
+ await page.goto("/posts/1");
96
+
97
+ await expect(page.getByText("2 hours ago")).toBeVisible();
98
+ });
99
+ ```
100
+
101
+ ### Test Date Boundaries
102
+
103
+ ```typescript
104
+ test.describe("end of month billing", () => {
105
+ test("shows billing on last day of month", async ({ page }) => {
106
+ await page.clock.install({ time: new Date("2025-01-31T10:00:00") });
107
+ await page.goto("/billing");
108
+
109
+ await expect(page.getByText("Payment due today")).toBeVisible();
110
+ });
111
+
112
+ test("shows days remaining mid-month", async ({ page }) => {
113
+ await page.clock.install({ time: new Date("2025-01-15T10:00:00") });
114
+ await page.goto("/billing");
115
+
116
+ await expect(page.getByText("16 days until payment")).toBeVisible();
117
+ });
118
+ });
119
+ ```
120
+
121
+ ## Time Advancement
122
+
123
+ ### Advance Time Manually
124
+
125
+ ```typescript
126
+ test("session timeout warning", async ({ page }) => {
127
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
128
+ await page.goto("/dashboard");
129
+
130
+ // Advance 25 minutes (session timeout at 30 min)
131
+ await page.clock.fastForward("25:00");
132
+
133
+ await expect(page.getByText("Session expires in 5 minutes")).toBeVisible();
134
+
135
+ // Advance 5 more minutes
136
+ await page.clock.fastForward("05:00");
137
+
138
+ await expect(page.getByText("Session expired")).toBeVisible();
139
+ });
140
+ ```
141
+
142
+ ### Pause and Resume Time
143
+
144
+ ```typescript
145
+ test("countdown timer", async ({ page }) => {
146
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
147
+ await page.goto("/sale");
148
+
149
+ // Initial state
150
+ await expect(page.getByText("Sale ends in 2:00:00")).toBeVisible();
151
+
152
+ // Advance 1 hour
153
+ await page.clock.fastForward("01:00:00");
154
+
155
+ await expect(page.getByText("Sale ends in 1:00:00")).toBeVisible();
156
+
157
+ // Advance past end
158
+ await page.clock.fastForward("01:00:01");
159
+
160
+ await expect(page.getByText("Sale ended")).toBeVisible();
161
+ });
162
+ ```
163
+
164
+ ### Run Pending Timers
165
+
166
+ ```typescript
167
+ test("debounced search", async ({ page }) => {
168
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
169
+ await page.goto("/search");
170
+
171
+ await page.getByLabel("Search").fill("playwright");
172
+
173
+ // Search is debounced by 300ms, won't fire yet
174
+ await expect(page.getByTestId("search-results")).toBeHidden();
175
+
176
+ // Fast forward past debounce
177
+ await page.clock.fastForward(300);
178
+
179
+ // Now search should execute
180
+ await expect(page.getByTestId("search-results")).toBeVisible();
181
+ });
182
+ ```
183
+
184
+ ## Timezone Testing
185
+
186
+ ### Test Different Timezones
187
+
188
+ ```typescript
189
+ test.describe("timezone display", () => {
190
+ test("shows correct time in PST", async ({ browser }) => {
191
+ const context = await browser.newContext({
192
+ timezoneId: "America/Los_Angeles",
193
+ });
194
+ const page = await context.newPage();
195
+
196
+ await page.clock.install({ time: new Date("2025-01-15T17:00:00Z") }); // 5 PM UTC
197
+
198
+ await page.goto("/schedule");
199
+
200
+ // Should show 9 AM PST
201
+ await expect(page.getByText("9:00 AM")).toBeVisible();
202
+
203
+ await context.close();
204
+ });
205
+
206
+ test("shows correct time in JST", async ({ browser }) => {
207
+ const context = await browser.newContext({
208
+ timezoneId: "Asia/Tokyo",
209
+ });
210
+ const page = await context.newPage();
211
+
212
+ await page.clock.install({ time: new Date("2025-01-15T17:00:00Z") }); // 5 PM UTC
213
+
214
+ await page.goto("/schedule");
215
+
216
+ // Should show 2 AM next day JST
217
+ await expect(page.getByText("2:00 AM")).toBeVisible();
218
+
219
+ await context.close();
220
+ });
221
+ });
222
+ ```
223
+
224
+ ### Timezone Fixture
225
+
226
+ ```typescript
227
+ // fixtures/timezone.fixture.ts
228
+ import { test as base } from "@playwright/test";
229
+
230
+ type TimezoneFixtures = {
231
+ pageInTimezone: (timezone: string) => Promise<Page>;
232
+ };
233
+
234
+ export const test = base.extend<TimezoneFixtures>({
235
+ pageInTimezone: async ({ browser }, use) => {
236
+ const pages: Page[] = [];
237
+
238
+ await use(async (timezone) => {
239
+ const context = await browser.newContext({ timezoneId: timezone });
240
+ const page = await context.newPage();
241
+ pages.push(page);
242
+ return page;
243
+ });
244
+
245
+ // Cleanup
246
+ for (const page of pages) {
247
+ await page.context().close();
248
+ }
249
+ },
250
+ });
251
+ ```
252
+
253
+ ## Timer Mocking
254
+
255
+ ### Mock setInterval
256
+
257
+ ```typescript
258
+ test("auto-refresh data", async ({ page }) => {
259
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
260
+
261
+ let apiCalls = 0;
262
+ await page.route("**/api/data", (route) => {
263
+ apiCalls++;
264
+ route.fulfill({ json: { value: apiCalls } });
265
+ });
266
+
267
+ await page.goto("/live-data"); // Sets up 30s refresh interval
268
+
269
+ expect(apiCalls).toBe(1); // Initial load
270
+
271
+ // Advance 30 seconds
272
+ await page.clock.fastForward("00:30");
273
+ expect(apiCalls).toBe(2); // First refresh
274
+
275
+ // Advance another 30 seconds
276
+ await page.clock.fastForward("00:30");
277
+ expect(apiCalls).toBe(3); // Second refresh
278
+ });
279
+ ```
280
+
281
+ ### Mock setTimeout Chains
282
+
283
+ ```typescript
284
+ test("notification queue", async ({ page }) => {
285
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
286
+ await page.goto("/notifications");
287
+
288
+ // Trigger 3 notifications that show sequentially
289
+ await page.getByRole("button", { name: "Show All" }).click();
290
+
291
+ // First notification appears immediately
292
+ await expect(page.getByText("Notification 1")).toBeVisible();
293
+
294
+ // Second appears after 2 seconds
295
+ await page.clock.fastForward("00:02");
296
+ await expect(page.getByText("Notification 2")).toBeVisible();
297
+
298
+ // Third appears after 2 more seconds
299
+ await page.clock.fastForward("00:02");
300
+ await expect(page.getByText("Notification 3")).toBeVisible();
301
+ });
302
+ ```
303
+
304
+ ### Test Animation Frames
305
+
306
+ ```typescript
307
+ test("animation completes", async ({ page }) => {
308
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
309
+ await page.goto("/animation-demo");
310
+
311
+ await page.getByRole("button", { name: "Animate" }).click();
312
+
313
+ // Animation runs for 500ms
314
+ const element = page.getByTestId("animated-box");
315
+ await expect(element).toHaveCSS("opacity", "0");
316
+
317
+ // Fast forward through animation
318
+ await page.clock.fastForward(500);
319
+
320
+ await expect(element).toHaveCSS("opacity", "1");
321
+ });
322
+ ```
323
+
324
+ ## Best Practices
325
+
326
+ ### Always Install Clock Before Navigation
327
+
328
+ ```typescript
329
+ // Good
330
+ test("date test", async ({ page }) => {
331
+ await page.clock.install({ time: new Date("2025-01-15") });
332
+ await page.goto("/"); // Page loads with mocked time
333
+ });
334
+
335
+ // Bad - time already captured by page
336
+ test("date test", async ({ page }) => {
337
+ await page.goto("/");
338
+ await page.clock.install({ time: new Date("2025-01-15") }); // Too late!
339
+ });
340
+ ```
341
+
342
+ ### Use ISO Strings for Clarity
343
+
344
+ ```typescript
345
+ // Good - explicit timezone
346
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00Z") });
347
+
348
+ // Ambiguous - uses local timezone
349
+ await page.clock.install({ time: new Date("2025-01-15T09:00:00") });
350
+ ```
351
+
352
+ ## Anti-Patterns to Avoid
353
+
354
+ | Anti-Pattern | Problem | Solution |
355
+ | ---------------------------------------- | ------------------------------- | -------------------------------------- |
356
+ | Installing clock after navigation | Page already captured real time | Install clock before `goto()` |
357
+ | Hardcoded relative dates | Tests break over time | Use fixed dates with clock mock |
358
+ | Not accounting for timezone | Tests fail in different regions | Use explicit UTC times or set timezone |
359
+ | Using `waitForTimeout` with mocked clock | Conflicts with mocked timers | Use `fastForward` instead |
360
+
361
+ ## Related References
362
+
363
+ - **Assertions**: See [assertions-waiting.md](../core/assertions-waiting.md) for time-based assertions
364
+ - **Fixtures**: See [fixtures-hooks.md](../core/fixtures-hooks.md) for clock fixtures