@openobserve/browser-core 0.3.2-beta.3 → 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,267 +0,0 @@
|
|
|
1
|
-
import type { Clock } from '../../test'
|
|
2
|
-
import { mockClock } from '../../test'
|
|
3
|
-
import type { PageMayExitEvent } from '../browser/pageMayExitObservable'
|
|
4
|
-
import { Observable } from '../tools/observable'
|
|
5
|
-
import type { FlushController, FlushEvent } from './flushController'
|
|
6
|
-
import { createFlushController, FLUSH_DURATION_LIMIT, MESSAGES_LIMIT } from './flushController'
|
|
7
|
-
import { RECOMMENDED_REQUEST_BYTES_LIMIT } from './httpRequest'
|
|
8
|
-
|
|
9
|
-
const BYTES_LIMIT = RECOMMENDED_REQUEST_BYTES_LIMIT
|
|
10
|
-
// Arbitrary message size that is below the BYTES_LIMIT
|
|
11
|
-
const SMALL_MESSAGE_BYTE_COUNT = 2
|
|
12
|
-
|
|
13
|
-
describe('flushController', () => {
|
|
14
|
-
let clock: Clock
|
|
15
|
-
let flushController: FlushController
|
|
16
|
-
let flushSpy: jasmine.Spy<(event: FlushEvent) => void>
|
|
17
|
-
let pageMayExitObservable: Observable<PageMayExitEvent>
|
|
18
|
-
let sessionExpireObservable: Observable<void>
|
|
19
|
-
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
clock = mockClock()
|
|
22
|
-
pageMayExitObservable = new Observable()
|
|
23
|
-
sessionExpireObservable = new Observable()
|
|
24
|
-
flushController = createFlushController({
|
|
25
|
-
pageMayExitObservable,
|
|
26
|
-
sessionExpireObservable,
|
|
27
|
-
})
|
|
28
|
-
flushSpy = jasmine.createSpy()
|
|
29
|
-
flushController.flushObservable.subscribe(flushSpy)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('when flushing, the event contains a reason, the bytes count and the messages count', () => {
|
|
33
|
-
const messagesCount = 3
|
|
34
|
-
for (let i = 0; i < messagesCount; i += 1) {
|
|
35
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
36
|
-
flushController.notifyAfterAddMessage()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
pageMayExitObservable.notify({ reason: 'before_unload' })
|
|
40
|
-
|
|
41
|
-
expect(flushSpy).toHaveBeenCalledOnceWith({
|
|
42
|
-
reason: jasmine.any(String),
|
|
43
|
-
bytesCount: messagesCount * SMALL_MESSAGE_BYTE_COUNT,
|
|
44
|
-
messagesCount,
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
describe('page exit', () => {
|
|
49
|
-
it('notifies when the page is exiting', () => {
|
|
50
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
51
|
-
flushController.notifyAfterAddMessage()
|
|
52
|
-
pageMayExitObservable.notify({ reason: 'before_unload' })
|
|
53
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('flush reason should be the page exit reason', () => {
|
|
57
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
58
|
-
flushController.notifyAfterAddMessage()
|
|
59
|
-
pageMayExitObservable.notify({ reason: 'before_unload' })
|
|
60
|
-
expect(flushSpy.calls.first().args[0].reason).toBe('before_unload')
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('does not notify if no message was added', () => {
|
|
64
|
-
pageMayExitObservable.notify({ reason: 'before_unload' })
|
|
65
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('notifies when the page is exiting even if no message have been fully added yet', () => {
|
|
69
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
70
|
-
pageMayExitObservable.notify({ reason: 'before_unload' })
|
|
71
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
describe('session expire', () => {
|
|
76
|
-
it('notifies when the session expires', () => {
|
|
77
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
78
|
-
flushController.notifyAfterAddMessage()
|
|
79
|
-
sessionExpireObservable.notify()
|
|
80
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('flush reason should be "session_expire"', () => {
|
|
84
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
85
|
-
flushController.notifyAfterAddMessage()
|
|
86
|
-
sessionExpireObservable.notify()
|
|
87
|
-
expect(flushSpy.calls.first().args[0].reason).toBe('session_expire')
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('does not notify if no message was added', () => {
|
|
91
|
-
sessionExpireObservable.notify()
|
|
92
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('notifies when the session expires even if no message have been fully added yet', () => {
|
|
96
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
97
|
-
sessionExpireObservable.notify()
|
|
98
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
describe('bytes limit', () => {
|
|
103
|
-
it('notifies when the bytes limit is reached after adding a message', () => {
|
|
104
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT)
|
|
105
|
-
flushController.notifyAfterAddMessage()
|
|
106
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('flush reason should be "bytes_limit"', () => {
|
|
110
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT)
|
|
111
|
-
flushController.notifyAfterAddMessage()
|
|
112
|
-
expect(flushSpy.calls.first().args[0].reason).toBe('bytes_limit')
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('notifies when the bytes limit will be reached before adding a message', () => {
|
|
116
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
117
|
-
flushController.notifyAfterAddMessage()
|
|
118
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT)
|
|
119
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('does not take removed messages into account', () => {
|
|
123
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
124
|
-
flushController.notifyAfterAddMessage()
|
|
125
|
-
flushController.notifyAfterRemoveMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
126
|
-
|
|
127
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT - SMALL_MESSAGE_BYTE_COUNT)
|
|
128
|
-
flushController.notifyAfterAddMessage()
|
|
129
|
-
|
|
130
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('does not notify when the bytes limit will be reached if no message was added yet', () => {
|
|
134
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT)
|
|
135
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('resets the current bytes count once flushed', () => {
|
|
139
|
-
flushController.notifyBeforeAddMessage(BYTES_LIMIT)
|
|
140
|
-
flushController.notifyAfterAddMessage()
|
|
141
|
-
|
|
142
|
-
flushSpy.calls.reset()
|
|
143
|
-
|
|
144
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
145
|
-
flushController.notifyAfterAddMessage()
|
|
146
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
describe('messages limit', () => {
|
|
151
|
-
it('notifies when the messages limit is reached', () => {
|
|
152
|
-
for (let i = 0; i < MESSAGES_LIMIT; i += 1) {
|
|
153
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
154
|
-
flushController.notifyAfterAddMessage()
|
|
155
|
-
}
|
|
156
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('flush reason should be "messages_limit"', () => {
|
|
160
|
-
for (let i = 0; i < MESSAGES_LIMIT; i += 1) {
|
|
161
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
162
|
-
flushController.notifyAfterAddMessage()
|
|
163
|
-
}
|
|
164
|
-
expect(flushSpy.calls.first().args[0].reason).toBe('messages_limit')
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('does not flush when the message was not fully added yet', () => {
|
|
168
|
-
for (let i = 0; i < MESSAGES_LIMIT - 1; i += 1) {
|
|
169
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
170
|
-
flushController.notifyAfterAddMessage()
|
|
171
|
-
}
|
|
172
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
173
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('does not take removed messages into account', () => {
|
|
177
|
-
for (let i = 0; i < MESSAGES_LIMIT - 1; i += 1) {
|
|
178
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
179
|
-
flushController.notifyAfterAddMessage()
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
flushController.notifyAfterRemoveMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
183
|
-
|
|
184
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
185
|
-
flushController.notifyAfterAddMessage()
|
|
186
|
-
|
|
187
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('resets the messages count when flushed', () => {
|
|
191
|
-
for (let i = 0; i < MESSAGES_LIMIT; i += 1) {
|
|
192
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
193
|
-
flushController.notifyAfterAddMessage()
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
flushSpy.calls.reset()
|
|
197
|
-
|
|
198
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
199
|
-
flushController.notifyAfterAddMessage()
|
|
200
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
201
|
-
})
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
describe('duration limit', () => {
|
|
205
|
-
it('notifies when the duration limit is reached after adding a message', () => {
|
|
206
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
207
|
-
flushController.notifyAfterAddMessage()
|
|
208
|
-
clock.tick(FLUSH_DURATION_LIMIT)
|
|
209
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('flush reason should be "duration_limit"', () => {
|
|
213
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
214
|
-
flushController.notifyAfterAddMessage()
|
|
215
|
-
clock.tick(FLUSH_DURATION_LIMIT)
|
|
216
|
-
expect(flushSpy.calls.first().args[0].reason).toBe('duration_limit')
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
it('does not postpone the duration limit when another message was added', () => {
|
|
220
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
221
|
-
flushController.notifyAfterAddMessage()
|
|
222
|
-
clock.tick(FLUSH_DURATION_LIMIT / 2)
|
|
223
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
224
|
-
flushController.notifyAfterAddMessage()
|
|
225
|
-
clock.tick(FLUSH_DURATION_LIMIT / 2)
|
|
226
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
it('does not notify if no message was added yet', () => {
|
|
230
|
-
clock.tick(FLUSH_DURATION_LIMIT)
|
|
231
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('does not notify if a message was added then removed', () => {
|
|
235
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
236
|
-
flushController.notifyAfterAddMessage()
|
|
237
|
-
flushController.notifyAfterRemoveMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
238
|
-
clock.tick(FLUSH_DURATION_LIMIT)
|
|
239
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('notifies if a message was added, and another was added then removed', () => {
|
|
243
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
244
|
-
flushController.notifyAfterAddMessage()
|
|
245
|
-
|
|
246
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
247
|
-
flushController.notifyAfterAddMessage()
|
|
248
|
-
flushController.notifyAfterRemoveMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
249
|
-
|
|
250
|
-
clock.tick(FLUSH_DURATION_LIMIT)
|
|
251
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('does not notify prematurely if a message was added then removed then another was added', () => {
|
|
255
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
256
|
-
flushController.notifyAfterAddMessage()
|
|
257
|
-
flushController.notifyAfterRemoveMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
258
|
-
clock.tick(FLUSH_DURATION_LIMIT / 2)
|
|
259
|
-
flushController.notifyBeforeAddMessage(SMALL_MESSAGE_BYTE_COUNT)
|
|
260
|
-
flushController.notifyAfterAddMessage()
|
|
261
|
-
clock.tick(FLUSH_DURATION_LIMIT / 2)
|
|
262
|
-
expect(flushSpy).not.toHaveBeenCalled()
|
|
263
|
-
clock.tick(FLUSH_DURATION_LIMIT / 2)
|
|
264
|
-
expect(flushSpy).toHaveBeenCalled()
|
|
265
|
-
})
|
|
266
|
-
})
|
|
267
|
-
})
|
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
collectAsyncCalls,
|
|
3
|
-
mockEndpointBuilder,
|
|
4
|
-
interceptRequests,
|
|
5
|
-
DEFAULT_FETCH_MOCK,
|
|
6
|
-
TOO_MANY_REQUESTS_FETCH_MOCK,
|
|
7
|
-
NETWORK_ERROR_FETCH_MOCK,
|
|
8
|
-
wait,
|
|
9
|
-
} from '../../test'
|
|
10
|
-
import type { Request } from '../../test'
|
|
11
|
-
import type { EndpointBuilder } from '../domain/configuration'
|
|
12
|
-
import { createEndpointBuilder } from '../domain/configuration'
|
|
13
|
-
import { addExperimentalFeatures, resetExperimentalFeatures, ExperimentalFeature } from '../tools/experimentalFeatures'
|
|
14
|
-
import { noop } from '../tools/utils/functionUtils'
|
|
15
|
-
import {
|
|
16
|
-
createHttpRequest,
|
|
17
|
-
fetchKeepAliveStrategy,
|
|
18
|
-
fetchStrategy,
|
|
19
|
-
RECOMMENDED_REQUEST_BYTES_LIMIT,
|
|
20
|
-
} from './httpRequest'
|
|
21
|
-
import type { HttpRequest, HttpRequestEvent } from './httpRequest'
|
|
22
|
-
|
|
23
|
-
describe('httpRequest', () => {
|
|
24
|
-
const ENDPOINT_URL = 'http://my.website'
|
|
25
|
-
let interceptor: ReturnType<typeof interceptRequests>
|
|
26
|
-
let requests: Request[]
|
|
27
|
-
let endpointBuilder: EndpointBuilder
|
|
28
|
-
let request: HttpRequest
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
interceptor = interceptRequests()
|
|
32
|
-
requests = interceptor.requests
|
|
33
|
-
endpointBuilder = mockEndpointBuilder(ENDPOINT_URL)
|
|
34
|
-
request = createHttpRequest([endpointBuilder], noop)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
describe('send', () => {
|
|
38
|
-
it('should use fetch when fetch keepalive is not available', async () => {
|
|
39
|
-
interceptor.withRequest(false)
|
|
40
|
-
|
|
41
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
42
|
-
await interceptor.waitForAllFetchCalls()
|
|
43
|
-
|
|
44
|
-
expect(requests.length).toEqual(1)
|
|
45
|
-
expect(requests[0].type).toBe('fetch')
|
|
46
|
-
expect(requests[0].url).toContain(ENDPOINT_URL)
|
|
47
|
-
expect(requests[0].body).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should use fetch keepalive when the bytes count is correct', async () => {
|
|
51
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
52
|
-
pending('no fetch keepalive support')
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
56
|
-
await interceptor.waitForAllFetchCalls()
|
|
57
|
-
|
|
58
|
-
expect(requests.length).toEqual(1)
|
|
59
|
-
expect(requests[0].type).toBe('fetch-keepalive')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('should use fetch over fetch keepalive when the bytes count is too high', async () => {
|
|
63
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: RECOMMENDED_REQUEST_BYTES_LIMIT })
|
|
64
|
-
await interceptor.waitForAllFetchCalls()
|
|
65
|
-
|
|
66
|
-
expect(requests.length).toEqual(1)
|
|
67
|
-
expect(requests[0].type).toBe('fetch')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should fallback to fetch when fetch keepalive is not queued', async () => {
|
|
71
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
72
|
-
pending('no fetch keepalive support')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const fetchSpy = interceptor.withFetch(NETWORK_ERROR_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
76
|
-
|
|
77
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
78
|
-
|
|
79
|
-
await interceptor.waitForAllFetchCalls()
|
|
80
|
-
await collectAsyncCalls(fetchSpy, 2)
|
|
81
|
-
expect(requests.length).toEqual(2)
|
|
82
|
-
expect(requests[0].type).toBe('fetch-keepalive')
|
|
83
|
-
expect(requests[1].type).toBe('fetch')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('should use retry strategy', async () => {
|
|
87
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
88
|
-
pending('no fetch keepalive support')
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const fetchSpy = interceptor.withFetch(TOO_MANY_REQUESTS_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
92
|
-
|
|
93
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
94
|
-
|
|
95
|
-
await interceptor.waitForAllFetchCalls()
|
|
96
|
-
await collectAsyncCalls(fetchSpy, 2)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('sends the payload to multiple endpoints', async () => {
|
|
100
|
-
const endpointBuilder2 = mockEndpointBuilder('http://my.website2')
|
|
101
|
-
|
|
102
|
-
request = createHttpRequest([endpointBuilder, endpointBuilder2], noop)
|
|
103
|
-
|
|
104
|
-
interceptor.withFetch(DEFAULT_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
105
|
-
|
|
106
|
-
const payloadData = '{"foo":"bar1"}\n{"foo":"bar2"}'
|
|
107
|
-
request.send({ data: payloadData, bytesCount: 10 })
|
|
108
|
-
|
|
109
|
-
await interceptor.waitForAllFetchCalls()
|
|
110
|
-
expect(requests.length).toEqual(2)
|
|
111
|
-
expect(requests[0].url).toContain('http://my.website')
|
|
112
|
-
expect(requests[0].body).toEqual(payloadData)
|
|
113
|
-
expect(requests[1].url).toContain('http://my.website2')
|
|
114
|
-
expect(requests[1].body).toEqual(payloadData)
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
describe('fetchKeepAliveStrategy onResponse', () => {
|
|
119
|
-
it('should be called with intake response when fetch is used', (done) => {
|
|
120
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
121
|
-
pending('no fetch keepalive support')
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interceptor.withFetch(TOO_MANY_REQUESTS_FETCH_MOCK)
|
|
125
|
-
|
|
126
|
-
fetchKeepAliveStrategy(
|
|
127
|
-
endpointBuilder,
|
|
128
|
-
RECOMMENDED_REQUEST_BYTES_LIMIT,
|
|
129
|
-
{ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 },
|
|
130
|
-
(response) => {
|
|
131
|
-
expect(response).toEqual({ status: 429, type: 'cors' })
|
|
132
|
-
done()
|
|
133
|
-
}
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
it('should be called with intake response when fallback to fetch due fetch keepalive not queued', (done) => {
|
|
138
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
139
|
-
pending('no fetch keepalive support')
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
interceptor.withFetch(NETWORK_ERROR_FETCH_MOCK, TOO_MANY_REQUESTS_FETCH_MOCK)
|
|
143
|
-
|
|
144
|
-
fetchKeepAliveStrategy(
|
|
145
|
-
endpointBuilder,
|
|
146
|
-
RECOMMENDED_REQUEST_BYTES_LIMIT,
|
|
147
|
-
{ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 },
|
|
148
|
-
(response) => {
|
|
149
|
-
expect(response).toEqual({ status: 429, type: 'cors' })
|
|
150
|
-
done()
|
|
151
|
-
}
|
|
152
|
-
)
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
it('should be called with intake response when fallback to fetch due to size', (done) => {
|
|
156
|
-
interceptor.withFetch(TOO_MANY_REQUESTS_FETCH_MOCK)
|
|
157
|
-
|
|
158
|
-
fetchKeepAliveStrategy(
|
|
159
|
-
endpointBuilder,
|
|
160
|
-
RECOMMENDED_REQUEST_BYTES_LIMIT,
|
|
161
|
-
{ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: RECOMMENDED_REQUEST_BYTES_LIMIT },
|
|
162
|
-
(response) => {
|
|
163
|
-
expect(response).toEqual({ status: 429, type: 'cors' })
|
|
164
|
-
done()
|
|
165
|
-
}
|
|
166
|
-
)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('fetchStrategy onResponse', () => {
|
|
171
|
-
it('should be called with intake response', (done) => {
|
|
172
|
-
interceptor.withFetch(DEFAULT_FETCH_MOCK)
|
|
173
|
-
|
|
174
|
-
fetchStrategy(endpointBuilder, { data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 }, (response) => {
|
|
175
|
-
expect(response).toEqual({ status: 200, type: 'cors' })
|
|
176
|
-
done()
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('should be called with status 0 when fetch fails', (done) => {
|
|
181
|
-
interceptor.withFetch(NETWORK_ERROR_FETCH_MOCK)
|
|
182
|
-
|
|
183
|
-
fetchStrategy(endpointBuilder, { data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 }, (response) => {
|
|
184
|
-
expect(response).toEqual({ status: 0 })
|
|
185
|
-
done()
|
|
186
|
-
})
|
|
187
|
-
})
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
describe('sendOnExit', () => {
|
|
191
|
-
it('should use fetch when sendBeacon is not defined', async () => {
|
|
192
|
-
interceptor.withSendBeacon(false)
|
|
193
|
-
|
|
194
|
-
request.sendOnExit({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
195
|
-
|
|
196
|
-
await interceptor.waitForAllFetchCalls()
|
|
197
|
-
|
|
198
|
-
expect(requests.length).toEqual(1)
|
|
199
|
-
expect(requests[0].type).toBe('fetch')
|
|
200
|
-
expect(requests[0].url).toContain(ENDPOINT_URL)
|
|
201
|
-
expect(requests[0].body).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
it('should use sendBeacon when the bytes count is correct', () => {
|
|
205
|
-
if (!interceptor.isSendBeaconSupported()) {
|
|
206
|
-
pending('no sendBeacon support')
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
request.sendOnExit({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
210
|
-
|
|
211
|
-
expect(requests.length).toEqual(1)
|
|
212
|
-
expect(requests[0].type).toBe('sendBeacon')
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('should use fetch over sendBeacon when the bytes count is too high', async () => {
|
|
216
|
-
request.sendOnExit({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: RECOMMENDED_REQUEST_BYTES_LIMIT })
|
|
217
|
-
|
|
218
|
-
await interceptor.waitForAllFetchCalls()
|
|
219
|
-
|
|
220
|
-
expect(requests.length).toEqual(1)
|
|
221
|
-
expect(requests[0].type).toBe('fetch')
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
it('should fallback to fetch when sendBeacon is not queued', async () => {
|
|
225
|
-
if (!interceptor.isSendBeaconSupported()) {
|
|
226
|
-
pending('no sendBeacon support')
|
|
227
|
-
}
|
|
228
|
-
interceptor.withSendBeacon(() => false)
|
|
229
|
-
|
|
230
|
-
request.sendOnExit({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
231
|
-
|
|
232
|
-
await interceptor.waitForAllFetchCalls()
|
|
233
|
-
|
|
234
|
-
expect(requests.length).toEqual(1)
|
|
235
|
-
expect(requests[0].type).toBe('fetch')
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
it('should fallback to fetch when sendBeacon throws', async () => {
|
|
239
|
-
if (!interceptor.isSendBeaconSupported()) {
|
|
240
|
-
pending('no sendBeacon support')
|
|
241
|
-
}
|
|
242
|
-
let sendBeaconCalled = false
|
|
243
|
-
interceptor.withSendBeacon(() => {
|
|
244
|
-
sendBeaconCalled = true
|
|
245
|
-
throw new Error('mock sendBeacon error')
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
request.sendOnExit({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
249
|
-
|
|
250
|
-
await interceptor.waitForAllFetchCalls()
|
|
251
|
-
|
|
252
|
-
expect(sendBeaconCalled).toBe(true)
|
|
253
|
-
expect(requests.length).toEqual(1)
|
|
254
|
-
expect(requests[0].type).toBe('fetch')
|
|
255
|
-
})
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
describe('HttpRequestEvent observable', () => {
|
|
259
|
-
const observedEvents: HttpRequestEvent[] = []
|
|
260
|
-
|
|
261
|
-
function latestEvents() {
|
|
262
|
-
const events = [...observedEvents]
|
|
263
|
-
observedEvents.length = 0
|
|
264
|
-
return events
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
beforeEach(() => {
|
|
268
|
-
request.observable.subscribe((event) => {
|
|
269
|
-
observedEvents.push(event)
|
|
270
|
-
})
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
afterEach(() => {
|
|
274
|
-
observedEvents.length = 0
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('should report success for successful requests', async () => {
|
|
278
|
-
interceptor.withFetch(DEFAULT_FETCH_MOCK)
|
|
279
|
-
|
|
280
|
-
const payload = { data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 }
|
|
281
|
-
request.send(payload)
|
|
282
|
-
await interceptor.waitForAllFetchCalls()
|
|
283
|
-
await wait(0)
|
|
284
|
-
|
|
285
|
-
expect(latestEvents()).toEqual([
|
|
286
|
-
{ type: 'success', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
287
|
-
])
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
it('should report failure for failing requests', async () => {
|
|
291
|
-
interceptor.withFetch(TOO_MANY_REQUESTS_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
292
|
-
|
|
293
|
-
const payload = { data: '{"foo":"barX"}\n{"foo":"barY"}', bytesCount: 10 }
|
|
294
|
-
request.send(payload)
|
|
295
|
-
await interceptor.waitForAllFetchCalls()
|
|
296
|
-
await wait(0)
|
|
297
|
-
await interceptor.waitForAllFetchCalls()
|
|
298
|
-
await wait(0)
|
|
299
|
-
|
|
300
|
-
expect(latestEvents()).toEqual([
|
|
301
|
-
{ type: 'failure', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
302
|
-
{ type: 'success', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
303
|
-
])
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
it('should report multiple failures when requests are retried repeatedly', async () => {
|
|
307
|
-
interceptor.withFetch(TOO_MANY_REQUESTS_FETCH_MOCK, TOO_MANY_REQUESTS_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
308
|
-
|
|
309
|
-
const payload = { data: '{"foo":"barA"}\n{"foo":"barB"}', bytesCount: 10 }
|
|
310
|
-
request.send(payload)
|
|
311
|
-
await interceptor.waitForAllFetchCalls()
|
|
312
|
-
await wait(0)
|
|
313
|
-
await interceptor.waitForAllFetchCalls()
|
|
314
|
-
await wait(0)
|
|
315
|
-
await interceptor.waitForAllFetchCalls()
|
|
316
|
-
await wait(0)
|
|
317
|
-
|
|
318
|
-
expect(latestEvents()).toEqual([
|
|
319
|
-
{ type: 'failure', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
320
|
-
{ type: 'failure', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
321
|
-
{ type: 'success', bandwidth: { ongoingByteCount: 0, ongoingRequestCount: 0 }, payload },
|
|
322
|
-
])
|
|
323
|
-
})
|
|
324
|
-
})
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
describe('httpRequest intake parameters', () => {
|
|
328
|
-
const clientToken = 'some_client_token'
|
|
329
|
-
let interceptor: ReturnType<typeof interceptRequests>
|
|
330
|
-
let requests: Request[]
|
|
331
|
-
let endpointBuilder: EndpointBuilder
|
|
332
|
-
let request: HttpRequest
|
|
333
|
-
|
|
334
|
-
beforeEach(() => {
|
|
335
|
-
interceptor = interceptRequests()
|
|
336
|
-
requests = interceptor.requests
|
|
337
|
-
endpointBuilder = createEndpointBuilder({ clientToken }, 'logs')
|
|
338
|
-
request = createHttpRequest([endpointBuilder], noop)
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
it('should have a unique request id', async () => {
|
|
342
|
-
interceptor.withFetch(DEFAULT_FETCH_MOCK, DEFAULT_FETCH_MOCK)
|
|
343
|
-
|
|
344
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
345
|
-
request.send({ data: '{"foo":"bar1"}\n{"foo":"bar2"}', bytesCount: 10 })
|
|
346
|
-
|
|
347
|
-
await interceptor.waitForAllFetchCalls()
|
|
348
|
-
|
|
349
|
-
const search = /dd-request-id=([^&]*)/
|
|
350
|
-
const requestId1 = search.exec(requests[0].url)?.[1]
|
|
351
|
-
const requestId2 = search.exec(requests[1].url)?.[1]
|
|
352
|
-
|
|
353
|
-
expect(requestId1).not.toBe(requestId2)
|
|
354
|
-
expect(requests.length).toEqual(2)
|
|
355
|
-
})
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
describe('httpRequest with AVOID_FETCH_KEEPALIVE feature flag', () => {
|
|
359
|
-
const ENDPOINT_URL = 'http://my.website'
|
|
360
|
-
let interceptor: ReturnType<typeof interceptRequests>
|
|
361
|
-
let requests: Request[]
|
|
362
|
-
let endpointBuilder: EndpointBuilder
|
|
363
|
-
let request: HttpRequest
|
|
364
|
-
|
|
365
|
-
beforeEach(() => {
|
|
366
|
-
interceptor = interceptRequests()
|
|
367
|
-
requests = interceptor.requests
|
|
368
|
-
endpointBuilder = mockEndpointBuilder(ENDPOINT_URL)
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
afterEach(() => {
|
|
372
|
-
resetExperimentalFeatures()
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
it('should use regular fetch (without keepalive) when feature flag is enabled', async () => {
|
|
376
|
-
addExperimentalFeatures([ExperimentalFeature.AVOID_FETCH_KEEPALIVE])
|
|
377
|
-
request = createHttpRequest([endpointBuilder], noop)
|
|
378
|
-
|
|
379
|
-
request.send({ data: '{"foo":"bar"}', bytesCount: 10 })
|
|
380
|
-
await interceptor.waitForAllFetchCalls()
|
|
381
|
-
|
|
382
|
-
expect(requests.length).toEqual(1)
|
|
383
|
-
expect(requests[0].type).toBe('fetch')
|
|
384
|
-
expect(requests[0].url).toContain(ENDPOINT_URL)
|
|
385
|
-
})
|
|
386
|
-
|
|
387
|
-
it('should use fetch keepalive when feature flag is not enabled', async () => {
|
|
388
|
-
if (!interceptor.isFetchKeepAliveSupported()) {
|
|
389
|
-
pending('no fetch keepalive support')
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
request = createHttpRequest([endpointBuilder], noop)
|
|
393
|
-
|
|
394
|
-
request.send({ data: '{"foo":"bar"}', bytesCount: 10 })
|
|
395
|
-
await interceptor.waitForAllFetchCalls()
|
|
396
|
-
|
|
397
|
-
expect(requests.length).toEqual(1)
|
|
398
|
-
expect(requests[0].type).toBe('fetch-keepalive')
|
|
399
|
-
})
|
|
400
|
-
})
|