-
Notifications
You must be signed in to change notification settings - Fork 179
Expand file tree
/
Copy pathcookieObservable.spec.ts
More file actions
134 lines (104 loc) · 5.28 KB
/
cookieObservable.spec.ts
File metadata and controls
134 lines (104 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import type { Subscription } from '@datadog/browser-core'
import { ONE_MINUTE, deleteCookie, setCookie } from '@datadog/browser-core'
import type { Clock } from '@datadog/browser-core/test'
import { mockClock } from '@datadog/browser-core/test'
import { mockRumConfiguration } from '../../test'
import type { CookieStoreWindow } from './cookieObservable'
import { WATCH_COOKIE_INTERVAL_DELAY, createCookieObservable } from './cookieObservable'
const COOKIE_NAME = 'cookie_name'
const COOKIE_DURATION = ONE_MINUTE
describe('cookieObservable', () => {
let subscription: Subscription
let originalSupportedEntryTypes: PropertyDescriptor | undefined
let clock: Clock
beforeEach(() => {
deleteCookie(COOKIE_NAME)
clock = mockClock()
originalSupportedEntryTypes = Object.getOwnPropertyDescriptor(window, 'cookieStore')
})
afterEach(() => {
subscription?.unsubscribe()
if (originalSupportedEntryTypes) {
Object.defineProperty(window, 'cookieStore', originalSupportedEntryTypes)
}
})
it('should notify observers on cookie change', async () => {
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
const cookieChangePromise = new Promise((resolve) => {
subscription = observable.subscribe(resolve)
})
// When writing a cookie just after subscribing to the cookieStore 'change' event, the 'change'
// event is sometimes not triggered, making this test case flaky.
// To work around this, we get some random cookie from the cookieStore. This adds enough delay
// to ensure that the 'change' event is triggered when we write our cookie.
// This was reported here: https://issues.chromium.org/issues/420405275
const cookieStore = (window as CookieStoreWindow).cookieStore
if (cookieStore) {
// Wait for the cookieStore to be ready
await cookieStore.get('some_cookie_name')
}
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
const cookieChange = await cookieChangePromise
expect(cookieChange).toEqual('foo')
})
it('should notify observers on cookie change when cookieStore is not supported', () => {
Object.defineProperty(window, 'cookieStore', { get: () => undefined, configurable: true })
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
let cookieChange: string | undefined
subscription = observable.subscribe((change) => (cookieChange = change))
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
expect(cookieChange).toEqual('foo')
})
it('should not notify observers on cookie change when the cookie value as not changed when cookieStore is not supported', () => {
Object.defineProperty(window, 'cookieStore', { get: () => undefined, configurable: true })
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
let cookieChange: string | undefined
subscription = observable.subscribe((change) => (cookieChange = change))
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
expect(cookieChange).toBeUndefined()
})
it('should not re-notify observers if the cookie has not changed since last notification when cookieStore is not supported', () => {
Object.defineProperty(window, 'cookieStore', { get: () => undefined, configurable: true })
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
const cookieChanges: Array<string | undefined> = []
subscription = observable.subscribe((change) => cookieChanges.push(change))
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY) // detects 'foo'
clock.tick(WATCH_COOKIE_INTERVAL_DELAY) // no change since last notification
expect(cookieChanges).toEqual(['foo'])
})
it('should notify observers on consecutive cookie changes when cookieStore is not supported', () => {
Object.defineProperty(window, 'cookieStore', { get: () => undefined, configurable: true })
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
const cookieChanges: Array<string | undefined> = []
subscription = observable.subscribe((change) => cookieChanges.push(change))
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
setCookie(COOKIE_NAME, 'bar', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
expect(cookieChanges).toEqual(['foo', 'bar'])
})
it('should fallback to polling when cookieStore rejects change listeners', () => {
Object.defineProperty(window, 'cookieStore', {
configurable: true,
get: () => ({
addEventListener: () => {
throw new Error("Lightning Web Security: Cannot add 'change' event listener to CookieStore object.")
},
removeEventListener: () => undefined,
}),
})
const observable = createCookieObservable(mockRumConfiguration(), COOKIE_NAME)
let cookieChange: string | undefined
expect(() => {
subscription = observable.subscribe((change) => (cookieChange = change))
}).not.toThrow()
setCookie(COOKIE_NAME, 'foo', COOKIE_DURATION)
clock.tick(WATCH_COOKIE_INTERVAL_DELAY)
expect(cookieChange).toEqual('foo')
})
})