@openobserve/browser-core 0.3.2 → 0.3.3
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/cjs/boot/init.js +1 -1
- package/cjs/domain/configuration/endpointBuilder.js +1 -1
- package/cjs/domain/tags.js +1 -1
- package/cjs/domain/telemetry/telemetry.js +1 -1
- package/cjs/domain/telemetry/telemetryEvent.types.d.ts +1 -1
- package/esm/boot/init.js +1 -1
- package/esm/domain/configuration/endpointBuilder.js +1 -1
- package/esm/domain/tags.js +1 -1
- package/esm/domain/telemetry/telemetry.js +1 -1
- package/esm/domain/telemetry/telemetryEvent.types.d.ts +1 -1
- package/package.json +2 -2
- package/src/domain/telemetry/telemetryEvent.types.ts +1 -1
- package/src/boot/displayAlreadyInitializedError.spec.ts +0 -18
- package/src/boot/init.spec.ts +0 -50
- package/src/browser/addEventListener.spec.ts +0 -141
- package/src/browser/cookie.spec.ts +0 -53
- package/src/browser/fetchObservable.spec.ts +0 -334
- package/src/browser/pageMayExitObservable.spec.ts +0 -56
- package/src/browser/xhrObservable.spec.ts +0 -405
- package/src/domain/allowedTrackingOrigins.spec.ts +0 -210
- package/src/domain/bufferedData.spec.ts +0 -34
- package/src/domain/configuration/configuration.spec.ts +0 -236
- package/src/domain/configuration/endpointBuilder.spec.ts +0 -173
- package/src/domain/configuration/transportConfiguration.spec.ts +0 -130
- package/src/domain/connectivity/connectivity.spec.ts +0 -50
- package/src/domain/console/consoleObservable.spec.ts +0 -151
- package/src/domain/context/contextManager.spec.ts +0 -152
- package/src/domain/context/contextUtils.spec.ts +0 -26
- package/src/domain/context/storeContextManager.spec.ts +0 -103
- package/src/domain/contexts/accountContext.spec.ts +0 -99
- package/src/domain/contexts/globalContext.spec.ts +0 -88
- package/src/domain/contexts/userContext.spec.ts +0 -156
- package/src/domain/error/error.spec.ts +0 -294
- package/src/domain/error/trackRuntimeError.spec.ts +0 -343
- package/src/domain/eventRateLimiter/createEventRateLimiter.spec.ts +0 -119
- package/src/domain/extension/extensionUtils.spec.ts +0 -47
- package/src/domain/report/reportObservable.spec.ts +0 -71
- package/src/domain/session/oldCookiesMigration.spec.ts +0 -76
- package/src/domain/session/sessionManager.spec.ts +0 -684
- package/src/domain/session/sessionState.spec.ts +0 -88
- package/src/domain/session/sessionStore.spec.ts +0 -647
- package/src/domain/session/sessionStoreOperations.spec.ts +0 -234
- package/src/domain/session/storeStrategies/sessionInCookie.spec.ts +0 -228
- package/src/domain/session/storeStrategies/sessionInLocalStorage.spec.ts +0 -75
- package/src/domain/synthetics/syntheticsWorkerValues.spec.ts +0 -82
- package/src/domain/tags.spec.ts +0 -74
- package/src/domain/telemetry/telemetry.spec.ts +0 -494
- package/src/domain/trackingConsent.spec.ts +0 -44
- package/src/tools/abstractHooks.spec.ts +0 -76
- package/src/tools/abstractLifeCycle.spec.ts +0 -46
- package/src/tools/boundedBuffer.spec.ts +0 -40
- package/src/tools/catchUserErrors.spec.ts +0 -20
- package/src/tools/encoder.spec.ts +0 -112
- package/src/tools/experimentalFeatures.spec.ts +0 -60
- package/src/tools/getZoneJsOriginalValue.spec.ts +0 -36
- package/src/tools/instrumentMethod.spec.ts +0 -381
- package/src/tools/matchOption.spec.ts +0 -41
- package/src/tools/mergeInto.spec.ts +0 -198
- package/src/tools/monitor.spec.ts +0 -172
- package/src/tools/observable.spec.ts +0 -259
- package/src/tools/queueMicrotask.spec.ts +0 -24
- package/src/tools/readBytesFromStream.spec.ts +0 -62
- package/src/tools/requestIdleCallback.spec.ts +0 -65
- package/src/tools/serialisation/jsonStringify.spec.ts +0 -76
- package/src/tools/serialisation/sanitize.spec.ts +0 -284
- package/src/tools/stackTrace/capturedExceptions.specHelper.ts +0 -316
- package/src/tools/stackTrace/computeStackTrace.spec.ts +0 -1007
- package/src/tools/stackTrace/handlingStack.spec.ts +0 -20
- package/src/tools/taskQueue.spec.ts +0 -60
- package/src/tools/timer.spec.ts +0 -76
- package/src/tools/utils/browserDetection.spec.ts +0 -120
- package/src/tools/utils/byteUtils.spec.ts +0 -29
- package/src/tools/utils/functionUtils.spec.ts +0 -229
- package/src/tools/utils/numberUtils.spec.ts +0 -27
- package/src/tools/utils/stringUtils.spec.ts +0 -74
- package/src/tools/utils/typeUtils.spec.ts +0 -25
- package/src/tools/utils/urlPolyfill.spec.ts +0 -55
- package/src/tools/valueHistory.spec.ts +0 -180
- package/src/transport/batch.spec.ts +0 -261
- package/src/transport/eventBridge.spec.ts +0 -90
- package/src/transport/flushController.spec.ts +0 -267
- package/src/transport/httpRequest.spec.ts +0 -400
- package/src/transport/sendWithRetryStrategy.spec.ts +0 -393
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { buildUrl, getPathName, isValidUrl, normalizeUrl, getPristineWindow } from './urlPolyfill'
|
|
2
|
-
|
|
3
|
-
describe('normalize url', () => {
|
|
4
|
-
it('should resolve absolute paths', () => {
|
|
5
|
-
expect(normalizeUrl('/my/path')).toEqual(`${location.origin}/my/path`)
|
|
6
|
-
})
|
|
7
|
-
|
|
8
|
-
it('should resolve relative paths', () => {
|
|
9
|
-
history.pushState({}, '', '/foo/')
|
|
10
|
-
expect(normalizeUrl('./my/path')).toEqual(`${location.origin}/foo/my/path`)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('should add protocol to relative url', () => {
|
|
14
|
-
expect(normalizeUrl('//foo.com:9876/my/path')).toEqual('http://foo.com:9876/my/path')
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should keep full url unchanged', () => {
|
|
18
|
-
expect(normalizeUrl('https://foo.com/my/path')).toEqual('https://foo.com/my/path')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should keep non http url unchanged', () => {
|
|
22
|
-
expect(normalizeUrl('ftp://foo.com/my/path')).toEqual('ftp://foo.com/my/path')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should keep file url unchanged', () => {
|
|
26
|
-
// On firefox, URL host is empty for file URI: 'https://bugzilla.mozilla.org/show_bug.cgi?id=1578787'
|
|
27
|
-
// In some cases, Mobile Safari also have this issue.
|
|
28
|
-
// As we should follow the browser behavior, having one or the other doesn't matter too much, so
|
|
29
|
-
// let's check for both.
|
|
30
|
-
expect(['file:///my/path', 'file://foo.com/my/path']).toContain(normalizeUrl('file://foo.com/my/path'))
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
describe('isValidUrl', () => {
|
|
35
|
-
it('should ensure url is valid', () => {
|
|
36
|
-
expect(isValidUrl('https://cloud.openobserve.ai/')).toBe(true)
|
|
37
|
-
expect(isValidUrl('https://api.openobserve.ai/')).toBe(true)
|
|
38
|
-
expect(isValidUrl('file://cloud.openobserve.ai')).toBe(true)
|
|
39
|
-
expect(isValidUrl('/plop')).toBe(false)
|
|
40
|
-
expect(isValidUrl('')).toBe(false)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('should return the same result if the URL has been wrongfully overridden between calls', () => {
|
|
44
|
-
expect(isValidUrl('https://cloud.openobserve.ai/')).toBe(true)
|
|
45
|
-
spyOn(window, 'URL').and.throwError('wrong URL override')
|
|
46
|
-
expect(isValidUrl('https://cloud.openobserve.ai')).toBe(true)
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('getPathName', () => {
|
|
51
|
-
it('should retrieve url path name', () => {
|
|
52
|
-
expect(getPathName('http://cloud.openobserve.ai')).toBe('/')
|
|
53
|
-
expect(getPathName('http://cloud.openobserve.ai/foo/bar?a=b#hello')).toBe('/foo/bar')
|
|
54
|
-
})
|
|
55
|
-
})
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import type { Clock } from '../../test'
|
|
2
|
-
import { mockClock } from '../../test'
|
|
3
|
-
import type { Duration, RelativeTime } from './utils/timeUtils'
|
|
4
|
-
import { addDuration, ONE_MINUTE } from './utils/timeUtils'
|
|
5
|
-
import { CLEAR_OLD_VALUES_INTERVAL, type ValueHistory, createValueHistory } from './valueHistory'
|
|
6
|
-
|
|
7
|
-
const EXPIRE_DELAY = 10 * ONE_MINUTE
|
|
8
|
-
const MAX_ENTRIES = 5
|
|
9
|
-
|
|
10
|
-
describe('valueHistory', () => {
|
|
11
|
-
let valueHistory: ValueHistory<string>
|
|
12
|
-
let clock: Clock
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
clock = mockClock()
|
|
16
|
-
valueHistory = createValueHistory({ expireDelay: EXPIRE_DELAY, maxEntries: MAX_ENTRIES })
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
valueHistory.stop()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
describe('find', () => {
|
|
24
|
-
it('should return undefined when there is no active entry and no startTime', () => {
|
|
25
|
-
expect(valueHistory.find()).toBeUndefined()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('should return the value of the first active entry when there is no startTime', () => {
|
|
29
|
-
valueHistory.add('foo', 0 as RelativeTime)
|
|
30
|
-
|
|
31
|
-
expect(valueHistory.find()).toEqual('foo')
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should return undefined if the most recent entry is closed and no startTime', () => {
|
|
35
|
-
valueHistory.add('foo', 0 as RelativeTime).close(5 as RelativeTime)
|
|
36
|
-
|
|
37
|
-
expect(valueHistory.find()).toBeUndefined()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('should return the value of entries matching startTime', () => {
|
|
41
|
-
valueHistory.add('foo', 0 as RelativeTime).close(5 as RelativeTime)
|
|
42
|
-
valueHistory.add('bar', 5 as RelativeTime).close(10 as RelativeTime)
|
|
43
|
-
valueHistory.add('qux', 10 as RelativeTime)
|
|
44
|
-
|
|
45
|
-
expect(valueHistory.find(2 as RelativeTime)).toEqual('foo')
|
|
46
|
-
expect(valueHistory.find(7 as RelativeTime)).toEqual('bar')
|
|
47
|
-
expect(valueHistory.find(10 as RelativeTime)).toEqual('qux')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should return undefined when no entries matches startTime', () => {
|
|
51
|
-
valueHistory.add('foo', 0 as RelativeTime).close(10 as RelativeTime)
|
|
52
|
-
valueHistory.add('bar', 20 as RelativeTime)
|
|
53
|
-
|
|
54
|
-
expect(valueHistory.find(15 as RelativeTime)).toBeUndefined()
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
describe('with `option.returnInactive` true', () => {
|
|
58
|
-
it('should return the value of the closest entry regardless of the being closed', () => {
|
|
59
|
-
valueHistory.add('foo', 0 as RelativeTime).close(10 as RelativeTime)
|
|
60
|
-
valueHistory.add('bar', 20 as RelativeTime)
|
|
61
|
-
expect(valueHistory.find(15 as RelativeTime, { returnInactive: true })).toEqual('foo')
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
describe('findAll', () => {
|
|
67
|
-
it('should return an empty array when there is no active entry and no startTime', () => {
|
|
68
|
-
expect(valueHistory.findAll()).toEqual([])
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should return all active entry value when there is no startTime', () => {
|
|
72
|
-
valueHistory.add('foo', 0 as RelativeTime)
|
|
73
|
-
valueHistory.add('bar', 5 as RelativeTime).close(10 as RelativeTime)
|
|
74
|
-
valueHistory.add('qux', 10 as RelativeTime)
|
|
75
|
-
|
|
76
|
-
expect(valueHistory.findAll()).toEqual(['qux', 'foo'])
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('should return the entries of entries matching startTime', () => {
|
|
80
|
-
valueHistory.add('foo', 0 as RelativeTime).close(6 as RelativeTime)
|
|
81
|
-
valueHistory.add('bar', 5 as RelativeTime).close(8 as RelativeTime)
|
|
82
|
-
valueHistory.add('qux', 10 as RelativeTime)
|
|
83
|
-
|
|
84
|
-
expect(valueHistory.findAll(2 as RelativeTime)).toEqual(['foo'])
|
|
85
|
-
expect(valueHistory.findAll(5 as RelativeTime)).toEqual(['bar', 'foo'])
|
|
86
|
-
expect(valueHistory.findAll(7 as RelativeTime)).toEqual(['bar'])
|
|
87
|
-
expect(valueHistory.findAll(9 as RelativeTime)).toEqual([])
|
|
88
|
-
expect(valueHistory.findAll(10 as RelativeTime)).toEqual(['qux'])
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('should return an empty array when no entry is matching startTime', () => {
|
|
92
|
-
valueHistory.add('foo', 0 as RelativeTime).close(10 as RelativeTime)
|
|
93
|
-
valueHistory.add('bar', 20 as RelativeTime)
|
|
94
|
-
|
|
95
|
-
expect(valueHistory.findAll(15 as RelativeTime)).toEqual([])
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should return all context overlapping with the duration', () => {
|
|
99
|
-
valueHistory.add('foo', 0 as RelativeTime)
|
|
100
|
-
valueHistory.add('bar', 5 as RelativeTime).close(10 as RelativeTime)
|
|
101
|
-
valueHistory.add('baz', 10 as RelativeTime).close(15 as RelativeTime)
|
|
102
|
-
valueHistory.add('qux', 15 as RelativeTime)
|
|
103
|
-
|
|
104
|
-
expect(valueHistory.findAll(0 as RelativeTime, 20 as Duration)).toEqual(['qux', 'baz', 'bar', 'foo'])
|
|
105
|
-
expect(valueHistory.findAll(6 as RelativeTime, 5 as Duration)).toEqual(['baz', 'bar', 'foo'])
|
|
106
|
-
expect(valueHistory.findAll(11 as RelativeTime, 5 as Duration)).toEqual(['qux', 'baz', 'foo'])
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
describe('removing entries', () => {
|
|
111
|
-
it('should not return removed entries', () => {
|
|
112
|
-
valueHistory.add('foo', 0 as RelativeTime).remove()
|
|
113
|
-
expect(valueHistory.find()).toBeUndefined()
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('removing an entry twice should not impact other entries', () => {
|
|
117
|
-
valueHistory.add('bar', 5 as RelativeTime)
|
|
118
|
-
const entry = valueHistory.add('foo', 0 as RelativeTime)
|
|
119
|
-
entry.remove()
|
|
120
|
-
entry.remove()
|
|
121
|
-
expect(valueHistory.find()).toEqual('bar')
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
it('should reset values', () => {
|
|
126
|
-
valueHistory.add('foo', 0 as RelativeTime).close(10 as RelativeTime)
|
|
127
|
-
valueHistory.add('bar', 10 as RelativeTime)
|
|
128
|
-
|
|
129
|
-
valueHistory.reset()
|
|
130
|
-
|
|
131
|
-
expect(valueHistory.find()).toBeUndefined()
|
|
132
|
-
expect(valueHistory.find(0 as RelativeTime)).toBeUndefined()
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
describe('clearing old values', () => {
|
|
136
|
-
it('should clear old values after expiration', () => {
|
|
137
|
-
const originalTime = performance.now() as RelativeTime
|
|
138
|
-
valueHistory.add('foo', originalTime).close(addDuration(originalTime, 10 as Duration))
|
|
139
|
-
clock.tick(10)
|
|
140
|
-
|
|
141
|
-
expect(valueHistory.find(originalTime)).toBeDefined()
|
|
142
|
-
|
|
143
|
-
clock.tick(EXPIRE_DELAY + CLEAR_OLD_VALUES_INTERVAL)
|
|
144
|
-
|
|
145
|
-
expect(valueHistory.find(originalTime)).toBeUndefined()
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it('should clear multiple histories at the same time to avoid race condition', () => {
|
|
149
|
-
const delay = 5
|
|
150
|
-
const originalTime = performance.now() as RelativeTime
|
|
151
|
-
|
|
152
|
-
const valueHistory1 = createValueHistory({ expireDelay: EXPIRE_DELAY })
|
|
153
|
-
clock.tick(delay)
|
|
154
|
-
const valueHistory2 = createValueHistory({ expireDelay: EXPIRE_DELAY })
|
|
155
|
-
|
|
156
|
-
valueHistory1.add('foo', originalTime).close(addDuration(originalTime, 10 as Duration))
|
|
157
|
-
valueHistory2.add('bar', originalTime).close(addDuration(originalTime, 10 as Duration))
|
|
158
|
-
|
|
159
|
-
expect(valueHistory1.find(originalTime)).toBeDefined()
|
|
160
|
-
expect(valueHistory2.find(originalTime)).toBeDefined()
|
|
161
|
-
|
|
162
|
-
clock.tick(EXPIRE_DELAY + CLEAR_OLD_VALUES_INTERVAL - delay)
|
|
163
|
-
|
|
164
|
-
expect(valueHistory1.find(originalTime)).toBeUndefined()
|
|
165
|
-
expect(valueHistory2.find(originalTime)).toBeUndefined()
|
|
166
|
-
|
|
167
|
-
valueHistory1.stop()
|
|
168
|
-
valueHistory2.stop()
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it('should limit the number of entries', () => {
|
|
173
|
-
for (let i = 0; i < MAX_ENTRIES + 1; i++) {
|
|
174
|
-
valueHistory.add(`${i}`, 0 as RelativeTime)
|
|
175
|
-
}
|
|
176
|
-
const values = valueHistory.findAll()
|
|
177
|
-
expect(values.length).toEqual(5)
|
|
178
|
-
expect(values).toEqual(['5', '4', '3', '2', '1'])
|
|
179
|
-
})
|
|
180
|
-
})
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { Observable } from '..'
|
|
2
|
-
import type { MockFlushController } from '../../test'
|
|
3
|
-
import { createMockFlushController } from '../../test'
|
|
4
|
-
import { display } from '../tools/display'
|
|
5
|
-
import type { Encoder } from '../tools/encoder'
|
|
6
|
-
import { createIdentityEncoder } from '../tools/encoder'
|
|
7
|
-
import { createBatch, MESSAGE_BYTES_LIMIT, type Batch } from './batch'
|
|
8
|
-
import type { HttpRequest, HttpRequestEvent } from './httpRequest'
|
|
9
|
-
|
|
10
|
-
describe('batch', () => {
|
|
11
|
-
const BIG_MESSAGE_OVER_BYTES_LIMIT = { message: 'x'.repeat(MESSAGE_BYTES_LIMIT + 1) }
|
|
12
|
-
const SMALL_MESSAGE = { message: 'hello' }
|
|
13
|
-
const SMALL_MESSAGE_BYTES_COUNT = 19
|
|
14
|
-
const SEPARATOR_BYTES_COUNT = 1
|
|
15
|
-
|
|
16
|
-
let batch: Batch
|
|
17
|
-
let transport: {
|
|
18
|
-
observable: Observable<HttpRequestEvent>
|
|
19
|
-
send: jasmine.Spy<HttpRequest['send']>
|
|
20
|
-
sendOnExit: jasmine.Spy<HttpRequest['sendOnExit']>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let flushController: MockFlushController
|
|
24
|
-
let encoder: Encoder<string>
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
transport = {
|
|
28
|
-
observable: new Observable<HttpRequestEvent>(),
|
|
29
|
-
send: jasmine.createSpy(),
|
|
30
|
-
sendOnExit: jasmine.createSpy(),
|
|
31
|
-
} satisfies HttpRequest
|
|
32
|
-
flushController = createMockFlushController()
|
|
33
|
-
encoder = createIdentityEncoder()
|
|
34
|
-
batch = createBatch({ encoder, request: transport, flushController })
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('should send a message', () => {
|
|
38
|
-
batch.add(SMALL_MESSAGE)
|
|
39
|
-
|
|
40
|
-
flushController.notifyFlush()
|
|
41
|
-
|
|
42
|
-
expect(transport.send.calls.mostRecent().args[0]).toEqual({
|
|
43
|
-
data: '{"message":"hello"}',
|
|
44
|
-
bytesCount: SMALL_MESSAGE_BYTES_COUNT,
|
|
45
|
-
encoding: undefined,
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
describe('adding a message', () => {
|
|
50
|
-
it('should add message to the flush controller', () => {
|
|
51
|
-
batch.add(SMALL_MESSAGE)
|
|
52
|
-
|
|
53
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledOnceWith(SMALL_MESSAGE_BYTES_COUNT)
|
|
54
|
-
expect(flushController.notifyAfterAddMessage).toHaveBeenCalledOnceWith(0)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('should consider separators when adding message', () => {
|
|
58
|
-
batch.add(SMALL_MESSAGE)
|
|
59
|
-
batch.add(SMALL_MESSAGE)
|
|
60
|
-
batch.add(SMALL_MESSAGE)
|
|
61
|
-
|
|
62
|
-
expect(flushController.bytesCount).toEqual(
|
|
63
|
-
SMALL_MESSAGE_BYTES_COUNT +
|
|
64
|
-
SEPARATOR_BYTES_COUNT +
|
|
65
|
-
SMALL_MESSAGE_BYTES_COUNT +
|
|
66
|
-
SEPARATOR_BYTES_COUNT +
|
|
67
|
-
SMALL_MESSAGE_BYTES_COUNT
|
|
68
|
-
)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should remove the estimated message bytes count when replacing a message', () => {
|
|
72
|
-
batch.add(SMALL_MESSAGE)
|
|
73
|
-
batch.upsert(SMALL_MESSAGE, 'a')
|
|
74
|
-
|
|
75
|
-
flushController.notifyBeforeAddMessage.calls.reset()
|
|
76
|
-
|
|
77
|
-
batch.upsert(SMALL_MESSAGE, 'a')
|
|
78
|
-
|
|
79
|
-
expect(flushController.notifyAfterRemoveMessage).toHaveBeenCalledOnceWith(SMALL_MESSAGE_BYTES_COUNT)
|
|
80
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledOnceWith(SMALL_MESSAGE_BYTES_COUNT)
|
|
81
|
-
expect(flushController.bytesCount).toEqual(
|
|
82
|
-
// Note: contrary to added messages (see test above), we don't take separators into account
|
|
83
|
-
// when upserting messages, because it's irrelevant: upserted messages size are not yet
|
|
84
|
-
// encoded so the bytes count is only an estimation
|
|
85
|
-
SMALL_MESSAGE_BYTES_COUNT + SMALL_MESSAGE_BYTES_COUNT
|
|
86
|
-
)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should not send a message with a bytes size above the limit', () => {
|
|
90
|
-
const warnSpy = spyOn(display, 'warn')
|
|
91
|
-
batch.add(BIG_MESSAGE_OVER_BYTES_LIMIT)
|
|
92
|
-
|
|
93
|
-
expect(warnSpy).toHaveBeenCalled()
|
|
94
|
-
expect(flushController.notifyBeforeAddMessage).not.toHaveBeenCalled()
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('should adjust the message size after the message has been added', () => {
|
|
98
|
-
const message = { message: '😤' } // JS string length = 2, but 4 bytes once encoded to UTF-8
|
|
99
|
-
batch.add(message)
|
|
100
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledOnceWith(16)
|
|
101
|
-
expect(flushController.notifyAfterAddMessage).toHaveBeenCalledOnceWith(2) // 2 more bytes once encoded
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('should upsert a message for a given key', () => {
|
|
106
|
-
batch.upsert({ message: '1' }, 'a')
|
|
107
|
-
batch.upsert({ message: '2' }, 'a')
|
|
108
|
-
batch.upsert({ message: '3' }, 'b')
|
|
109
|
-
batch.upsert({ message: '4' }, 'c')
|
|
110
|
-
flushController.notifyFlush()
|
|
111
|
-
|
|
112
|
-
expect(transport.send.calls.mostRecent().args[0]).toEqual({
|
|
113
|
-
data: '{"message":"2"}\n{"message":"3"}\n{"message":"4"}',
|
|
114
|
-
bytesCount: jasmine.any(Number),
|
|
115
|
-
encoding: undefined,
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
batch.upsert({ message: '5' }, 'c')
|
|
119
|
-
batch.upsert({ message: '6' }, 'b')
|
|
120
|
-
batch.upsert({ message: '7' }, 'a')
|
|
121
|
-
flushController.notifyFlush()
|
|
122
|
-
|
|
123
|
-
expect(transport.send.calls.mostRecent().args[0]).toEqual({
|
|
124
|
-
data: '{"message":"5"}\n{"message":"6"}\n{"message":"7"}',
|
|
125
|
-
bytesCount: jasmine.any(Number),
|
|
126
|
-
encoding: undefined,
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
batch.upsert({ message: '8' }, 'a')
|
|
130
|
-
batch.upsert({ message: '9' }, 'b')
|
|
131
|
-
batch.upsert({ message: '10' }, 'a')
|
|
132
|
-
batch.upsert({ message: '11' }, 'b')
|
|
133
|
-
flushController.notifyFlush()
|
|
134
|
-
|
|
135
|
-
expect(transport.send.calls.mostRecent().args[0]).toEqual({
|
|
136
|
-
data: '{"message":"10"}\n{"message":"11"}',
|
|
137
|
-
bytesCount: jasmine.any(Number),
|
|
138
|
-
encoding: undefined,
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
describe('flush messages when the page is not exiting or with a synchronous encoder', () => {
|
|
143
|
-
it('should send addend and upserted messages in the same request', () => {
|
|
144
|
-
batch.add({ message: '1' })
|
|
145
|
-
batch.upsert({ message: '2' }, 'a')
|
|
146
|
-
|
|
147
|
-
flushController.notifyFlush()
|
|
148
|
-
|
|
149
|
-
expect(transport.send.calls.mostRecent().args[0]).toEqual({
|
|
150
|
-
data: '{"message":"1"}\n{"message":"2"}',
|
|
151
|
-
bytesCount: jasmine.any(Number),
|
|
152
|
-
encoding: undefined,
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('should encode upserted messages', () => {
|
|
157
|
-
const encoderWriteSpy = spyOn(encoder, 'write')
|
|
158
|
-
|
|
159
|
-
batch.upsert({ message: '2' }, 'a')
|
|
160
|
-
|
|
161
|
-
flushController.notifyFlush()
|
|
162
|
-
|
|
163
|
-
expect(encoderWriteSpy).toHaveBeenCalledOnceWith('{"message":"2"}')
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('should be able to use telemetry in the httpRequest.send', () => {
|
|
167
|
-
transport.send.and.callFake(() => {
|
|
168
|
-
addTelemetryDebugFake()
|
|
169
|
-
})
|
|
170
|
-
const addTelemetryDebugFake = () => batch.add({ message: 'telemetry message' })
|
|
171
|
-
|
|
172
|
-
batch.add({ message: 'normal message' })
|
|
173
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledTimes(1)
|
|
174
|
-
|
|
175
|
-
flushController.notifyFlush()
|
|
176
|
-
expect(transport.send).toHaveBeenCalledTimes(1)
|
|
177
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledTimes(2)
|
|
178
|
-
|
|
179
|
-
flushController.notifyFlush()
|
|
180
|
-
expect(transport.send).toHaveBeenCalledTimes(2)
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
describe('flush messages when the page is exiting and with an asynchronous encoder', () => {
|
|
185
|
-
beforeEach(() => {
|
|
186
|
-
encoder.isAsync = true
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
;[
|
|
191
|
-
{
|
|
192
|
-
title: 'when adding a message, it should be sent in one request',
|
|
193
|
-
add: { message: 1 },
|
|
194
|
-
expectedRequests: ['{"message":1}'],
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
title: 'when upserting a message, it should be sent in one request',
|
|
198
|
-
upsert: { message: 1 },
|
|
199
|
-
expectedRequests: ['{"message":1}'],
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
title: 'when adding a message and upserting another, they should be sent in two separate requests',
|
|
203
|
-
add: { message: 1 },
|
|
204
|
-
upsert: { message: 2 },
|
|
205
|
-
expectedRequests: ['{"message":1}', '{"message":2}'],
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
title:
|
|
209
|
-
'when adding a message and another message is still pending, they should be sent in two separate requests',
|
|
210
|
-
add: { message: 1 },
|
|
211
|
-
pending: { message: 2 },
|
|
212
|
-
expectedRequests: ['{"message":1}', '{"message":2}'],
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
title: 'when upserting a message and another message is still pending, they should be sent in one request',
|
|
216
|
-
upsert: { message: 1 },
|
|
217
|
-
pending: { message: 2 },
|
|
218
|
-
expectedRequests: ['{"message":2}\n{"message":1}'],
|
|
219
|
-
},
|
|
220
|
-
].forEach(({ title, add, upsert, pending, expectedRequests }) => {
|
|
221
|
-
it(title, () => {
|
|
222
|
-
if (add) {
|
|
223
|
-
batch.add(add)
|
|
224
|
-
}
|
|
225
|
-
if (upsert) {
|
|
226
|
-
batch.upsert(upsert, 'a')
|
|
227
|
-
}
|
|
228
|
-
if (pending) {
|
|
229
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
230
|
-
const original = encoder.finishSync
|
|
231
|
-
spyOn(encoder, 'finishSync').and.callFake(() => ({
|
|
232
|
-
...original(),
|
|
233
|
-
pendingData: JSON.stringify(pending),
|
|
234
|
-
}))
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
flushController.notifyFlush('before_unload')
|
|
238
|
-
|
|
239
|
-
expect(transport.sendOnExit.calls.allArgs().map(([payload]) => payload.data)).toEqual(expectedRequests)
|
|
240
|
-
})
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
it('should be able to use telemetry in the httpRequest.sendOnExit', () => {
|
|
244
|
-
transport.sendOnExit.and.callFake(() => {
|
|
245
|
-
addTelemetryDebugFake()
|
|
246
|
-
})
|
|
247
|
-
const addTelemetryDebugFake = () => batch.add({ message: 'telemetry message' })
|
|
248
|
-
|
|
249
|
-
batch.add({ message: 'normal message' })
|
|
250
|
-
batch.upsert({ message: '2' }, 'a')
|
|
251
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledTimes(2)
|
|
252
|
-
|
|
253
|
-
flushController.notifyFlush('before_unload')
|
|
254
|
-
expect(transport.sendOnExit).toHaveBeenCalledTimes(2)
|
|
255
|
-
expect(flushController.notifyBeforeAddMessage).toHaveBeenCalledTimes(4)
|
|
256
|
-
|
|
257
|
-
flushController.notifyFlush('before_unload')
|
|
258
|
-
expect(transport.sendOnExit).toHaveBeenCalledTimes(3)
|
|
259
|
-
})
|
|
260
|
-
})
|
|
261
|
-
})
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { mockEventBridge } from '../../test'
|
|
2
|
-
import { DefaultPrivacyLevel } from '../domain/configuration'
|
|
3
|
-
import type { BrowserWindowWithEventBridge } from './eventBridge'
|
|
4
|
-
import { getEventBridge, canUseEventBridge, BridgeCapability, bridgeSupports } from './eventBridge'
|
|
5
|
-
|
|
6
|
-
describe('canUseEventBridge', () => {
|
|
7
|
-
const allowedWebViewHosts = ['foo.bar']
|
|
8
|
-
|
|
9
|
-
it('should detect when the bridge is present and the webView host is allowed', () => {
|
|
10
|
-
mockEventBridge({ allowedWebViewHosts })
|
|
11
|
-
expect(canUseEventBridge('foo.bar')).toBeTrue()
|
|
12
|
-
expect(canUseEventBridge('baz.foo.bar')).toBeTrue()
|
|
13
|
-
expect(canUseEventBridge('www.foo.bar')).toBeTrue()
|
|
14
|
-
expect(canUseEventBridge('www.qux.foo.bar')).toBeTrue()
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should not detect when the bridge is present and the webView host is not allowed', () => {
|
|
18
|
-
mockEventBridge({ allowedWebViewHosts })
|
|
19
|
-
expect(canUseEventBridge('foo.com')).toBeFalse()
|
|
20
|
-
expect(canUseEventBridge('foo.bar.baz')).toBeFalse()
|
|
21
|
-
expect(canUseEventBridge('bazfoo.bar')).toBeFalse()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('should not detect when the bridge on the parent domain if only the subdomain is allowed', () => {
|
|
25
|
-
mockEventBridge({ allowedWebViewHosts: ['baz.foo.bar'] })
|
|
26
|
-
expect(canUseEventBridge('foo.bar')).toBeFalse()
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should not detect when the bridge is absent', () => {
|
|
30
|
-
expect(canUseEventBridge()).toBeFalse()
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
describe('event bridge send', () => {
|
|
35
|
-
let sendSpy: jasmine.Spy<(msg: string) => void>
|
|
36
|
-
|
|
37
|
-
beforeEach(() => {
|
|
38
|
-
const eventBridge = mockEventBridge()
|
|
39
|
-
sendSpy = spyOn(eventBridge, 'send')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should serialize sent events without view', () => {
|
|
43
|
-
const eventBridge = getEventBridge()!
|
|
44
|
-
|
|
45
|
-
eventBridge.send('view', { foo: 'bar' })
|
|
46
|
-
|
|
47
|
-
expect(sendSpy).toHaveBeenCalledOnceWith('{"eventType":"view","event":{"foo":"bar"}}')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should serialize sent events with view', () => {
|
|
51
|
-
const eventBridge = getEventBridge()!
|
|
52
|
-
|
|
53
|
-
eventBridge.send('view', { foo: 'bar' }, '123')
|
|
54
|
-
|
|
55
|
-
expect(sendSpy).toHaveBeenCalledOnceWith('{"eventType":"view","event":{"foo":"bar"},"view":{"id":"123"}}')
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
describe('event bridge getPrivacyLevel', () => {
|
|
60
|
-
const bridgePrivacyLevel = DefaultPrivacyLevel.MASK
|
|
61
|
-
|
|
62
|
-
beforeEach(() => {
|
|
63
|
-
mockEventBridge({ privacyLevel: bridgePrivacyLevel })
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('should return the privacy level', () => {
|
|
67
|
-
const eventBridge = getEventBridge()!
|
|
68
|
-
|
|
69
|
-
expect(eventBridge.getPrivacyLevel()).toEqual(bridgePrivacyLevel)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('should return undefined if getPrivacyLevel not present in the bridge', () => {
|
|
73
|
-
delete (window as BrowserWindowWithEventBridge).DatadogEventBridge?.getPrivacyLevel
|
|
74
|
-
const eventBridge = getEventBridge()!
|
|
75
|
-
|
|
76
|
-
expect(eventBridge.getPrivacyLevel()).toBeUndefined()
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
describe('bridgeSupports', () => {
|
|
80
|
-
it('should returns true when the bridge supports a capability', () => {
|
|
81
|
-
mockEventBridge({ capabilities: [BridgeCapability.RECORDS] })
|
|
82
|
-
expect(bridgeSupports(BridgeCapability.RECORDS)).toBeTrue()
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should returns false when the bridge does not support a capability', () => {
|
|
86
|
-
mockEventBridge({ capabilities: [] })
|
|
87
|
-
expect(bridgeSupports(BridgeCapability.RECORDS)).toBeFalse()
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
})
|