@prosdevlab/experience-sdk-plugins 0.1.4 → 0.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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +30 -0
- package/dist/index.d.ts +608 -1
- package/dist/index.js +692 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/exit-intent/exit-intent.test.ts +423 -0
- package/src/exit-intent/exit-intent.ts +372 -0
- package/src/exit-intent/index.ts +6 -0
- package/src/exit-intent/types.ts +59 -0
- package/src/index.ts +5 -0
- package/src/integration.test.ts +362 -0
- package/src/page-visits/index.ts +6 -0
- package/src/page-visits/page-visits.test.ts +562 -0
- package/src/page-visits/page-visits.ts +314 -0
- package/src/page-visits/types.ts +119 -0
- package/src/scroll-depth/index.ts +6 -0
- package/src/scroll-depth/scroll-depth.test.ts +545 -0
- package/src/scroll-depth/scroll-depth.ts +400 -0
- package/src/scroll-depth/types.ts +122 -0
- package/src/time-delay/index.ts +6 -0
- package/src/time-delay/time-delay.test.ts +477 -0
- package/src/time-delay/time-delay.ts +297 -0
- package/src/time-delay/types.ts +89 -0
- package/src/utils/sanitize.ts +1 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/** @module timeDelayPlugin */
|
|
2
|
+
|
|
3
|
+
import { SDK } from '@lytics/sdk-kit';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { timeDelayPlugin } from './time-delay';
|
|
6
|
+
import type { TimeDelayEvent, TimeDelayPluginConfig } from './types';
|
|
7
|
+
|
|
8
|
+
describe('Time Delay Plugin', () => {
|
|
9
|
+
// Use fake timers for time-based tests
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.useFakeTimers();
|
|
12
|
+
// Ensure document is visible by default
|
|
13
|
+
Object.defineProperty(document, 'hidden', {
|
|
14
|
+
writable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
value: false,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
vi.useRealTimers();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper to initialize SDK with time delay plugin
|
|
27
|
+
*/
|
|
28
|
+
function initPlugin(config: TimeDelayPluginConfig = {}) {
|
|
29
|
+
const sdk = new SDK(config);
|
|
30
|
+
sdk.use(timeDelayPlugin);
|
|
31
|
+
return sdk;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('Basic Functionality', () => {
|
|
35
|
+
it('should trigger after configured delay', async () => {
|
|
36
|
+
const events: TimeDelayEvent[] = [];
|
|
37
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: false } });
|
|
38
|
+
|
|
39
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
40
|
+
events.push(event);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await sdk.init();
|
|
44
|
+
|
|
45
|
+
// Before delay
|
|
46
|
+
expect(events.length).toBe(0);
|
|
47
|
+
|
|
48
|
+
// Fast forward to trigger time
|
|
49
|
+
vi.advanceTimersByTime(5000);
|
|
50
|
+
|
|
51
|
+
// Should have triggered
|
|
52
|
+
expect(events.length).toBe(1);
|
|
53
|
+
expect(events[0].elapsed).toBeGreaterThanOrEqual(5000);
|
|
54
|
+
expect(events[0].activeElapsed).toBeGreaterThanOrEqual(5000);
|
|
55
|
+
expect(events[0].wasPaused).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should not trigger if delay is 0', async () => {
|
|
59
|
+
const events: TimeDelayEvent[] = [];
|
|
60
|
+
const sdk = initPlugin({ timeDelay: { delay: 0 } });
|
|
61
|
+
|
|
62
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
63
|
+
events.push(event);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await sdk.init();
|
|
67
|
+
|
|
68
|
+
// Advance some time
|
|
69
|
+
vi.advanceTimersByTime(10000);
|
|
70
|
+
|
|
71
|
+
// Should not trigger
|
|
72
|
+
expect(events.length).toBe(0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should update context with elapsed time', async () => {
|
|
76
|
+
const events: TimeDelayEvent[] = [];
|
|
77
|
+
const sdk = initPlugin({ timeDelay: { delay: 3000, pauseWhenHidden: false } });
|
|
78
|
+
|
|
79
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
80
|
+
events.push(event);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await sdk.init();
|
|
84
|
+
|
|
85
|
+
vi.advanceTimersByTime(3000);
|
|
86
|
+
|
|
87
|
+
expect(events.length).toBe(1);
|
|
88
|
+
expect(events[0].timestamp).toBeDefined();
|
|
89
|
+
expect(events[0].elapsed).toBeGreaterThanOrEqual(3000);
|
|
90
|
+
expect(events[0].activeElapsed).toBeGreaterThanOrEqual(3000);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should only trigger once', async () => {
|
|
94
|
+
const events: TimeDelayEvent[] = [];
|
|
95
|
+
const sdk = initPlugin({ timeDelay: { delay: 2000, pauseWhenHidden: false } });
|
|
96
|
+
|
|
97
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
98
|
+
events.push(event);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await sdk.init();
|
|
102
|
+
|
|
103
|
+
vi.advanceTimersByTime(2000);
|
|
104
|
+
expect(events.length).toBe(1);
|
|
105
|
+
|
|
106
|
+
// Advance more time
|
|
107
|
+
vi.advanceTimersByTime(5000);
|
|
108
|
+
expect(events.length).toBe(1); // Still only 1
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('Visibility Handling', () => {
|
|
113
|
+
it('should pause timer when tab is hidden', async () => {
|
|
114
|
+
const events: TimeDelayEvent[] = [];
|
|
115
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: true } });
|
|
116
|
+
|
|
117
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
118
|
+
events.push(event);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await sdk.init();
|
|
122
|
+
|
|
123
|
+
// 2 seconds active
|
|
124
|
+
vi.advanceTimersByTime(2000);
|
|
125
|
+
|
|
126
|
+
// Hide tab
|
|
127
|
+
Object.defineProperty(document, 'hidden', {
|
|
128
|
+
writable: true,
|
|
129
|
+
configurable: true,
|
|
130
|
+
value: true,
|
|
131
|
+
});
|
|
132
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
133
|
+
|
|
134
|
+
// 3 seconds hidden (should be paused)
|
|
135
|
+
vi.advanceTimersByTime(3000);
|
|
136
|
+
|
|
137
|
+
// Should NOT have triggered yet
|
|
138
|
+
expect(events.length).toBe(0);
|
|
139
|
+
|
|
140
|
+
// Show tab
|
|
141
|
+
Object.defineProperty(document, 'hidden', {
|
|
142
|
+
writable: true,
|
|
143
|
+
configurable: true,
|
|
144
|
+
value: false,
|
|
145
|
+
});
|
|
146
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
147
|
+
|
|
148
|
+
// 3 more seconds active (total 5 active)
|
|
149
|
+
vi.advanceTimersByTime(3000);
|
|
150
|
+
|
|
151
|
+
// Should have triggered
|
|
152
|
+
expect(events.length).toBe(1);
|
|
153
|
+
expect(events[0].activeElapsed).toBeGreaterThanOrEqual(5000);
|
|
154
|
+
expect(events[0].elapsed).toBeGreaterThanOrEqual(8000); // 2 + 3 + 3
|
|
155
|
+
expect(events[0].wasPaused).toBe(true);
|
|
156
|
+
expect(events[0].visibilityChanges).toBeGreaterThan(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should not pause if pauseWhenHidden is false', async () => {
|
|
160
|
+
const events: TimeDelayEvent[] = [];
|
|
161
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: false } });
|
|
162
|
+
|
|
163
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
164
|
+
events.push(event);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await sdk.init();
|
|
168
|
+
|
|
169
|
+
// 2 seconds active
|
|
170
|
+
vi.advanceTimersByTime(2000);
|
|
171
|
+
|
|
172
|
+
// Hide tab
|
|
173
|
+
Object.defineProperty(document, 'hidden', {
|
|
174
|
+
writable: true,
|
|
175
|
+
configurable: true,
|
|
176
|
+
value: true,
|
|
177
|
+
});
|
|
178
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
179
|
+
|
|
180
|
+
// 3 more seconds (should still count)
|
|
181
|
+
vi.advanceTimersByTime(3000);
|
|
182
|
+
|
|
183
|
+
// Should have triggered (total 5 seconds)
|
|
184
|
+
expect(events.length).toBe(1);
|
|
185
|
+
expect(events[0].elapsed).toBeGreaterThanOrEqual(5000);
|
|
186
|
+
expect(events[0].wasPaused).toBe(false); // Never paused
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle rapid visibility changes', async () => {
|
|
190
|
+
const events: TimeDelayEvent[] = [];
|
|
191
|
+
const sdk = initPlugin({ timeDelay: { delay: 10000, pauseWhenHidden: true } });
|
|
192
|
+
|
|
193
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
194
|
+
events.push(event);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
await sdk.init();
|
|
198
|
+
|
|
199
|
+
// Multiple hide/show cycles
|
|
200
|
+
for (let i = 0; i < 5; i++) {
|
|
201
|
+
vi.advanceTimersByTime(1000); // 1s active
|
|
202
|
+
|
|
203
|
+
// Hide
|
|
204
|
+
Object.defineProperty(document, 'hidden', {
|
|
205
|
+
writable: true,
|
|
206
|
+
configurable: true,
|
|
207
|
+
value: true,
|
|
208
|
+
});
|
|
209
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
210
|
+
vi.advanceTimersByTime(500); // 0.5s hidden
|
|
211
|
+
|
|
212
|
+
// Show
|
|
213
|
+
Object.defineProperty(document, 'hidden', {
|
|
214
|
+
writable: true,
|
|
215
|
+
configurable: true,
|
|
216
|
+
value: false,
|
|
217
|
+
});
|
|
218
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Total: 5s active, 2.5s hidden = 7.5s elapsed, 5s active
|
|
222
|
+
expect(events.length).toBe(0); // Not triggered yet (need 10s active)
|
|
223
|
+
|
|
224
|
+
// Add 5 more seconds active (total 10s active)
|
|
225
|
+
vi.advanceTimersByTime(5000);
|
|
226
|
+
|
|
227
|
+
// Should trigger
|
|
228
|
+
expect(events.length).toBe(1);
|
|
229
|
+
expect(events[0].activeElapsed).toBeGreaterThanOrEqual(9000); // Allow some tolerance
|
|
230
|
+
expect(events[0].wasPaused).toBe(true);
|
|
231
|
+
expect(events[0].visibilityChanges).toBeGreaterThan(5);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should handle starting hidden', async () => {
|
|
235
|
+
// Set document hidden before init
|
|
236
|
+
Object.defineProperty(document, 'hidden', {
|
|
237
|
+
writable: true,
|
|
238
|
+
configurable: true,
|
|
239
|
+
value: true,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const events: TimeDelayEvent[] = [];
|
|
243
|
+
const sdk = initPlugin({ timeDelay: { delay: 3000, pauseWhenHidden: true } });
|
|
244
|
+
|
|
245
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
246
|
+
events.push(event);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
await sdk.init();
|
|
250
|
+
|
|
251
|
+
// 2 seconds hidden (should be paused from start)
|
|
252
|
+
vi.advanceTimersByTime(2000);
|
|
253
|
+
expect(events.length).toBe(0);
|
|
254
|
+
|
|
255
|
+
// Show tab
|
|
256
|
+
Object.defineProperty(document, 'hidden', { writable: true, value: false });
|
|
257
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
258
|
+
|
|
259
|
+
// 3 seconds active
|
|
260
|
+
vi.advanceTimersByTime(3000);
|
|
261
|
+
|
|
262
|
+
// Should trigger
|
|
263
|
+
expect(events.length).toBe(1);
|
|
264
|
+
expect(events[0].activeElapsed).toBeGreaterThanOrEqual(3000);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe('API Methods', () => {
|
|
269
|
+
it('should expose getElapsed method', async () => {
|
|
270
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: false } });
|
|
271
|
+
await sdk.init();
|
|
272
|
+
|
|
273
|
+
vi.advanceTimersByTime(2000);
|
|
274
|
+
|
|
275
|
+
const elapsed = sdk.timeDelay.getElapsed();
|
|
276
|
+
expect(elapsed).toBeGreaterThanOrEqual(2000);
|
|
277
|
+
expect(elapsed).toBeLessThan(3000);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should expose getActiveElapsed method', async () => {
|
|
281
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: true } });
|
|
282
|
+
await sdk.init();
|
|
283
|
+
|
|
284
|
+
// 2s active
|
|
285
|
+
vi.advanceTimersByTime(2000);
|
|
286
|
+
|
|
287
|
+
// Hide for 3s
|
|
288
|
+
Object.defineProperty(document, 'hidden', { writable: true, value: true });
|
|
289
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
290
|
+
vi.advanceTimersByTime(3000);
|
|
291
|
+
|
|
292
|
+
const activeElapsed = sdk.timeDelay.getActiveElapsed();
|
|
293
|
+
const totalElapsed = sdk.timeDelay.getElapsed();
|
|
294
|
+
|
|
295
|
+
expect(activeElapsed).toBeGreaterThanOrEqual(2000);
|
|
296
|
+
expect(activeElapsed).toBeLessThan(3000);
|
|
297
|
+
expect(totalElapsed).toBeGreaterThanOrEqual(5000);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should expose getRemaining method', async () => {
|
|
301
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: false } });
|
|
302
|
+
await sdk.init();
|
|
303
|
+
|
|
304
|
+
vi.advanceTimersByTime(2000);
|
|
305
|
+
|
|
306
|
+
const remaining = sdk.timeDelay.getRemaining();
|
|
307
|
+
expect(remaining).toBeGreaterThan(2000);
|
|
308
|
+
expect(remaining).toBeLessThanOrEqual(3000);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should return 0 for getRemaining after trigger', async () => {
|
|
312
|
+
const sdk = initPlugin({ timeDelay: { delay: 2000, pauseWhenHidden: false } });
|
|
313
|
+
await sdk.init();
|
|
314
|
+
|
|
315
|
+
vi.advanceTimersByTime(2000);
|
|
316
|
+
|
|
317
|
+
const remaining = sdk.timeDelay.getRemaining();
|
|
318
|
+
expect(remaining).toBe(0);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should expose isPaused method', async () => {
|
|
322
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: true } });
|
|
323
|
+
await sdk.init();
|
|
324
|
+
|
|
325
|
+
expect(sdk.timeDelay.isPaused()).toBe(false);
|
|
326
|
+
|
|
327
|
+
// Hide tab
|
|
328
|
+
Object.defineProperty(document, 'hidden', { writable: true, value: true });
|
|
329
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
330
|
+
|
|
331
|
+
expect(sdk.timeDelay.isPaused()).toBe(true);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should expose isTriggered method', async () => {
|
|
335
|
+
const sdk = initPlugin({ timeDelay: { delay: 2000, pauseWhenHidden: false } });
|
|
336
|
+
await sdk.init();
|
|
337
|
+
|
|
338
|
+
expect(sdk.timeDelay.isTriggered()).toBe(false);
|
|
339
|
+
|
|
340
|
+
vi.advanceTimersByTime(2000);
|
|
341
|
+
|
|
342
|
+
expect(sdk.timeDelay.isTriggered()).toBe(true);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should expose reset method', async () => {
|
|
346
|
+
const events: TimeDelayEvent[] = [];
|
|
347
|
+
const sdk = initPlugin({ timeDelay: { delay: 3000, pauseWhenHidden: false } });
|
|
348
|
+
|
|
349
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
350
|
+
events.push(event);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
await sdk.init();
|
|
354
|
+
|
|
355
|
+
vi.advanceTimersByTime(3000);
|
|
356
|
+
expect(events.length).toBe(1);
|
|
357
|
+
expect(sdk.timeDelay.isTriggered()).toBe(true);
|
|
358
|
+
|
|
359
|
+
// Reset
|
|
360
|
+
sdk.timeDelay.reset();
|
|
361
|
+
expect(sdk.timeDelay.isTriggered()).toBe(false);
|
|
362
|
+
|
|
363
|
+
// Should trigger again after 3s
|
|
364
|
+
vi.advanceTimersByTime(3000);
|
|
365
|
+
expect(events.length).toBe(2);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('Cleanup', () => {
|
|
370
|
+
it('should cleanup timers on destroy', async () => {
|
|
371
|
+
const events: TimeDelayEvent[] = [];
|
|
372
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: false } });
|
|
373
|
+
|
|
374
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
375
|
+
events.push(event);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await sdk.init();
|
|
379
|
+
|
|
380
|
+
vi.advanceTimersByTime(2000);
|
|
381
|
+
|
|
382
|
+
// Destroy SDK
|
|
383
|
+
sdk.emit('destroy');
|
|
384
|
+
|
|
385
|
+
// Advance past trigger time
|
|
386
|
+
vi.advanceTimersByTime(5000);
|
|
387
|
+
|
|
388
|
+
// Should NOT have triggered (timer was cleared)
|
|
389
|
+
expect(events.length).toBe(0);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('should cleanup visibility listeners on destroy', async () => {
|
|
393
|
+
const sdk = initPlugin({ timeDelay: { delay: 5000, pauseWhenHidden: true } });
|
|
394
|
+
await sdk.init();
|
|
395
|
+
|
|
396
|
+
const removeEventListenerSpy = vi.spyOn(document, 'removeEventListener');
|
|
397
|
+
|
|
398
|
+
// Destroy SDK
|
|
399
|
+
sdk.emit('destroy');
|
|
400
|
+
|
|
401
|
+
// Should have removed visibility listener
|
|
402
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('visibilitychange', expect.any(Function));
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
describe('Edge Cases', () => {
|
|
407
|
+
it('should handle delay elapsed during pause', async () => {
|
|
408
|
+
const events: TimeDelayEvent[] = [];
|
|
409
|
+
const sdk = initPlugin({ timeDelay: { delay: 2000, pauseWhenHidden: true } });
|
|
410
|
+
|
|
411
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
412
|
+
events.push(event);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
await sdk.init();
|
|
416
|
+
|
|
417
|
+
// 1s active
|
|
418
|
+
vi.advanceTimersByTime(1000);
|
|
419
|
+
|
|
420
|
+
// Hide tab
|
|
421
|
+
Object.defineProperty(document, 'hidden', {
|
|
422
|
+
writable: true,
|
|
423
|
+
configurable: true,
|
|
424
|
+
value: true,
|
|
425
|
+
});
|
|
426
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
427
|
+
|
|
428
|
+
// 5s hidden (enough to complete delay if not paused)
|
|
429
|
+
vi.advanceTimersByTime(5000);
|
|
430
|
+
|
|
431
|
+
// Should NOT have triggered yet
|
|
432
|
+
expect(events.length).toBe(0);
|
|
433
|
+
|
|
434
|
+
// Show tab
|
|
435
|
+
Object.defineProperty(document, 'hidden', {
|
|
436
|
+
writable: true,
|
|
437
|
+
configurable: true,
|
|
438
|
+
value: false,
|
|
439
|
+
});
|
|
440
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
441
|
+
|
|
442
|
+
// 1 more second active (total 2s active)
|
|
443
|
+
vi.advanceTimersByTime(1000);
|
|
444
|
+
|
|
445
|
+
// Should trigger
|
|
446
|
+
expect(events.length).toBe(1);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('should work in environments without Page Visibility API', async () => {
|
|
450
|
+
// Mock missing document.hidden
|
|
451
|
+
const originalHidden = Object.getOwnPropertyDescriptor(document, 'hidden');
|
|
452
|
+
Object.defineProperty(document, 'hidden', {
|
|
453
|
+
get: () => undefined,
|
|
454
|
+
configurable: true,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
const events: TimeDelayEvent[] = [];
|
|
458
|
+
const sdk = initPlugin({ timeDelay: { delay: 2000, pauseWhenHidden: true } });
|
|
459
|
+
|
|
460
|
+
sdk.on('trigger:timeDelay', (event) => {
|
|
461
|
+
events.push(event);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
await sdk.init();
|
|
465
|
+
|
|
466
|
+
vi.advanceTimersByTime(2000);
|
|
467
|
+
|
|
468
|
+
// Should still trigger (falls back to no pause)
|
|
469
|
+
expect(events.length).toBe(1);
|
|
470
|
+
|
|
471
|
+
// Restore
|
|
472
|
+
if (originalHidden) {
|
|
473
|
+
Object.defineProperty(document, 'hidden', originalHidden);
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
});
|