@openobserve/browser-core 0.3.3 → 0.3.4

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.
Files changed (83) hide show
  1. package/cjs/boot/init.js +1 -1
  2. package/cjs/domain/configuration/endpointBuilder.js +1 -1
  3. package/cjs/domain/tags.js +1 -1
  4. package/cjs/domain/telemetry/telemetry.js +1 -1
  5. package/cjs/domain/telemetry/telemetryEvent.types.d.ts +1 -1
  6. package/esm/boot/init.js +1 -1
  7. package/esm/domain/configuration/endpointBuilder.js +1 -1
  8. package/esm/domain/tags.js +1 -1
  9. package/esm/domain/telemetry/telemetry.js +1 -1
  10. package/esm/domain/telemetry/telemetryEvent.types.d.ts +1 -1
  11. package/package.json +2 -2
  12. package/src/boot/displayAlreadyInitializedError.spec.ts +18 -0
  13. package/src/boot/init.spec.ts +50 -0
  14. package/src/browser/addEventListener.spec.ts +141 -0
  15. package/src/browser/cookie.spec.ts +53 -0
  16. package/src/browser/fetchObservable.spec.ts +334 -0
  17. package/src/browser/pageMayExitObservable.spec.ts +56 -0
  18. package/src/browser/xhrObservable.spec.ts +405 -0
  19. package/src/domain/allowedTrackingOrigins.spec.ts +210 -0
  20. package/src/domain/bufferedData.spec.ts +34 -0
  21. package/src/domain/configuration/configuration.spec.ts +236 -0
  22. package/src/domain/configuration/endpointBuilder.spec.ts +173 -0
  23. package/src/domain/configuration/transportConfiguration.spec.ts +130 -0
  24. package/src/domain/connectivity/connectivity.spec.ts +50 -0
  25. package/src/domain/console/consoleObservable.spec.ts +151 -0
  26. package/src/domain/context/contextManager.spec.ts +152 -0
  27. package/src/domain/context/contextUtils.spec.ts +26 -0
  28. package/src/domain/context/storeContextManager.spec.ts +103 -0
  29. package/src/domain/contexts/accountContext.spec.ts +99 -0
  30. package/src/domain/contexts/globalContext.spec.ts +88 -0
  31. package/src/domain/contexts/userContext.spec.ts +156 -0
  32. package/src/domain/error/error.spec.ts +294 -0
  33. package/src/domain/error/trackRuntimeError.spec.ts +343 -0
  34. package/src/domain/eventRateLimiter/createEventRateLimiter.spec.ts +119 -0
  35. package/src/domain/extension/extensionUtils.spec.ts +47 -0
  36. package/src/domain/report/reportObservable.spec.ts +71 -0
  37. package/src/domain/session/oldCookiesMigration.spec.ts +76 -0
  38. package/src/domain/session/sessionManager.spec.ts +684 -0
  39. package/src/domain/session/sessionState.spec.ts +88 -0
  40. package/src/domain/session/sessionStore.spec.ts +647 -0
  41. package/src/domain/session/sessionStoreOperations.spec.ts +234 -0
  42. package/src/domain/session/storeStrategies/sessionInCookie.spec.ts +228 -0
  43. package/src/domain/session/storeStrategies/sessionInLocalStorage.spec.ts +75 -0
  44. package/src/domain/synthetics/syntheticsWorkerValues.spec.ts +82 -0
  45. package/src/domain/tags.spec.ts +74 -0
  46. package/src/domain/telemetry/telemetry.spec.ts +494 -0
  47. package/src/domain/telemetry/telemetryEvent.types.ts +1 -1
  48. package/src/domain/trackingConsent.spec.ts +44 -0
  49. package/src/tools/abstractHooks.spec.ts +76 -0
  50. package/src/tools/abstractLifeCycle.spec.ts +46 -0
  51. package/src/tools/boundedBuffer.spec.ts +40 -0
  52. package/src/tools/catchUserErrors.spec.ts +20 -0
  53. package/src/tools/encoder.spec.ts +112 -0
  54. package/src/tools/experimentalFeatures.spec.ts +60 -0
  55. package/src/tools/getZoneJsOriginalValue.spec.ts +36 -0
  56. package/src/tools/instrumentMethod.spec.ts +381 -0
  57. package/src/tools/matchOption.spec.ts +41 -0
  58. package/src/tools/mergeInto.spec.ts +198 -0
  59. package/src/tools/monitor.spec.ts +172 -0
  60. package/src/tools/observable.spec.ts +259 -0
  61. package/src/tools/queueMicrotask.spec.ts +24 -0
  62. package/src/tools/readBytesFromStream.spec.ts +62 -0
  63. package/src/tools/requestIdleCallback.spec.ts +65 -0
  64. package/src/tools/serialisation/jsonStringify.spec.ts +76 -0
  65. package/src/tools/serialisation/sanitize.spec.ts +284 -0
  66. package/src/tools/stackTrace/capturedExceptions.specHelper.ts +316 -0
  67. package/src/tools/stackTrace/computeStackTrace.spec.ts +1007 -0
  68. package/src/tools/stackTrace/handlingStack.spec.ts +20 -0
  69. package/src/tools/taskQueue.spec.ts +60 -0
  70. package/src/tools/timer.spec.ts +76 -0
  71. package/src/tools/utils/browserDetection.spec.ts +120 -0
  72. package/src/tools/utils/byteUtils.spec.ts +29 -0
  73. package/src/tools/utils/functionUtils.spec.ts +229 -0
  74. package/src/tools/utils/numberUtils.spec.ts +27 -0
  75. package/src/tools/utils/stringUtils.spec.ts +74 -0
  76. package/src/tools/utils/typeUtils.spec.ts +25 -0
  77. package/src/tools/utils/urlPolyfill.spec.ts +55 -0
  78. package/src/tools/valueHistory.spec.ts +180 -0
  79. package/src/transport/batch.spec.ts +261 -0
  80. package/src/transport/eventBridge.spec.ts +90 -0
  81. package/src/transport/flushController.spec.ts +267 -0
  82. package/src/transport/httpRequest.spec.ts +400 -0
  83. package/src/transport/sendWithRetryStrategy.spec.ts +393 -0
