@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.
- package/.agents/skills/e2e-testing-expert/SKILL.md +28 -0
- package/.agents/skills/frontend-design/LICENSE.txt +177 -0
- package/.agents/skills/frontend-design/SKILL.md +42 -0
- package/.agents/skills/nodejs-backend-patterns/SKILL.md +639 -0
- package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
- package/.agents/skills/playwright-best-practices/LICENSE.md +7 -0
- package/.agents/skills/playwright-best-practices/README.md +147 -0
- package/.agents/skills/playwright-best-practices/SKILL.md +303 -0
- package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +360 -0
- package/.agents/skills/playwright-best-practices/advanced/authentication.md +871 -0
- package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +364 -0
- package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +409 -0
- package/.agents/skills/playwright-best-practices/advanced/multi-context.md +288 -0
- package/.agents/skills/playwright-best-practices/advanced/multi-user.md +393 -0
- package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +452 -0
- package/.agents/skills/playwright-best-practices/advanced/third-party.md +464 -0
- package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +363 -0
- package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +369 -0
- package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +383 -0
- package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +391 -0
- package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +403 -0
- package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +504 -0
- package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +403 -0
- package/.agents/skills/playwright-best-practices/core/annotations.md +424 -0
- package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +361 -0
- package/.agents/skills/playwright-best-practices/core/configuration.md +452 -0
- package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +417 -0
- package/.agents/skills/playwright-best-practices/core/global-setup.md +434 -0
- package/.agents/skills/playwright-best-practices/core/locators.md +242 -0
- package/.agents/skills/playwright-best-practices/core/page-object-model.md +315 -0
- package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +453 -0
- package/.agents/skills/playwright-best-practices/core/test-data.md +492 -0
- package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +361 -0
- package/.agents/skills/playwright-best-practices/core/test-tags.md +298 -0
- package/.agents/skills/playwright-best-practices/debugging/console-errors.md +420 -0
- package/.agents/skills/playwright-best-practices/debugging/debugging.md +504 -0
- package/.agents/skills/playwright-best-practices/debugging/error-testing.md +360 -0
- package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +496 -0
- package/.agents/skills/playwright-best-practices/frameworks/angular.md +530 -0
- package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +469 -0
- package/.agents/skills/playwright-best-practices/frameworks/react.md +531 -0
- package/.agents/skills/playwright-best-practices/frameworks/vue.md +574 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +468 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +283 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +546 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +397 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +521 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +371 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +453 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +424 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +497 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +359 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +719 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +506 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +493 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +500 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +576 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +509 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +377 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +562 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +561 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +331 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +508 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +476 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +430 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +634 -0
- package/.env.example +21 -0
- package/README.md +30 -0
- package/bin/arcality.mjs +86 -0
- package/package.json +66 -0
- package/playwright.config.ts +12 -0
- package/scripts/cleanup-qmsdev.mjs +63 -0
- package/scripts/discover-view.mjs +52 -0
- package/scripts/extract-view.mjs +64 -0
- package/scripts/gen-and-run.mjs +838 -0
- package/scripts/init.mjs +290 -0
- package/scripts/migrate-to-central-out.mjs +157 -0
- package/scripts/postinstall.mjs +63 -0
- package/scripts/rebrand-report.mjs +241 -0
- package/scripts/setup.mjs +166 -0
- package/src/KnowledgeService.ts +239 -0
- package/src/arcalityClient.mjs +266 -0
- package/src/configLoader.mjs +179 -0
- package/src/configManager.mjs +172 -0
- package/src/consoleBanner.ts +32 -0
- package/src/envSetup.ts +205 -0
- package/src/index.ts +25 -0
- package/src/projectInspector.ts +42 -0
- package/src/services/collectiveMemoryService.ts +178 -0
- package/src/testRunner.ts +201 -0
- package/tests/_helpers/ArcalityReporter.ts +490 -0
- package/tests/_helpers/agentic-runner.spec.ts +741 -0
- package/tests/_helpers/ai-agent-helper.ts +1573 -0
- package/tests/_helpers/discover-view.spec.ts +238 -0
- package/tests/_helpers/extract-view.spec.ts +118 -0
- package/tests/_helpers/qa-tools.ts +333 -0
- 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
|