@newrelic/browser-agent 1.234.0 → 1.235.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/README.md +1 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/constants/shared-channel.js +19 -0
- package/dist/cjs/common/harvest/harvest-scheduler.js +21 -5
- package/dist/cjs/common/session/{session-entity.test.js → session-entity.component-test.js} +79 -42
- package/dist/cjs/common/session/session-entity.js +19 -11
- package/dist/cjs/common/timer/interaction-timer.js +1 -1
- package/dist/cjs/common/url/canonicalize-url.test.js +26 -30
- package/dist/cjs/common/util/data-size.test.js +37 -20
- package/dist/cjs/common/util/feature-flags.js +23 -12
- package/dist/cjs/common/util/feature-flags.test.js +84 -0
- package/dist/cjs/common/util/global-scope.js +1 -32
- package/dist/cjs/common/util/global-scope.test.js +72 -0
- package/dist/cjs/common/util/obfuscate.component-test.js +129 -0
- package/dist/cjs/common/util/obfuscate.js +2 -2
- package/dist/cjs/common/util/submit-data.js +3 -3
- package/dist/cjs/common/util/submit-data.test.js +145 -121
- package/dist/cjs/common/wrap/wrap-raf.js +1 -1
- package/dist/cjs/common/wrap/wrap-timer.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/index.js +4 -0
- package/dist/cjs/features/jserrors/instrument/index.js +2 -15
- package/dist/cjs/features/session_replay/aggregate/index.component-test.js +457 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +99 -82
- package/dist/cjs/features/session_replay/replay-mode.js +28 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +222 -99
- package/dist/cjs/features/session_trace/constants.js +1 -3
- package/dist/cjs/features/session_trace/instrument/index.js +0 -16
- package/dist/cjs/features/spa/constants.js +0 -1
- package/dist/cjs/features/utils/agent-session.js +20 -36
- package/dist/cjs/features/utils/agent-session.test.js +211 -0
- package/dist/cjs/features/utils/aggregate-base.js +7 -12
- package/dist/cjs/features/utils/aggregate-base.test.js +110 -0
- package/dist/cjs/features/utils/feature-base.test.js +42 -0
- package/dist/cjs/features/utils/handler-cache.js +28 -23
- package/dist/cjs/features/utils/handler-cache.test.js +53 -0
- package/dist/cjs/features/utils/instrument-base.js +58 -39
- package/dist/cjs/features/utils/instrument-base.test.js +179 -0
- package/dist/cjs/features/utils/lazy-feature-loader.test.js +30 -0
- package/dist/cjs/loaders/agent.js +0 -1
- package/dist/cjs/loaders/api/api.js +1 -1
- package/dist/cjs/loaders/features/featureDependencies.js +2 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/shared-channel.js +12 -0
- package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
- package/dist/esm/common/session/{session-entity.test.js → session-entity.component-test.js} +77 -40
- package/dist/esm/common/session/session-entity.js +17 -11
- package/dist/esm/common/timer/interaction-timer.js +1 -1
- package/dist/esm/common/url/canonicalize-url.test.js +25 -29
- package/dist/esm/common/util/data-size.test.js +35 -20
- package/dist/esm/common/util/feature-flags.js +23 -12
- package/dist/esm/common/util/feature-flags.test.js +80 -0
- package/dist/esm/common/util/global-scope.js +1 -29
- package/dist/esm/common/util/global-scope.test.js +70 -0
- package/dist/esm/common/util/obfuscate.component-test.js +125 -0
- package/dist/esm/common/util/obfuscate.js +2 -2
- package/dist/esm/common/util/submit-data.js +3 -3
- package/dist/esm/common/util/submit-data.test.js +143 -121
- package/dist/esm/common/wrap/wrap-raf.js +1 -1
- package/dist/esm/common/wrap/wrap-timer.js +1 -1
- package/dist/esm/features/jserrors/aggregate/index.js +4 -0
- package/dist/esm/features/jserrors/instrument/index.js +2 -15
- package/dist/esm/features/session_replay/aggregate/index.component-test.js +453 -0
- package/dist/esm/features/session_replay/aggregate/index.js +92 -78
- package/dist/esm/features/session_replay/replay-mode.js +23 -0
- package/dist/esm/features/session_trace/aggregate/index.js +223 -100
- package/dist/esm/features/session_trace/constants.js +0 -1
- package/dist/esm/features/session_trace/instrument/index.js +1 -17
- package/dist/esm/features/spa/constants.js +0 -1
- package/dist/esm/features/utils/agent-session.js +21 -37
- package/dist/esm/features/utils/agent-session.test.js +207 -0
- package/dist/esm/features/utils/aggregate-base.js +7 -12
- package/dist/esm/features/utils/aggregate-base.test.js +108 -0
- package/dist/esm/features/utils/feature-base.test.js +40 -0
- package/dist/esm/features/utils/handler-cache.js +28 -23
- package/dist/esm/features/utils/handler-cache.test.js +51 -0
- package/dist/esm/features/utils/instrument-base.js +58 -39
- package/dist/esm/features/utils/instrument-base.test.js +175 -0
- package/dist/esm/features/utils/lazy-feature-loader.test.js +29 -0
- package/dist/esm/loaders/agent.js +0 -1
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/esm/loaders/features/featureDependencies.js +2 -0
- package/dist/types/common/constants/shared-channel.d.ts +5 -0
- package/dist/types/common/constants/shared-channel.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +2 -0
- package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts +4 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.component-test.d.ts +2 -0
- package/dist/types/common/harvest/harvest.component-test.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.component-test.d.ts +2 -0
- package/dist/types/common/session/session-entity.component-test.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.d.ts +9 -5
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timer/interaction-timer.component-test.d.ts +2 -0
- package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +1 -0
- package/dist/types/common/url/encode.component-test.d.ts +2 -0
- package/dist/types/common/url/encode.component-test.d.ts.map +1 -0
- package/dist/types/common/url/protocol.component-test.d.ts +2 -0
- package/dist/types/common/url/protocol.component-test.d.ts.map +1 -0
- package/dist/types/common/util/feature-flags.d.ts +1 -0
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/global-scope.d.ts +0 -9
- package/dist/types/common/util/global-scope.d.ts.map +1 -1
- package/dist/types/common/util/obfuscate.component-test.d.ts +2 -0
- package/dist/types/common/util/obfuscate.component-test.d.ts.map +1 -0
- package/dist/types/features/jserrors/aggregate/index.d.ts +1 -0
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +2 -0
- package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +1 -0
- package/dist/types/features/session_replay/aggregate/index.d.ts +14 -5
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/replay-mode.d.ts +9 -0
- package/dist/types/features/session_replay/replay-mode.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts +21 -3
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/constants.d.ts +0 -1
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts +0 -2
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/spa/constants.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +6 -1
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/handler-cache.d.ts +12 -11
- package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +17 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/common/constants/shared-channel.js +13 -0
- package/src/common/harvest/harvest-scheduler.js +17 -6
- package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -47
- package/src/common/session/session-entity.js +15 -12
- package/src/common/timer/interaction-timer.js +1 -1
- package/src/common/url/canonicalize-url.test.js +32 -21
- package/src/common/util/data-size.test.js +27 -20
- package/src/common/util/feature-flags.js +24 -12
- package/src/common/util/feature-flags.test.js +98 -0
- package/src/common/util/global-scope.js +0 -26
- package/src/common/util/global-scope.test.js +87 -0
- package/src/common/util/obfuscate.component-test.js +173 -0
- package/src/common/util/obfuscate.js +2 -2
- package/src/common/util/submit-data.js +3 -3
- package/src/common/util/submit-data.test.js +123 -115
- package/src/common/wrap/wrap-raf.js +1 -1
- package/src/common/wrap/wrap-timer.js +1 -1
- package/src/features/jserrors/aggregate/index.js +5 -0
- package/src/features/jserrors/instrument/index.js +2 -15
- package/src/features/session_replay/aggregate/index.component-test.js +368 -0
- package/src/features/session_replay/aggregate/index.js +96 -71
- package/src/features/session_replay/instrument/index.js +0 -1
- package/src/features/session_replay/replay-mode.js +23 -0
- package/src/features/session_trace/aggregate/index.js +198 -79
- package/src/features/session_trace/constants.js +0 -1
- package/src/features/session_trace/instrument/index.js +2 -19
- package/src/features/spa/constants.js +0 -1
- package/src/features/utils/agent-session.js +22 -34
- package/src/features/utils/agent-session.test.js +194 -0
- package/src/features/utils/aggregate-base.js +12 -9
- package/src/features/utils/aggregate-base.test.js +122 -0
- package/src/features/utils/feature-base.test.js +45 -0
- package/src/features/utils/handler-cache.js +29 -23
- package/src/features/utils/handler-cache.test.js +72 -0
- package/src/features/utils/instrument-base.js +45 -29
- package/src/features/utils/instrument-base.test.js +190 -0
- package/src/features/utils/lazy-feature-loader.test.js +37 -0
- package/src/loaders/agent.js +0 -1
- package/src/loaders/api/api.js +2 -2
- package/src/loaders/features/featureDependencies.js +2 -0
- package/dist/cjs/common/storage/local-memory.js +0 -35
- package/dist/cjs/common/storage/local-memory.test.js +0 -20
- package/dist/esm/common/storage/local-memory.js +0 -28
- package/dist/esm/common/storage/local-memory.test.js +0 -18
- package/dist/types/common/storage/local-memory.d.ts +0 -8
- package/dist/types/common/storage/local-memory.d.ts.map +0 -1
- package/src/common/storage/local-memory.js +0 -30
- package/src/common/storage/local-memory.test.js +0 -19
- /package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
- /package/dist/cjs/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
- /package/dist/cjs/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/dist/cjs/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/dist/cjs/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
- /package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
- /package/dist/esm/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
- /package/dist/esm/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/dist/esm/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/dist/esm/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
- /package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
- /package/src/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
- /package/src/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/src/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/src/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
|
@@ -3,30 +3,30 @@
|
|
|
3
3
|
* @jest-environment-options {"html": "<html><head><script></script></head><body></body></html>", "url": "https://example.com/"}
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { faker } from '@faker-js/faker'
|
|
6
7
|
import { submitData } from './submit-data'
|
|
8
|
+
import * as globalScope from './global-scope'
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
jest.mock('./global-scope', () => ({
|
|
10
|
-
__esModule: true,
|
|
11
|
-
get isWorkerScope () {
|
|
12
|
-
return mockWorkerScope()
|
|
13
|
-
}
|
|
14
|
-
}))
|
|
10
|
+
jest.mock('./global-scope')
|
|
15
11
|
|
|
16
12
|
const url = 'https://example.com/api'
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
afterEach(() => {
|
|
19
15
|
jest.restoreAllMocks()
|
|
20
|
-
mockWorkerScope.mockReturnValue(false)
|
|
21
16
|
})
|
|
22
17
|
|
|
23
18
|
describe('submitData.jsonp', () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
jest.replaceProperty(globalScope, 'isWorkerScope', false)
|
|
21
|
+
})
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
delete global.importScripts
|
|
25
|
+
})
|
|
29
26
|
|
|
27
|
+
// This test requires a script tag to exist in the html set by this file's jest-environment-options header block.
|
|
28
|
+
test('should return an HTMLScriptElement when called from a web window environment', () => {
|
|
29
|
+
const jsonp = faker.datatype.uuid()
|
|
30
30
|
const result = submitData.jsonp({ url, jsonp })
|
|
31
31
|
|
|
32
32
|
expect(result).toBeInstanceOf(HTMLScriptElement)
|
|
@@ -35,125 +35,141 @@ describe('submitData.jsonp', () => {
|
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
test('should try to use importScripts when called from a worker scope', () => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const jsonp = 'callback'
|
|
41
|
-
|
|
38
|
+
jest.replaceProperty(globalScope, 'isWorkerScope', true)
|
|
42
39
|
global.importScripts = jest.fn()
|
|
43
40
|
|
|
41
|
+
const jsonp = faker.datatype.uuid()
|
|
44
42
|
submitData.jsonp({ url, jsonp })
|
|
45
43
|
|
|
46
|
-
expect(importScripts).toHaveBeenCalledWith(url + '&jsonp=' + jsonp)
|
|
47
|
-
|
|
48
|
-
delete global.importScripts
|
|
44
|
+
expect(global.importScripts).toHaveBeenCalledWith(url + '&jsonp=' + jsonp)
|
|
49
45
|
})
|
|
50
46
|
|
|
51
|
-
test('should fall back to an xhrGet call and return false when
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const jsonp = 'callback'
|
|
55
|
-
|
|
47
|
+
test('should fall back to an xhrGet call and return false when importScripts throws an error', () => {
|
|
48
|
+
jest.replaceProperty(globalScope, 'isWorkerScope', true)
|
|
56
49
|
jest.spyOn(submitData, 'xhrGet').mockImplementation(jest.fn())
|
|
50
|
+
global.importScripts = jest.fn().mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
57
51
|
|
|
52
|
+
const jsonp = faker.datatype.uuid()
|
|
58
53
|
const result = submitData.jsonp({ url, jsonp })
|
|
59
54
|
|
|
60
55
|
expect(result).toBe(false)
|
|
61
|
-
expect(
|
|
56
|
+
expect(global.importScripts).toHaveBeenCalledWith(url + '&jsonp=' + jsonp)
|
|
57
|
+
expect(submitData.xhrGet).toHaveBeenCalledWith({ url: url + '&jsonp=' + jsonp })
|
|
62
58
|
})
|
|
63
59
|
|
|
64
|
-
test('should not throw an error
|
|
65
|
-
jest.
|
|
60
|
+
test('should not throw an error when xhrGet throws an error', () => {
|
|
61
|
+
jest.replaceProperty(globalScope, 'isWorkerScope', true)
|
|
62
|
+
jest.spyOn(submitData, 'xhrGet').mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
63
|
+
global.importScripts = jest.fn().mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
66
64
|
|
|
67
|
-
const jsonp =
|
|
65
|
+
const jsonp = faker.datatype.uuid()
|
|
68
66
|
|
|
69
|
-
expect(() => {
|
|
70
|
-
submitData.jsonp({ url, jsonp })
|
|
71
|
-
}).not.toThrow()
|
|
67
|
+
expect(() => submitData.jsonp({ url, jsonp })).not.toThrow()
|
|
72
68
|
})
|
|
73
|
-
})
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const result = submitData.xhrGet({ url })
|
|
78
|
-
expect(result).toBeInstanceOf(XMLHttpRequest)
|
|
79
|
-
})
|
|
70
|
+
test('should not throw an error when element insertion fails', () => {
|
|
71
|
+
jest.spyOn(document, 'createElement').mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
80
72
|
|
|
81
|
-
|
|
82
|
-
expect(() => {
|
|
83
|
-
submitData.xhrGet({})
|
|
84
|
-
}).not.toThrow()
|
|
85
|
-
})
|
|
73
|
+
const jsonp = faker.datatype.uuid()
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
expect(() => {
|
|
89
|
-
submitData.xhrGet({ url: 'invalid url' })
|
|
90
|
-
}).not.toThrow()
|
|
75
|
+
expect(() => submitData.jsonp({ url, jsonp })).not.toThrow()
|
|
91
76
|
})
|
|
92
77
|
})
|
|
93
78
|
|
|
94
|
-
describe('submitData.
|
|
95
|
-
test('should
|
|
79
|
+
describe('submitData.xhrGet', () => {
|
|
80
|
+
test('xhrGet should call xhr with GET as the method', () => {
|
|
81
|
+
jest.spyOn(submitData, 'xhr').mockReturnValue(new XMLHttpRequest())
|
|
82
|
+
|
|
96
83
|
const result = submitData.xhrGet({ url })
|
|
97
|
-
expect(result).toBeInstanceOf(XMLHttpRequest)
|
|
98
|
-
})
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
expect((
|
|
102
|
-
submitData.xhr({})
|
|
103
|
-
}).not.toThrow()
|
|
85
|
+
expect(result).toBeInstanceOf(XMLHttpRequest)
|
|
86
|
+
expect(submitData.xhr).toHaveBeenCalledWith({ url, sync: false, method: 'GET' })
|
|
104
87
|
})
|
|
88
|
+
})
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
describe('submitData.xhr', () => {
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
jest.spyOn(global, 'XMLHttpRequest').mockImplementation(function () {
|
|
93
|
+
this.prototype = XMLHttpRequest.prototype
|
|
94
|
+
this.open = jest.fn()
|
|
95
|
+
this.send = jest.fn()
|
|
96
|
+
this.setRequestHeader = jest.fn()
|
|
97
|
+
|
|
98
|
+
this._withCredentials = false
|
|
99
|
+
Object.defineProperty(this, 'withCredentials', {
|
|
100
|
+
get: jest.fn(() => this._withCredentials),
|
|
101
|
+
set: jest.fn((val) => this._withCredentials = val)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
110
104
|
})
|
|
111
105
|
|
|
112
|
-
test('should send
|
|
113
|
-
|
|
106
|
+
test('should make and send an xhr with default values', () => {
|
|
107
|
+
const result = submitData.xhr({ url })
|
|
108
|
+
const xhr = jest.mocked(global.XMLHttpRequest).mock.instances[0]
|
|
114
109
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
expect(
|
|
110
|
+
expect(result).toBeInstanceOf(XMLHttpRequest)
|
|
111
|
+
expect(result.withCredentials).toBe(true)
|
|
112
|
+
expect(xhr.open).toHaveBeenCalledWith('POST', url, true)
|
|
113
|
+
expect(xhr.setRequestHeader).toHaveBeenCalledWith('content-type', 'text/plain')
|
|
114
|
+
expect(xhr.send).toHaveBeenCalledWith(null)
|
|
118
115
|
})
|
|
119
116
|
|
|
120
|
-
test('should send
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
test('should send the body when provided', () => {
|
|
118
|
+
const body = faker.lorem.paragraph()
|
|
119
|
+
submitData.xhr({ url, body })
|
|
120
|
+
const xhr = jest.mocked(global.XMLHttpRequest).mock.instances[0]
|
|
124
121
|
|
|
125
|
-
expect(
|
|
122
|
+
expect(xhr.send).toHaveBeenCalledWith(body)
|
|
126
123
|
})
|
|
127
124
|
|
|
128
|
-
|
|
129
|
-
test('should send a request synchronously if specified', () => {
|
|
130
|
-
jest.spyOn(XMLHttpRequest.prototype, 'open')
|
|
131
|
-
|
|
125
|
+
test('should set async to false', () => {
|
|
132
126
|
submitData.xhr({ url, sync: true })
|
|
127
|
+
const xhr = jest.mocked(global.XMLHttpRequest).mock.instances[0]
|
|
133
128
|
|
|
134
|
-
expect(
|
|
129
|
+
expect(xhr.open).toHaveBeenCalledWith('POST', url, false)
|
|
135
130
|
})
|
|
136
131
|
|
|
137
|
-
test('should
|
|
138
|
-
|
|
132
|
+
test('should use the provided method', () => {
|
|
133
|
+
submitData.xhr({ url, method: 'HEAD' })
|
|
134
|
+
const xhr = jest.mocked(global.XMLHttpRequest).mock.instances[0]
|
|
139
135
|
|
|
140
|
-
|
|
136
|
+
expect(xhr.open).toHaveBeenCalledWith('HEAD', url, true)
|
|
137
|
+
})
|
|
141
138
|
|
|
139
|
+
test('should use the provided headers', () => {
|
|
140
|
+
const headers = [{ key: faker.lorem.word(), value: faker.datatype.uuid() }]
|
|
142
141
|
submitData.xhr({ url, headers })
|
|
142
|
+
const xhr = jest.mocked(global.XMLHttpRequest).mock.instances[0]
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
})
|
|
144
|
+
expect(xhr.setRequestHeader).not.toHaveBeenCalledWith('content-type', 'text/plain')
|
|
145
|
+
expect(xhr.setRequestHeader).toHaveBeenCalledWith(headers[0].key, headers[0].value)
|
|
147
146
|
})
|
|
148
147
|
|
|
149
|
-
test('should
|
|
150
|
-
|
|
148
|
+
test('should not throw an error if withCredentials is not supported', () => {
|
|
149
|
+
jest.spyOn(global, 'XMLHttpRequest').mockImplementation(function () {
|
|
150
|
+
this.prototype = XMLHttpRequest.prototype
|
|
151
|
+
this.open = jest.fn()
|
|
152
|
+
this.send = jest.fn()
|
|
153
|
+
this.setRequestHeader = jest.fn()
|
|
154
|
+
})
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
expect(() => submitData.xhr({ url })).not.toThrow()
|
|
157
|
+
})
|
|
153
158
|
|
|
154
|
-
|
|
159
|
+
test('should not throw an error if setRequestHeader throws an error', () => {
|
|
160
|
+
jest.spyOn(global, 'XMLHttpRequest').mockImplementation(function () {
|
|
161
|
+
this.prototype = XMLHttpRequest.prototype
|
|
162
|
+
this.open = jest.fn()
|
|
163
|
+
this.send = jest.fn()
|
|
164
|
+
this.setRequestHeader = jest.fn()
|
|
155
165
|
|
|
156
|
-
|
|
166
|
+
Object.defineProperty(this, 'withCredentials', {
|
|
167
|
+
get: jest.fn().mockImplementation(() => { throw new Error(faker.lorem.sentence()) }),
|
|
168
|
+
set: jest.fn().mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
expect(() => submitData.xhr({ url })).not.toThrow()
|
|
157
173
|
})
|
|
158
174
|
})
|
|
159
175
|
|
|
@@ -164,55 +180,47 @@ describe('submitData.img', () => {
|
|
|
164
180
|
const result = submitData.img({ url: imageUrl })
|
|
165
181
|
|
|
166
182
|
expect(result).toBeInstanceOf(HTMLImageElement)
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
test('should not throw an error if URL is not provided', () => {
|
|
170
|
-
expect(() => {
|
|
171
|
-
submitData.img({})
|
|
172
|
-
}).not.toThrow()
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
test('should set the src attribute of the image element to the provided URL', () => {
|
|
176
|
-
const imageUrl = 'https://example.com/image.png'
|
|
177
|
-
|
|
178
|
-
const result = submitData.img({ url: imageUrl })
|
|
179
|
-
|
|
180
183
|
expect(result.src).toBe(imageUrl)
|
|
181
184
|
})
|
|
182
185
|
})
|
|
183
186
|
|
|
184
187
|
describe('submitData.beacon', () => {
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
afterEach(() => {
|
|
189
|
+
delete window.navigator.sendBeacon
|
|
190
|
+
})
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
192
|
+
test('should return true when beacon request succeeds', () => {
|
|
193
|
+
window.navigator.sendBeacon = jest.fn().mockReturnValue(true)
|
|
191
194
|
|
|
195
|
+
const body = faker.lorem.paragraph()
|
|
192
196
|
const result = submitData.beacon({ url, body })
|
|
193
197
|
|
|
194
198
|
expect(result).toBe(true)
|
|
199
|
+
expect(window.navigator.sendBeacon).toHaveBeenCalledWith(url, body)
|
|
195
200
|
})
|
|
196
201
|
|
|
197
|
-
test('should return false when beacon request
|
|
198
|
-
|
|
202
|
+
test('should return false when beacon request returns false', () => {
|
|
203
|
+
window.navigator.sendBeacon = jest.fn().mockReturnValue(false)
|
|
199
204
|
|
|
200
|
-
|
|
201
|
-
bind: jest.fn(() => () => { throw new Error('message') })
|
|
202
|
-
}
|
|
205
|
+
const result = submitData.beacon({ url })
|
|
203
206
|
|
|
204
|
-
|
|
207
|
+
expect(result).toBe(false)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('should return false when beacon request throws an error', () => {
|
|
211
|
+
window.navigator.sendBeacon = jest.fn(() => { throw new Error(faker.lorem.sentence()) })
|
|
212
|
+
|
|
213
|
+
const result = submitData.beacon({ url })
|
|
205
214
|
|
|
206
215
|
expect(result).toBe(false)
|
|
207
216
|
})
|
|
208
217
|
|
|
209
|
-
test('should
|
|
210
|
-
|
|
218
|
+
test('should always bind window.navigator to the sendBeacon function', () => {
|
|
219
|
+
window.navigator.sendBeacon = jest.fn().mockReturnValue(true)
|
|
220
|
+
window.navigator.sendBeacon.bind = jest.fn(() => {})
|
|
211
221
|
|
|
212
|
-
|
|
222
|
+
submitData.beacon({ url })
|
|
213
223
|
|
|
214
|
-
expect(()
|
|
215
|
-
submitData.beacon({ url, body })
|
|
216
|
-
}).toThrow()
|
|
224
|
+
expect(window.navigator.sendBeacon.bind).toHaveBeenCalledWith(window.navigator)
|
|
217
225
|
})
|
|
218
226
|
})
|
|
@@ -32,6 +32,7 @@ export class Aggregate extends AggregateBase {
|
|
|
32
32
|
super(agentIdentifier, aggregator, FEATURE_NAME)
|
|
33
33
|
|
|
34
34
|
this.stackReported = {}
|
|
35
|
+
this.observedAt = {}
|
|
35
36
|
this.pageviewReported = {}
|
|
36
37
|
this.errorCache = {}
|
|
37
38
|
this.currentBody
|
|
@@ -171,6 +172,7 @@ export class Aggregate extends AggregateBase {
|
|
|
171
172
|
if (!this.stackReported[bucketHash]) {
|
|
172
173
|
this.stackReported[bucketHash] = true
|
|
173
174
|
params.stack_trace = truncateSize(stackInfo.stackString)
|
|
175
|
+
this.observedAt[bucketHash] = agentRuntime.offset + time
|
|
174
176
|
} else {
|
|
175
177
|
params.browser_stack_hash = stringHashCode(stackInfo.stackString)
|
|
176
178
|
}
|
|
@@ -186,6 +188,9 @@ export class Aggregate extends AggregateBase {
|
|
|
186
188
|
this.pageviewReported[bucketHash] = true
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
if (agentRuntime?.session?.state?.sessionReplay) params.hasReplay = true
|
|
192
|
+
params.firstOccurrenceTimestamp = this.observedAt[bucketHash]
|
|
193
|
+
|
|
189
194
|
var type = internal ? 'ierr' : 'err'
|
|
190
195
|
var newMetrics = { time: time }
|
|
191
196
|
|
|
@@ -38,7 +38,7 @@ export class Instrument extends InstrumentBase {
|
|
|
38
38
|
return true
|
|
39
39
|
})
|
|
40
40
|
this.thrown = true
|
|
41
|
-
|
|
41
|
+
handle('err', [err, now()], undefined, FEATURE_NAMES.jserrors, thisInstrument.ee)
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
thisInstrument.ee.on('fn-end', function () {
|
|
@@ -89,7 +89,7 @@ export class Instrument extends InstrumentBase {
|
|
|
89
89
|
|
|
90
90
|
try {
|
|
91
91
|
if (this.skipNext) this.skipNext -= 1
|
|
92
|
-
else
|
|
92
|
+
else handle('err', [errorObj || new UncaughtException(message, filename, lineno), now()], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
93
93
|
} catch (e) {
|
|
94
94
|
try {
|
|
95
95
|
handle('ierr', [e, now(), true], undefined, FEATURE_NAMES.jserrors, this.ee)
|
|
@@ -113,19 +113,6 @@ function UncaughtException (message, filename, lineno) {
|
|
|
113
113
|
this.line = lineno
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
/**
|
|
117
|
-
* Adds a timestamp and emits the 'err' event, which the error aggregator listens for
|
|
118
|
-
* @param {Error} err
|
|
119
|
-
* @param {boolean} doNotStamp
|
|
120
|
-
* @param {ContextualEE} ee
|
|
121
|
-
*/
|
|
122
|
-
function notice (err, doNotStamp, ee) {
|
|
123
|
-
// by default add timestamp, unless specifically told not to
|
|
124
|
-
// this is to preserve existing behavior
|
|
125
|
-
var time = (!doNotStamp) ? now() : null
|
|
126
|
-
handle('err', [err, time], undefined, FEATURE_NAMES.jserrors, ee)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
116
|
/**
|
|
130
117
|
* Attempts to cast an unhandledPromiseRejection reason (reject(...)) to an Error object
|
|
131
118
|
* @param {*} reason - The reason property from an unhandled promise rejection
|