@newrelic/browser-agent 1.241.0 → 1.243.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/CHANGELOG.md +1465 -0
- package/dist/cjs/cdn/polyfills/lite.js +13 -1
- package/dist/cjs/cdn/polyfills/pro.js +17 -1
- package/dist/cjs/cdn/polyfills/spa.js +18 -1
- package/dist/cjs/common/config/state/init.js +32 -5
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/dom/query-selector.js +16 -0
- package/dist/cjs/common/session/session-entity.js +20 -2
- package/dist/cjs/common/wrap/wrap-function.js +1 -1
- package/dist/cjs/features/ajax/aggregate/index.js +1 -1
- package/dist/cjs/features/session_replay/aggregate/index.js +84 -50
- package/dist/cjs/features/utils/feature-base.js +1 -2
- package/dist/cjs/features/utils/instrument-base.js +1 -0
- package/dist/cjs/loaders/api/api.js +2 -2
- package/dist/cjs/loaders/api/apiAsync.js +0 -37
- package/dist/cjs/loaders/configure/configure.js +1 -1
- package/dist/cjs/loaders/configure/public-path.js +6 -3
- package/dist/esm/cdn/polyfills/lite.js +8 -1
- package/dist/esm/cdn/polyfills/pro.js +13 -2
- package/dist/esm/cdn/polyfills/spa.js +13 -1
- package/dist/esm/common/config/state/init.js +32 -5
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/dom/query-selector.js +9 -0
- package/dist/esm/common/session/session-entity.js +18 -1
- package/dist/esm/common/wrap/wrap-function.js +1 -1
- package/dist/esm/features/ajax/aggregate/index.js +1 -1
- package/dist/esm/features/session_replay/aggregate/index.js +83 -50
- package/dist/esm/features/utils/feature-base.js +1 -2
- package/dist/esm/features/utils/instrument-base.js +1 -0
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/esm/loaders/api/apiAsync.js +1 -36
- package/dist/esm/loaders/configure/configure.js +1 -1
- package/dist/esm/loaders/configure/public-path.js +6 -3
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/dom/query-selector.d.ts +2 -0
- package/dist/types/common/dom/query-selector.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.d.ts +5 -0
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +11 -14
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/feature-base.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
- package/dist/types/loaders/configure/public-path.d.ts +1 -1
- package/dist/types/loaders/configure/public-path.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cdn/polyfills/lite.js +14 -1
- package/src/cdn/polyfills/pro.js +23 -2
- package/src/cdn/polyfills/spa.js +24 -1
- package/src/common/config/state/init.js +33 -4
- package/src/common/dom/query-selector.js +9 -0
- package/src/common/session/session-entity.js +20 -1
- package/src/common/wrap/wrap-function.js +1 -1
- package/src/features/ajax/aggregate/index.js +2 -2
- package/src/features/session_replay/aggregate/index.js +82 -34
- package/src/features/utils/feature-base.js +1 -2
- package/src/features/utils/instrument-base.js +1 -0
- package/src/loaders/api/api.js +1 -2
- package/src/loaders/api/apiAsync.js +1 -39
- package/src/loaders/configure/configure.js +1 -1
- package/src/loaders/configure/public-path.js +6 -3
- package/src/common/aggregate/aggregator.test.js +0 -107
- package/src/common/config/state/configurable.test.js +0 -73
- package/src/common/config/state/info.test.js +0 -31
- package/src/common/config/state/init.test.js +0 -28
- package/src/common/config/state/loader-config.test.js +0 -21
- package/src/common/config/state/runtime.test.js +0 -21
- package/src/common/constants/env.cdn.test.js +0 -7
- package/src/common/constants/env.npm.test.js +0 -7
- package/src/common/constants/env.test.js +0 -7
- package/src/common/constants/runtime.test.js +0 -176
- package/src/common/deny-list/deny-list.test.js +0 -104
- package/src/common/drain/drain.test.js +0 -74
- package/src/common/event-emitter/contextual-ee.component-test.js +0 -293
- package/src/common/event-emitter/handle.test.js +0 -56
- package/src/common/event-emitter/register-handler.test.js +0 -61
- package/src/common/harvest/harvest-scheduler.test.js +0 -492
- package/src/common/harvest/harvest.test.js +0 -813
- package/src/common/ids/id.test.js +0 -92
- package/src/common/ids/unique-id.test.js +0 -58
- package/src/common/session/session-entity.component-test.js +0 -346
- package/src/common/storage/local-storage.test.js +0 -17
- package/src/common/timer/interaction-timer.component-test.js +0 -212
- package/src/common/timer/timer.test.js +0 -99
- package/src/common/timing/nav-timing.test.js +0 -161
- package/src/common/url/canonicalize-url.test.js +0 -45
- package/src/common/url/clean-url.test.js +0 -25
- package/src/common/url/encode.test.js +0 -81
- package/src/common/url/location.test.js +0 -15
- package/src/common/url/parse-url.test.js +0 -110
- package/src/common/url/protocol.test.js +0 -17
- package/src/common/util/console.test.js +0 -34
- package/src/common/util/data-size.test.js +0 -56
- package/src/common/util/feature-flags.test.js +0 -94
- package/src/common/util/get-or-set.test.js +0 -58
- package/src/common/util/invoke.test.js +0 -65
- package/src/common/util/map-own.test.js +0 -52
- package/src/common/util/obfuscate.component-test.js +0 -173
- package/src/common/util/stringify.test.js +0 -49
- package/src/common/util/submit-data.test.js +0 -183
- package/src/common/util/traverse.test.js +0 -50
- package/src/common/vitals/cumulative-layout-shift.test.js +0 -71
- package/src/common/vitals/first-contentful-paint.test.js +0 -124
- package/src/common/vitals/first-input-delay.test.js +0 -88
- package/src/common/vitals/first-paint.test.js +0 -127
- package/src/common/vitals/interaction-to-next-paint.test.js +0 -74
- package/src/common/vitals/largest-contentful-paint.test.js +0 -94
- package/src/common/vitals/long-task.test.js +0 -122
- package/src/common/vitals/time-to-first-byte.test.js +0 -147
- package/src/common/vitals/vital-metric.test.js +0 -171
- package/src/common/wrap/wrap-promise.component-test.js +0 -110
- package/src/features/ajax/instrument/distributed-tracing.test.js +0 -375
- package/src/features/jserrors/aggregate/canonical-function-name.test.js +0 -13
- package/src/features/jserrors/aggregate/compute-stack-trace.test.js +0 -414
- package/src/features/jserrors/aggregate/format-stack-trace.test.js +0 -39
- package/src/features/jserrors/aggregate/string-hash-code.test.js +0 -12
- package/src/features/metrics/aggregate/framework-detection.test.js +0 -332
- package/src/features/page_view_timing/aggregate/index.component-test.js +0 -86
- package/src/features/session_replay/aggregate/index.component-test.js +0 -317
- package/src/features/spa/aggregate/interaction-node.test.js +0 -17
- package/src/features/utils/agent-session.test.js +0 -194
- package/src/features/utils/aggregate-base.test.js +0 -123
- package/src/features/utils/feature-base.test.js +0 -45
- package/src/features/utils/handler-cache.test.js +0 -72
- package/src/features/utils/instrument-base.test.js +0 -216
- package/src/features/utils/lazy-feature-loader.test.js +0 -37
- package/src/loaders/api/api.component-test.js +0 -45
- package/src/loaders/api/api.test.js +0 -85
- package/src/loaders/api/apiAsync.test.js +0 -17
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { HandlerCache } from './handler-cache'
|
|
2
|
-
|
|
3
|
-
jest.useFakeTimers()
|
|
4
|
-
|
|
5
|
-
test('should immediately invoke handler when decision has already been made and is true', () => {
|
|
6
|
-
const handlerCache = new HandlerCache()
|
|
7
|
-
handlerCache.decide(true)
|
|
8
|
-
|
|
9
|
-
const handler = jest.fn()
|
|
10
|
-
handlerCache.settle(handler)
|
|
11
|
-
|
|
12
|
-
expect(handler).toHaveBeenCalled()
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('should not invoke handler when decision has already been made and is false', () => {
|
|
16
|
-
const handlerCache = new HandlerCache()
|
|
17
|
-
handlerCache.decide(false)
|
|
18
|
-
|
|
19
|
-
const handler = jest.fn()
|
|
20
|
-
handlerCache.settle(handler)
|
|
21
|
-
|
|
22
|
-
expect(handler).not.toHaveBeenCalled()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('should cache the handler until a decision is made', () => {
|
|
26
|
-
const handlerCache = new HandlerCache()
|
|
27
|
-
|
|
28
|
-
const handler = jest.fn()
|
|
29
|
-
handlerCache.settle(handler)
|
|
30
|
-
expect(handler).not.toHaveBeenCalled()
|
|
31
|
-
|
|
32
|
-
handlerCache.decide(true)
|
|
33
|
-
expect(handler).toHaveBeenCalled()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('should not invoke handler when decision times out', () => {
|
|
37
|
-
const handlerCache = new HandlerCache()
|
|
38
|
-
jest.advanceTimersByTime(10000)
|
|
39
|
-
|
|
40
|
-
const handler = jest.fn()
|
|
41
|
-
handlerCache.settle(handler)
|
|
42
|
-
|
|
43
|
-
expect(handler).not.toHaveBeenCalled()
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('should clear the timeout when a decision is made', () => {
|
|
47
|
-
jest.spyOn(global, 'setTimeout')
|
|
48
|
-
jest.spyOn(global, 'clearTimeout')
|
|
49
|
-
|
|
50
|
-
const handlerCache = new HandlerCache()
|
|
51
|
-
|
|
52
|
-
const handler = jest.fn()
|
|
53
|
-
handlerCache.settle(handler)
|
|
54
|
-
handlerCache.decide(true)
|
|
55
|
-
|
|
56
|
-
const timeout = jest.mocked(global.setTimeout).mock.results[0].value
|
|
57
|
-
expect(global.clearTimeout).toHaveBeenCalledWith(timeout)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('should not allow another decision after a permanent one', () => {
|
|
61
|
-
jest.spyOn(global, 'clearTimeout')
|
|
62
|
-
|
|
63
|
-
const handlerCache = new HandlerCache()
|
|
64
|
-
|
|
65
|
-
const handler = jest.fn()
|
|
66
|
-
handlerCache.settle(handler)
|
|
67
|
-
handlerCache.permanentlyDecide(false)
|
|
68
|
-
handlerCache.decide(true)
|
|
69
|
-
|
|
70
|
-
expect(global.clearTimeout).toHaveBeenCalledTimes(1)
|
|
71
|
-
expect(handler).not.toHaveBeenCalled()
|
|
72
|
-
})
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { faker } from '@faker-js/faker'
|
|
2
|
-
import { InstrumentBase } from './instrument-base'
|
|
3
|
-
import { FeatureBase } from './feature-base'
|
|
4
|
-
import { drain, registerDrain } from '../../common/drain/drain'
|
|
5
|
-
import { onWindowLoad } from '../../common/window/load'
|
|
6
|
-
import { lazyFeatureLoader } from './lazy-feature-loader'
|
|
7
|
-
import { getConfigurationValue } from '../../common/config/config'
|
|
8
|
-
import { setupAgentSession } from './agent-session'
|
|
9
|
-
import { warn } from '../../common/util/console'
|
|
10
|
-
import * as globalScopeModule from '../../common/constants/runtime'
|
|
11
|
-
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
12
|
-
|
|
13
|
-
jest.enableAutomock()
|
|
14
|
-
jest.unmock('./instrument-base')
|
|
15
|
-
jest.unmock('../../loaders/features/features')
|
|
16
|
-
jest.mock('../../common/drain/drain', () => ({
|
|
17
|
-
__esModule: true,
|
|
18
|
-
drain: jest.fn(),
|
|
19
|
-
registerDrain: jest.fn()
|
|
20
|
-
}))
|
|
21
|
-
jest.mock('../../common/window/load', () => ({
|
|
22
|
-
__esModule: true,
|
|
23
|
-
onWindowLoad: jest.fn()
|
|
24
|
-
}))
|
|
25
|
-
jest.mock('../../common/constants/runtime', () => ({
|
|
26
|
-
__esModule: true,
|
|
27
|
-
isBrowserScope: undefined,
|
|
28
|
-
isWorkerScope: undefined
|
|
29
|
-
}))
|
|
30
|
-
jest.mock('../../common/config/config', () => ({
|
|
31
|
-
__esModule: true,
|
|
32
|
-
getConfigurationValue: jest.fn()
|
|
33
|
-
}))
|
|
34
|
-
jest.mock('../../common/config/config', () => ({
|
|
35
|
-
__esModule: true,
|
|
36
|
-
getConfigurationValue: jest.fn().mockReturnValue({}),
|
|
37
|
-
originals: {
|
|
38
|
-
MO: jest.fn()
|
|
39
|
-
}
|
|
40
|
-
}))
|
|
41
|
-
jest.mock('./feature-base', () => ({
|
|
42
|
-
__esModule: true,
|
|
43
|
-
FeatureBase: jest.fn(function (...args) {
|
|
44
|
-
this.agentIdentifier = args[0]
|
|
45
|
-
this.aggregator = args[1]
|
|
46
|
-
this.featureName = args[2]
|
|
47
|
-
})
|
|
48
|
-
}))
|
|
49
|
-
jest.mock('./agent-session', () => ({
|
|
50
|
-
__esModule: true,
|
|
51
|
-
setupAgentSession: jest.fn()
|
|
52
|
-
}))
|
|
53
|
-
|
|
54
|
-
let agentIdentifier
|
|
55
|
-
let aggregator
|
|
56
|
-
let featureName
|
|
57
|
-
let mockAggregate
|
|
58
|
-
|
|
59
|
-
beforeEach(() => {
|
|
60
|
-
jest.replaceProperty(globalScopeModule, 'isBrowserScope', true)
|
|
61
|
-
jest.replaceProperty(globalScopeModule, 'isWorkerScope', false)
|
|
62
|
-
|
|
63
|
-
agentIdentifier = faker.datatype.uuid()
|
|
64
|
-
aggregator = {}
|
|
65
|
-
featureName = faker.datatype.uuid()
|
|
66
|
-
|
|
67
|
-
mockAggregate = jest.fn()
|
|
68
|
-
jest.mocked(lazyFeatureLoader).mockResolvedValue({ Aggregate: mockAggregate })
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('should construct a new instrument', () => {
|
|
72
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
|
|
73
|
-
|
|
74
|
-
expect(FeatureBase).toHaveBeenCalledWith(agentIdentifier, aggregator, featureName)
|
|
75
|
-
expect(instrument.featAggregate).toBeUndefined()
|
|
76
|
-
expect(instrument.auto).toEqual(true)
|
|
77
|
-
expect(instrument.abortHandler).toBeUndefined()
|
|
78
|
-
expect(registerDrain).toHaveBeenCalledWith(agentIdentifier, featureName)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('should not immediately drain', () => {
|
|
82
|
-
new InstrumentBase(agentIdentifier, aggregator, featureName, false)
|
|
83
|
-
|
|
84
|
-
expect(registerDrain).not.toHaveBeenCalled()
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test('should import aggregator on window load', async () => {
|
|
88
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
|
|
89
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
90
|
-
instrument.importAggregator(aggregateArgs)
|
|
91
|
-
|
|
92
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
93
|
-
await windowLoadCallback()
|
|
94
|
-
|
|
95
|
-
expect(onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true)
|
|
96
|
-
expect(lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate')
|
|
97
|
-
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('should immediately import aggregator in worker scope', async () => {
|
|
101
|
-
jest.replaceProperty(globalScopeModule, 'isBrowserScope', false)
|
|
102
|
-
jest.replaceProperty(globalScopeModule, 'isWorkerScope', true)
|
|
103
|
-
|
|
104
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
|
|
105
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
106
|
-
instrument.importAggregator(aggregateArgs)
|
|
107
|
-
|
|
108
|
-
// In worker scope, we cannot wait on importLater method
|
|
109
|
-
await new Promise(process.nextTick)
|
|
110
|
-
|
|
111
|
-
expect(onWindowLoad).not.toHaveBeenCalled()
|
|
112
|
-
expect(lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate')
|
|
113
|
-
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('should import the session manager and replay aggregate for new session', async () => {
|
|
117
|
-
jest.mocked(getConfigurationValue).mockReturnValue(true)
|
|
118
|
-
jest.mocked(setupAgentSession).mockReturnValue({
|
|
119
|
-
isNew: true
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, FEATURE_NAMES.sessionReplay)
|
|
123
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
124
|
-
instrument.importAggregator(aggregateArgs)
|
|
125
|
-
|
|
126
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
127
|
-
await windowLoadCallback()
|
|
128
|
-
|
|
129
|
-
expect(getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled')
|
|
130
|
-
expect(setupAgentSession).toHaveBeenCalledWith(agentIdentifier)
|
|
131
|
-
expect(lazyFeatureLoader).toHaveBeenCalledWith(FEATURE_NAMES.sessionReplay, 'aggregate')
|
|
132
|
-
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs)
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
test('should import the session manager and replay aggregate when a recording is active', async () => {
|
|
136
|
-
jest.mocked(getConfigurationValue).mockReturnValue(true)
|
|
137
|
-
jest.mocked(setupAgentSession).mockReturnValue({
|
|
138
|
-
isNew: false,
|
|
139
|
-
state: {
|
|
140
|
-
sessionReplay: 1
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, FEATURE_NAMES.sessionReplay)
|
|
145
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
146
|
-
instrument.importAggregator(aggregateArgs)
|
|
147
|
-
|
|
148
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
149
|
-
await windowLoadCallback()
|
|
150
|
-
|
|
151
|
-
expect(getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled')
|
|
152
|
-
expect(setupAgentSession).toHaveBeenCalledWith(agentIdentifier)
|
|
153
|
-
expect(lazyFeatureLoader).toHaveBeenCalledWith(FEATURE_NAMES.sessionReplay, 'aggregate')
|
|
154
|
-
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
test('should not import session aggregate when session is not new and a recording is not active', async () => {
|
|
158
|
-
jest.mocked(getConfigurationValue).mockReturnValue(true)
|
|
159
|
-
jest.mocked(setupAgentSession).mockReturnValue({
|
|
160
|
-
isNew: false,
|
|
161
|
-
state: {
|
|
162
|
-
sessionReplay: 0
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, FEATURE_NAMES.sessionReplay)
|
|
167
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
168
|
-
instrument.importAggregator(aggregateArgs)
|
|
169
|
-
|
|
170
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
171
|
-
await windowLoadCallback()
|
|
172
|
-
|
|
173
|
-
expect(getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled')
|
|
174
|
-
expect(setupAgentSession).toHaveBeenCalledWith(agentIdentifier)
|
|
175
|
-
expect(drain).toHaveBeenCalledWith(agentIdentifier, FEATURE_NAMES.sessionReplay)
|
|
176
|
-
expect(lazyFeatureLoader).not.toHaveBeenCalled()
|
|
177
|
-
expect(mockAggregate).not.toHaveBeenCalled()
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
test('feature still imports by default even when setupAgentSession throws an error', async () => {
|
|
181
|
-
jest.mocked(getConfigurationValue).mockReturnValue(true)
|
|
182
|
-
jest.mocked(setupAgentSession).mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
|
|
183
|
-
|
|
184
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
|
|
185
|
-
const aggregateArgs = { [faker.datatype.uuid()]: faker.lorem.sentence() }
|
|
186
|
-
instrument.abortHandler = jest.fn()
|
|
187
|
-
instrument.importAggregator(aggregateArgs)
|
|
188
|
-
|
|
189
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
190
|
-
await windowLoadCallback()
|
|
191
|
-
|
|
192
|
-
expect(onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true)
|
|
193
|
-
expect(instrument.abortHandler).not.toHaveBeenCalled()
|
|
194
|
-
expect(warn).toHaveBeenCalledWith(expect.stringContaining('A problem occurred when starting up session manager'), expect.any(Error))
|
|
195
|
-
expect(lazyFeatureLoader).toHaveBeenCalled()
|
|
196
|
-
expect(mockAggregate).toHaveBeenCalled()
|
|
197
|
-
await expect(instrument.onAggregateImported).resolves.toBe(true)
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
test('no uncaught async exception is thrown when an import fails', async () => {
|
|
201
|
-
jest.mocked(lazyFeatureLoader).mockRejectedValue(new Error('ChunkLoadError')) // () => { throw new Error('ChunkLoadError: loading chunk xxx failed.') })
|
|
202
|
-
const mockOnError = jest.fn()
|
|
203
|
-
global.onerror = mockOnError
|
|
204
|
-
|
|
205
|
-
const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
|
|
206
|
-
instrument.abortHandler = jest.fn()
|
|
207
|
-
instrument.importAggregator()
|
|
208
|
-
|
|
209
|
-
const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
|
|
210
|
-
await windowLoadCallback()
|
|
211
|
-
|
|
212
|
-
expect(warn).toHaveBeenNthCalledWith(2, expect.stringContaining(`Downloading and initializing ${featureName} failed`), expect.any(Error))
|
|
213
|
-
expect(instrument.abortHandler).toHaveBeenCalled()
|
|
214
|
-
await expect(instrument.onAggregateImported).resolves.toBe(false)
|
|
215
|
-
expect(mockOnError).not.toHaveBeenCalled()
|
|
216
|
-
})
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { faker } from '@faker-js/faker'
|
|
2
|
-
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
3
|
-
import { lazyFeatureLoader } from './lazy-feature-loader'
|
|
4
|
-
|
|
5
|
-
// Use enableAutomock to make it easier to mock all the things that get imported by the aggregators
|
|
6
|
-
jest.enableAutomock()
|
|
7
|
-
// Unmock the file under test and the constants file
|
|
8
|
-
jest.unmock('../../loaders/features/features')
|
|
9
|
-
jest.unmock('./lazy-feature-loader')
|
|
10
|
-
|
|
11
|
-
test.each(Object.keys(FEATURE_NAMES))('should import the aggregate for feature %s', async (key) => {
|
|
12
|
-
const featureName = FEATURE_NAMES[key]
|
|
13
|
-
const randomId = faker.datatype.uuid()
|
|
14
|
-
|
|
15
|
-
jest.setMock(`../${featureName}/aggregate`, {
|
|
16
|
-
id: randomId,
|
|
17
|
-
featureName
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const result = await lazyFeatureLoader(featureName, 'aggregate')
|
|
21
|
-
|
|
22
|
-
expect(result.id).toEqual(randomId)
|
|
23
|
-
expect(result.featureName).toEqual(featureName)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('should throw an error when the featureName is not supported', async () => {
|
|
27
|
-
const featureName = faker.datatype.uuid()
|
|
28
|
-
|
|
29
|
-
expect(() => lazyFeatureLoader(featureName, 'aggregate')).toThrow()
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('should return undefined when the featurePart is not supported', async () => {
|
|
33
|
-
const featureName = faker.datatype.uuid()
|
|
34
|
-
const featurePart = faker.datatype.uuid()
|
|
35
|
-
|
|
36
|
-
expect(lazyFeatureLoader(featureName, featurePart)).toBeUndefined()
|
|
37
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { setAPI } from './api'
|
|
2
|
-
import { setInfo, getInfo, setConfiguration } from '../../common/config/config'
|
|
3
|
-
|
|
4
|
-
setInfo('abcd', { licenseKey: '1234', applicationID: '1234' })
|
|
5
|
-
setConfiguration('abcd', {})
|
|
6
|
-
let apiInterface
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
console.warn = jest.fn()
|
|
9
|
-
apiInterface = setAPI('abcd', true)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
jest.restoreAllMocks()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
describe('api', () => {
|
|
17
|
-
describe('setApplicationVersion', () => {
|
|
18
|
-
test('setApplicationVersion sets and unsets ja with valid values', () => {
|
|
19
|
-
apiInterface.setApplicationVersion('1.2.3')
|
|
20
|
-
expect(getInfo('abcd').jsAttributes).toMatchObject({ 'application.version': '1.2.3' })
|
|
21
|
-
|
|
22
|
-
apiInterface.setApplicationVersion(null)
|
|
23
|
-
expect(getInfo('abcd').jsAttributes).toMatchObject({ })
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('setApplicationVersion warns if invalid data is supplied', () => {
|
|
27
|
-
apiInterface.setApplicationVersion(1)
|
|
28
|
-
expect(console.warn).toHaveBeenCalledWith('New Relic: Failed to execute setApplicationVersion. Expected <String | null>, but got <number>.')
|
|
29
|
-
|
|
30
|
-
apiInterface.setApplicationVersion(false)
|
|
31
|
-
expect(console.warn).toHaveBeenCalledWith('New Relic: Failed to execute setApplicationVersion. Expected <String | null>, but got <boolean>.')
|
|
32
|
-
|
|
33
|
-
apiInterface.setApplicationVersion({ version: '1.2.3' })
|
|
34
|
-
expect(console.warn).toHaveBeenCalledWith('New Relic: Failed to execute setApplicationVersion. Expected <String | null>, but got <object>.')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('setApplicationVersion replaces existing data if called twice', () => {
|
|
38
|
-
apiInterface.setApplicationVersion('1.2.3')
|
|
39
|
-
expect(getInfo('abcd').jsAttributes).toMatchObject({ 'application.version': '1.2.3' })
|
|
40
|
-
|
|
41
|
-
apiInterface.setApplicationVersion('4.5.6')
|
|
42
|
-
expect(getInfo('abcd').jsAttributes).toMatchObject({ 'application.version': '4.5.6' })
|
|
43
|
-
})
|
|
44
|
-
})
|
|
45
|
-
})
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { setTopLevelCallers, setAPI } from './api'
|
|
2
|
-
import { gosCDN } from '../../common/window/nreum'
|
|
3
|
-
|
|
4
|
-
jest.enableAutomock()
|
|
5
|
-
jest.unmock('./api')
|
|
6
|
-
|
|
7
|
-
describe('setTopLevelCallers', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
delete gosCDN().initializedAgents
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test('adds all api methods', () => {
|
|
13
|
-
setTopLevelCallers()
|
|
14
|
-
|
|
15
|
-
expect(Object.keys(gosCDN()).length).toEqual(14)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('and runs the corresponding fn under every exposed agent', () => {
|
|
19
|
-
let newrelic = gosCDN()
|
|
20
|
-
newrelic.initializedAgents = {
|
|
21
|
-
abcd: { exposed: true, api: { noticeError: jest.fn() } },
|
|
22
|
-
efgh: { exposed: false, api: { noticeError: jest.fn() } },
|
|
23
|
-
ijkl: { exposed: true, api: { noticeError: jest.fn() } }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const someArgs = ['wtfish', { bop: 'it' }]
|
|
27
|
-
newrelic.noticeError(...someArgs)
|
|
28
|
-
expect(newrelic.initializedAgents.abcd.api.noticeError).toHaveBeenCalledWith(...someArgs)
|
|
29
|
-
expect(newrelic.initializedAgents.efgh.api.noticeError).not.toHaveBeenCalled()
|
|
30
|
-
expect(newrelic.initializedAgents.ijkl.api.noticeError).toHaveBeenCalledWith(...someArgs)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('fn call returns right number of results based on running agent(s)', () => {
|
|
34
|
-
let newrelic = gosCDN()
|
|
35
|
-
newrelic.initializedAgents = {
|
|
36
|
-
abcd: { exposed: true, api: { interaction: jest.fn(() => 'duck') } }
|
|
37
|
-
}
|
|
38
|
-
let ret = newrelic.interaction()
|
|
39
|
-
expect(ret).toEqual('duck')
|
|
40
|
-
|
|
41
|
-
newrelic.initializedAgents.efgh = { exposed: true, api: { interaction: jest.fn(() => 'truck') } }
|
|
42
|
-
ret = newrelic.interaction()
|
|
43
|
-
expect(ret).toEqual(['duck', 'truck'])
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
jest.unmock('../../common/event-emitter/contextual-ee')
|
|
48
|
-
jest.mock('../../common/constants/runtime', () => {
|
|
49
|
-
return {
|
|
50
|
-
__esModule: true,
|
|
51
|
-
isBrowserScope: false
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
describe('setAPI', () => {
|
|
56
|
-
test('also adds all api methods', () => {
|
|
57
|
-
let apiI = setAPI('abcd', true)
|
|
58
|
-
|
|
59
|
-
expect(Object.keys(apiI).length).toEqual(14)
|
|
60
|
-
for (const k of Object.keys(apiI)) { expect(apiI[k]).toBeInstanceOf(Function) }
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('sets up spa interaction api prototype/handle', () => {
|
|
64
|
-
let apiI = setAPI('abcd', true)
|
|
65
|
-
let interactionProto = Object.getPrototypeOf(apiI.interaction())
|
|
66
|
-
|
|
67
|
-
expect(Object.keys(interactionProto).length).toEqual(10)
|
|
68
|
-
for (const k of Object.keys(interactionProto)) { expect(interactionProto[k]).toBeInstanceOf(Function) }
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('calls asyncApi setAPI as well', async () => {
|
|
72
|
-
jest.resetModules()
|
|
73
|
-
let setApiCalled
|
|
74
|
-
let asyncSetApi = new Promise(resolve => { setApiCalled = resolve })
|
|
75
|
-
jest.doMock('./apiAsync', () => {
|
|
76
|
-
return {
|
|
77
|
-
__esModule: true,
|
|
78
|
-
setAPI: jest.fn(id => setApiCalled(id))
|
|
79
|
-
}
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
setAPI('abcd', true)
|
|
83
|
-
await expect(asyncSetApi).resolves.toBe('abcd')
|
|
84
|
-
})
|
|
85
|
-
})
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { setAPI } from './apiAsync'
|
|
2
|
-
import * as register from '../../common/event-emitter/register-handler'
|
|
3
|
-
|
|
4
|
-
jest.enableAutomock()
|
|
5
|
-
jest.unmock('./apiAsync')
|
|
6
|
-
jest.unmock('../../common/event-emitter/contextual-ee')
|
|
7
|
-
|
|
8
|
-
test('setAPI registers all async methods', () => {
|
|
9
|
-
let callSpy = jest.spyOn(register, 'registerHandler')
|
|
10
|
-
setAPI('abcd')
|
|
11
|
-
|
|
12
|
-
expect(callSpy).toHaveBeenCalledTimes(5)
|
|
13
|
-
for (let i = 0; i < 5; i++) {
|
|
14
|
-
expect(callSpy.mock.calls[i][0].startsWith('api-')).toBeTruthy()
|
|
15
|
-
expect(callSpy.mock.calls[i][1]).toBeInstanceOf(Function)
|
|
16
|
-
}
|
|
17
|
-
})
|