@@ -0,0 +1,334 @@
1
+ import type { MockFetch, MockFetchManager } from '../../test'
2
+ import { registerCleanupTask, mockFetch } from '../../test'
3
+ import type { Subscription } from '../tools/observable'
4
+ import type { FetchResolveContext, FetchContext } from './fetchObservable'
5
+ import { initFetchObservable, resetFetchObservable, ResponseBodyAction } from './fetchObservable'
6
+
7
+ describe('fetch proxy', () => {
8
+ const FAKE_URL = 'http://fake-url/'
9
+ const FAKE_RELATIVE_URL = '/fake-path'
10
+ const NORMALIZED_FAKE_RELATIVE_URL = `${location.origin}/fake-path`
11
+ let mockFetchManager: MockFetchManager
12
+ let requestsTrackingSubscription: Subscription
13
+ let contextEditionSubscription: Subscription | undefined
14
+ let requests: FetchResolveContext[]
15
+ let originalMockFetch: typeof window.fetch
16
+ let fetch: MockFetch
17
+
18
+ beforeEach(() => {
19
+ mockFetchManager = mockFetch()
20
+ originalMockFetch = window.fetch
21
+
22
+ requests = []
23
+ requestsTrackingSubscription = initFetchObservable().subscribe((context) => {
24
+ if (context.state === 'resolve') {
25
+ requests.push(context)
26
+ }
27
+ })
28
+ fetch = window.fetch as MockFetch
29
+
30
+ registerCleanupTask(() => {
31
+ requestsTrackingSubscription.unsubscribe()
32
+ contextEditionSubscription?.unsubscribe()
33
+ resetFetchObservable()
34
+ })
35
+ })
36
+
37
+ it('should track server error', (done) => {
38
+ fetch(FAKE_URL).resolveWith({ status: 500, responseText: 'fetch error' })
39
+
40
+ mockFetchManager.whenAllComplete(() => {
41
+ const request = requests[0]
42
+ expect(request.method).toEqual('GET')
43
+ expect(request.url).toEqual(FAKE_URL)
44
+ expect(request.status).toEqual(500)
45
+ expect(request.isAborted).toBe(false)
46
+ expect(request.handlingStack).toBeDefined()
47
+ done()
48
+ })
49
+ })
50
+
51
+ it('should track refused fetch', (done) => {
52
+ fetch(FAKE_URL).rejectWith(new Error('fetch error'))
53
+
54
+ mockFetchManager.whenAllComplete(() => {
55
+ const request = requests[0]
56
+ expect(request.method).toEqual('GET')
57
+ expect(request.url).toEqual(FAKE_URL)
58
+ expect(request.status).toEqual(0)
59
+ expect(request.isAborted).toBe(false)
60
+ expect(request.error).toEqual(new Error('fetch error'))
61
+ expect(request.handlingStack).toBeDefined()
62
+ done()
63
+ })
64
+ })
65
+
66
+ it('should track aborted fetch', (done) => {
67
+ fetch(FAKE_URL).abort()
68
+
69
+ mockFetchManager.whenAllComplete(() => {
70
+ const request = requests[0]
71
+ expect(request.method).toEqual('GET')
72
+ expect(request.url).toEqual(FAKE_URL)
73
+ expect(request.status).toEqual(0)
74
+ expect(request.isAborted).toBe(true)
75
+ expect(request.error).toEqual(new DOMException('The user aborted a request', 'AbortError'))
76
+ expect(request.handlingStack).toBeDefined()
77
+ done()
78
+ })
79
+ })
80
+
81
+ it('should track fetch aborted by AbortController', (done) => {
82
+ if (!window.AbortController) {
83
+ pending('AbortController is not supported')
84
+ }
85
+
86
+ const controller = new AbortController()
87
+ void fetch(FAKE_URL, { signal: controller.signal })
88
+ controller.abort('AbortError')
89
+
90
+ mockFetchManager.whenAllComplete(() => {
91
+ const request = requests[0]
92
+ expect(request.method).toEqual('GET')
93
+ expect(request.url).toEqual(FAKE_URL)
94
+ expect(request.status).toEqual(0)
95
+ expect(request.isAborted).toBe(true)
96
+ expect(request.error).toEqual(controller.signal.reason)
97
+ expect(request.handlingStack).toBeDefined()
98
+ done()
99
+ })
100
+ })
101
+
102
+ it('should track opaque fetch', (done) => {
103
+ // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
104
+ fetch(FAKE_URL).resolveWith({ status: 0, type: 'opaque' })
105
+
106
+ mockFetchManager.whenAllComplete(() => {
107
+ const request = requests[0]
108
+ expect(request.method).toEqual('GET')
109
+ expect(request.url).toEqual(FAKE_URL)
110
+ expect(request.status).toEqual(0)
111
+ expect(request.isAborted).toBe(false)
112
+ done()
113
+ })
114
+ })
115
+
116
+ it('should track client error', (done) => {
117
+ fetch(FAKE_URL).resolveWith({ status: 400, responseText: 'Not found' })
118
+
119
+ mockFetchManager.whenAllComplete(() => {
120
+ const request = requests[0]
121
+ expect(request.method).toEqual('GET')
122
+ expect(request.url).toEqual(FAKE_URL)
123
+ expect(request.status).toEqual(400)
124
+ expect(request.isAborted).toBe(false)
125
+ done()
126
+ })
127
+ })
128
+
129
+ it('should get method from input', (done) => {
130
+ fetch(FAKE_URL).resolveWith({ status: 500 })
131
+ fetch(new Request(FAKE_URL)).resolveWith({ status: 500 })
132
+ fetch(new Request(FAKE_URL, { method: 'PUT' })).resolveWith({ status: 500 })
133
+ fetch(new Request(FAKE_URL, { method: 'PUT' }), { method: 'POST' }).resolveWith({ status: 500 })
134
+ fetch(new Request(FAKE_URL), { method: 'POST' }).resolveWith({ status: 500 })
135
+ fetch(FAKE_URL, { method: 'POST' }).resolveWith({ status: 500 })
136
+ fetch(FAKE_URL, { method: 'post' }).resolveWith({ status: 500 })
137
+ fetch(null as any).resolveWith({ status: 500 })
138
+ fetch({ method: 'POST' } as any).resolveWith({ status: 500 })
139
+ fetch(FAKE_URL, { method: null as any }).resolveWith({ status: 500 })
140
+ fetch(FAKE_URL, { method: undefined }).resolveWith({ status: 500 })
141
+
142
+ mockFetchManager.whenAllComplete(() => {
143
+ expect(requests[0].method).toEqual('GET')
144
+ expect(requests[1].method).toEqual('GET')
145
+ expect(requests[2].method).toEqual('PUT')
146
+ expect(requests[3].method).toEqual('POST')
147
+ expect(requests[4].method).toEqual('POST')
148
+ expect(requests[5].method).toEqual('POST')
149
+ expect(requests[6].method).toEqual('POST')
150
+ expect(requests[7].method).toEqual('GET')
151
+ expect(requests[8].method).toEqual('GET')
152
+ expect(requests[9].method).toEqual('NULL')
153
+ expect(requests[10].method).toEqual('GET')
154
+
155
+ done()
156
+ })
157
+ })
158
+
159
+ it('should get the normalized url from input', (done) => {
160
+ fetch(FAKE_URL).rejectWith(new Error('fetch error'))
161
+ fetch(new Request(FAKE_URL)).rejectWith(new Error('fetch error'))
162
+ fetch(null as any).rejectWith(new Error('fetch error'))
163
+ fetch({
164
+ toString() {
165
+ return FAKE_RELATIVE_URL
166
+ },
167
+ } as any).rejectWith(new Error('fetch error'))
168
+ fetch(FAKE_RELATIVE_URL).rejectWith(new Error('fetch error'))
169
+ fetch(new Request(FAKE_RELATIVE_URL)).rejectWith(new Error('fetch error'))
170
+
171
+ mockFetchManager.whenAllComplete(() => {
172
+ expect(requests[0].url).toEqual(FAKE_URL)
173
+ expect(requests[1].url).toEqual(FAKE_URL)
174
+ expect(requests[2].url).toMatch(/\/null$/)
175
+ expect(requests[3].url).toEqual(NORMALIZED_FAKE_RELATIVE_URL)
176
+ expect(requests[4].url).toEqual(NORMALIZED_FAKE_RELATIVE_URL)
177
+ expect(requests[5].url).toEqual(NORMALIZED_FAKE_RELATIVE_URL)
178
+ done()
179
+ })
180
+ })
181
+
182
+ it('should keep promise resolved behavior for Response', (done) => {
183
+ const mockFetchPromise = fetch(FAKE_URL)
184
+ const spy = jasmine.createSpy()
185
+ mockFetchPromise.then(spy).catch(() => {
186
+ fail('Should not have thrown an error!')
187
+ })
188
+ mockFetchPromise.resolveWith({ status: 500 })
189
+
190
+ setTimeout(() => {
191
+ expect(spy).toHaveBeenCalled()
192
+ done()
193
+ })
194
+ })
195
+
196
+ it('should keep promise resolved behavior for any other type', (done) => {
197
+ const mockFetchPromise = fetch(FAKE_URL)
198
+ const spy = jasmine.createSpy()
199
+ mockFetchPromise.then(spy).catch(() => {
200
+ fail('Should not have thrown an error!')
201
+ })
202
+ mockFetchPromise.resolveWith('response' as any)
203
+
204
+ setTimeout(() => {
205
+ expect(spy).toHaveBeenCalled()
206
+ done()
207
+ })
208
+ })
209
+
210
+ it('should keep promise rejected behavior for Error', (done) => {
211
+ const mockFetchPromise = fetch(FAKE_URL)
212
+ const spy = jasmine.createSpy()
213
+ mockFetchPromise.catch(spy)
214
+ mockFetchPromise.rejectWith(new Error('fetch error'))
215
+
216
+ setTimeout(() => {
217
+ expect(spy).toHaveBeenCalled()
218
+ done()
219
+ })
220
+ })
221
+
222
+ it('should keep promise rejected behavior for any other type', (done) => {
223
+ const mockFetchPromise = fetch(FAKE_URL)
224
+ const spy = jasmine.createSpy()
225
+ mockFetchPromise.catch(spy)
226
+ mockFetchPromise.rejectWith('fetch error' as any)
227
+
228
+ setTimeout(() => {
229
+ expect(spy).toHaveBeenCalled()
230
+ done()
231
+ })
232
+ })
233
+
234
+ it('should allow to enhance the context', (done) => {
235
+ type CustomContext = FetchContext & { foo: string }
236
+ contextEditionSubscription = initFetchObservable().subscribe((rawContext) => {
237
+ const context = rawContext as CustomContext
238
+ if (context.state === 'start') {
239
+ context.foo = 'bar'
240
+ }
241
+ })
242
+ fetch(FAKE_URL).resolveWith({ status: 500, responseText: 'fetch error' })
243
+
244
+ mockFetchManager.whenAllComplete(() => {
245
+ expect((requests[0] as CustomContext).foo).toBe('bar')
246
+ done()
247
+ })
248
+ })
249
+
250
+ describe('when unsubscribing', () => {
251
+ it('should stop tracking requests', (done) => {
252
+ requestsTrackingSubscription.unsubscribe()
253
+
254
+ fetch(FAKE_URL).resolveWith({ status: 200, responseText: 'ok' })
255
+
256
+ mockFetchManager.whenAllComplete(() => {
257
+ expect(requests).toEqual([])
258
+ done()
259
+ })
260
+ })
261
+
262
+ it('should restore original window.fetch', () => {
263
+ requestsTrackingSubscription.unsubscribe()
264
+
265
+ expect(window.fetch).toBe(originalMockFetch)
266
+ })
267
+ })
268
+ })
269
+
270
+ describe('fetch proxy with ResponseBodyAction', () => {
271
+ const FAKE_URL = 'http://fake-url/'
272
+ let mockFetchManager: MockFetchManager
273
+ let requestsTrackingSubscription: Subscription
274
+ let requests: FetchResolveContext[]
275
+ let fetch: MockFetch
276
+
277
+ function setupFetchTracking(responseBodyAction: () => ResponseBodyAction) {
278
+ mockFetchManager = mockFetch()
279
+ requests = []
280
+ requestsTrackingSubscription = initFetchObservable({ responseBodyAction }).subscribe((context) => {
281
+ if (context.state === 'resolve') {
282
+ requests.push(context)
283
+ }
284
+ })
285
+ fetch = window.fetch as MockFetch
286
+ }
287
+
288
+ afterEach(() => {
289
+ requestsTrackingSubscription?.unsubscribe()
290
+ resetFetchObservable()
291
+ })
292
+
293
+ it('should collect response body with COLLECT action', (done) => {
294
+ setupFetchTracking(() => ResponseBodyAction.COLLECT)
295
+
296
+ fetch(FAKE_URL).resolveWith({ status: 200, responseText: 'response body content' })
297
+
298
+ mockFetchManager.whenAllComplete(() => {
299
+ expect(requests[0].responseBody).toBe('response body content')
300
+ done()
301
+ })
302
+ })
303
+
304
+ it('should not collect response body with WAIT or IGNORE action', (done) => {
305
+ setupFetchTracking(() => ResponseBodyAction.WAIT)
306
+
307
+ fetch(FAKE_URL).resolveWith({ status: 200, responseText: 'response body content' })
308
+
309
+ mockFetchManager.whenAllComplete(() => {
310
+ expect(requests[0].responseBody).toBeUndefined()
311
+ done()
312
+ })
313
+ })
314
+
315
+ it('should use the highest priority action when multiple getters are registered', (done) => {
316
+ setupFetchTracking(() => ResponseBodyAction.WAIT)
317
+
318
+ initFetchObservable({
319
+ responseBodyAction: () => ResponseBodyAction.COLLECT,
320
+ })
321
+
322
+ registerCleanupTask(() => {
323
+ requestsTrackingSubscription.unsubscribe()
324
+ })
325
+
326
+ fetch = window.fetch as MockFetch
327
+ fetch(FAKE_URL).resolveWith({ status: 200, responseText: 'response body content' })
328
+
329
+ mockFetchManager.whenAllComplete(() => {
330
+ expect(requests[0].responseBody).toBe('response body content')
331
+ done()
332
+ })
333
+ })
334
+ })
@@ -0,0 +1,56 @@
1
+ import type { Configuration } from '../domain/configuration'
2
+ import { createNewEvent, restorePageVisibility, setPageVisibility, registerCleanupTask } from '../../test'
3
+ import type { PageMayExitEvent } from './pageMayExitObservable'
4
+ import { PageExitReason, createPageMayExitObservable } from './pageMayExitObservable'
5
+
6
+ describe('createPageMayExitObservable', () => {
7
+ let onExitSpy: jasmine.Spy<(event: PageMayExitEvent) => void>
8
+ let configuration: Configuration
9
+
10
+ beforeEach(() => {
11
+ onExitSpy = jasmine.createSpy()
12
+ configuration = {} as Configuration
13
+ registerCleanupTask(createPageMayExitObservable(configuration).subscribe(onExitSpy).unsubscribe)
14
+ })
15
+
16
+ afterEach(() => {
17
+ restorePageVisibility()
18
+ })
19
+
20
+ it('notifies when the page fires beforeunload', () => {
21
+ window.dispatchEvent(createNewEvent('beforeunload'))
22
+
23
+ expect(onExitSpy).toHaveBeenCalledOnceWith({ reason: PageExitReason.UNLOADING })
24
+ })
25
+
26
+ it('notifies when the page becomes hidden', () => {
27
+ emulatePageVisibilityChange('hidden')
28
+
29
+ expect(onExitSpy).toHaveBeenCalledOnceWith({ reason: PageExitReason.HIDDEN })
30
+ })
31
+
32
+ it('notifies when the page becomes frozen', () => {
33
+ window.dispatchEvent(createNewEvent('freeze'))
34
+
35
+ expect(onExitSpy).toHaveBeenCalledOnceWith({ reason: PageExitReason.FROZEN })
36
+ })
37
+
38
+ it('notifies multiple times', () => {
39
+ window.dispatchEvent(createNewEvent('beforeunload'))
40
+ window.dispatchEvent(createNewEvent('beforeunload'))
41
+ emulatePageVisibilityChange('hidden')
42
+
43
+ expect(onExitSpy).toHaveBeenCalledTimes(3)
44
+ })
45
+
46
+ it('does not notify when the page becomes visible', () => {
47
+ emulatePageVisibilityChange('visible')
48
+
49
+ expect(onExitSpy).not.toHaveBeenCalled()
50
+ })
51
+
52
+ function emulatePageVisibilityChange(visibility: 'visible' | 'hidden') {
53
+ setPageVisibility(visibility)
54
+ document.dispatchEvent(createNewEvent('visibilitychange'))
55
+ }
56
+ })