@newrelic/browser-agent 1.233.1 → 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/event-emitter/contextual-ee.test.js +10 -10
- package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/dist/cjs/common/harvest/harvest-scheduler.js +21 -5
- package/dist/cjs/common/harvest/harvest.component-test.js +224 -0
- package/dist/cjs/common/harvest/harvest.js +4 -11
- 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/url/encode.js +2 -2
- package/dist/cjs/common/util/console.test.js +30 -0
- 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/get-or-set.js +8 -1
- package/dist/cjs/common/util/get-or-set.test.js +47 -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/stringify.test.js +48 -0
- package/dist/cjs/common/util/submit-data.js +18 -18
- package/dist/cjs/common/util/submit-data.test.js +245 -0
- package/dist/cjs/common/util/traverse.js +19 -27
- package/dist/cjs/common/util/traverse.test.js +44 -0
- 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/metrics/aggregate/endpoint-map.js +14 -0
- package/dist/cjs/features/metrics/aggregate/index.js +3 -2
- package/dist/cjs/features/metrics/instrument/index.js +0 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
- 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/configure/configure.js +0 -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/event-emitter/contextual-ee.test.js +10 -10
- package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
- package/dist/esm/common/harvest/harvest.component-test.js +222 -0
- package/dist/esm/common/harvest/harvest.js +4 -11
- 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/url/encode.js +2 -2
- package/dist/esm/common/util/console.test.js +28 -0
- 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/get-or-set.js +8 -1
- package/dist/esm/common/util/get-or-set.test.js +45 -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/stringify.test.js +46 -0
- package/dist/esm/common/util/submit-data.js +18 -18
- package/dist/esm/common/util/submit-data.test.js +241 -0
- package/dist/esm/common/util/traverse.js +19 -27
- package/dist/esm/common/util/traverse.test.js +42 -0
- 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/metrics/aggregate/endpoint-map.js +7 -0
- package/dist/esm/features/metrics/aggregate/index.js +3 -2
- package/dist/esm/features/metrics/instrument/index.js +0 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
- 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/configure/configure.js +0 -1
- package/dist/esm/loaders/features/featureDependencies.js +2 -0
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- 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/context/shared-context.d.ts.map +1 -1
- 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/harvest/harvest.d.ts.map +1 -1
- 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/timer/timer.d.ts.map +1 -1
- 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/get-or-set.d.ts +9 -1
- package/dist/types/common/util/get-or-set.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/common/util/submit-data.d.ts +14 -10
- package/dist/types/common/util/submit-data.d.ts.map +1 -1
- package/dist/types/common/util/traverse.d.ts +10 -1
- package/dist/types/common/util/traverse.d.ts.map +1 -1
- package/dist/types/common/window/nreum.d.ts.map +1 -1
- 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/metrics/aggregate/endpoint-map.d.ts +8 -0
- package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
- package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/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/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
- package/package.json +14 -8
- package/src/common/config/state/init.js +0 -1
- package/src/common/constants/shared-channel.js +13 -0
- package/src/common/context/shared-context.js +0 -1
- package/src/common/event-emitter/contextual-ee.test.js +10 -10
- package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/src/common/harvest/harvest-scheduler.js +17 -6
- package/src/common/harvest/harvest.component-test.js +169 -0
- package/src/common/harvest/harvest.js +5 -9
- package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -48
- package/src/common/session/session-entity.js +15 -12
- package/src/common/timer/interaction-timer.js +1 -1
- package/src/common/timer/timer.js +0 -1
- package/src/common/url/canonicalize-url.test.js +32 -21
- package/src/common/url/encode.js +2 -2
- package/src/common/util/console.test.js +34 -0
- 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/get-or-set.js +8 -1
- package/src/common/util/get-or-set.test.js +58 -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/stringify.test.js +49 -0
- package/src/common/util/submit-data.js +18 -19
- package/src/common/util/submit-data.test.js +226 -0
- package/src/common/util/traverse.js +18 -27
- package/src/common/util/traverse.test.js +50 -0
- package/src/common/window/nreum.js +0 -1
- 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/metrics/aggregate/endpoint-map.js +7 -0
- package/src/features/metrics/aggregate/index.js +3 -2
- package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
- package/src/features/metrics/instrument/index.js +0 -2
- package/src/features/page_view_event/aggregate/index.js +48 -51
- package/src/features/page_view_event/instrument/index.js +0 -1
- 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 -24
- 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/configure/configure.js +0 -1
- 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/cjs/common/util/s-hash.js +0 -19
- package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
- package/dist/esm/common/storage/local-memory.js +0 -28
- package/dist/esm/common/storage/local-memory.test.js +0 -18
- package/dist/esm/common/util/s-hash.js +0 -13
- package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
- package/dist/types/common/storage/local-memory.d.ts +0 -8
- package/dist/types/common/storage/local-memory.d.ts.map +0 -1
- package/dist/types/common/util/s-hash.d.ts +0 -2
- package/dist/types/common/util/s-hash.d.ts.map +0 -1
- package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
- package/dist/types/features/metrics/instrument/workers-helper.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/src/common/util/s-hash.js +0 -14
- package/src/features/metrics/instrument/workers-helper.js +0 -113
- /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/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/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
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { submitData } from '../util/submit-data'
|
|
2
|
+
import { Harvest } from './harvest'
|
|
3
|
+
|
|
4
|
+
jest.mock('../context/shared-context', () => ({
|
|
5
|
+
__esModule: true,
|
|
6
|
+
SharedContext: function () {
|
|
7
|
+
this.sharedContext = {
|
|
8
|
+
agentIdentifier: 'abcd'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}))
|
|
12
|
+
jest.mock('../config/config', () => ({
|
|
13
|
+
__esModule: true,
|
|
14
|
+
getConfigurationValue: jest.fn(),
|
|
15
|
+
getInfo: jest.fn().mockReturnValue({
|
|
16
|
+
errorBeacon: 'example.com',
|
|
17
|
+
licenseKey: 'abcd'
|
|
18
|
+
}),
|
|
19
|
+
getRuntime: jest.fn().mockReturnValue({
|
|
20
|
+
bytesSent: {},
|
|
21
|
+
queryBytesSent: {}
|
|
22
|
+
})
|
|
23
|
+
}))
|
|
24
|
+
jest.mock('../util/submit-data', () => ({
|
|
25
|
+
__esModule: true,
|
|
26
|
+
submitData: {
|
|
27
|
+
xhr: jest.fn(() => ({
|
|
28
|
+
addEventListener: jest.fn()
|
|
29
|
+
})),
|
|
30
|
+
beacon: jest.fn(),
|
|
31
|
+
img: jest.fn()
|
|
32
|
+
}
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
describe('sendX', () => {
|
|
36
|
+
test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', (sendEmptyBody) => {
|
|
37
|
+
const sendCallback = jest.fn()
|
|
38
|
+
const harvester = new Harvest()
|
|
39
|
+
harvester.on('jserrors', () => ({
|
|
40
|
+
body: {},
|
|
41
|
+
qs: {}
|
|
42
|
+
}))
|
|
43
|
+
|
|
44
|
+
harvester.sendX({ endpoint: 'jserrors', cbFinished: sendCallback })
|
|
45
|
+
|
|
46
|
+
expect(sendCallback).toHaveBeenCalledWith({ sent: false })
|
|
47
|
+
expect(submitData.xhr).not.toHaveBeenCalled()
|
|
48
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
49
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('should send request when body is empty and sendEmptyBody is true', () => {
|
|
53
|
+
const harvester = new Harvest()
|
|
54
|
+
harvester.on('jserrors', () => ({
|
|
55
|
+
body: {},
|
|
56
|
+
qs: {}
|
|
57
|
+
}))
|
|
58
|
+
|
|
59
|
+
harvester.sendX({ endpoint: 'jserrors', opts: { sendEmptyBody: true }, cbFinished: jest.fn() })
|
|
60
|
+
|
|
61
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
+
url: expect.stringContaining('https://example.com/jserrors/1/abcd?'),
|
|
63
|
+
body: undefined
|
|
64
|
+
}))
|
|
65
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
66
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test.each([null, undefined, []])('should remove %s values from the body and query string when sending', (emptyValue) => {
|
|
70
|
+
const harvester = new Harvest()
|
|
71
|
+
harvester.on('jserrors', () => ({
|
|
72
|
+
body: { bar: 'foo', empty: emptyValue },
|
|
73
|
+
qs: { foo: 'bar', empty: emptyValue }
|
|
74
|
+
}))
|
|
75
|
+
|
|
76
|
+
harvester.sendX({ endpoint: 'jserrors', cbFinished: jest.fn() })
|
|
77
|
+
|
|
78
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
79
|
+
url: expect.stringContaining('&foo=bar'),
|
|
80
|
+
body: JSON.stringify({ bar: 'foo' })
|
|
81
|
+
}))
|
|
82
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
83
|
+
url: expect.not.stringContaining('&empty'),
|
|
84
|
+
body: expect.not.stringContaining('empty')
|
|
85
|
+
}))
|
|
86
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
87
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', (nonStringValue) => {
|
|
91
|
+
const harvester = new Harvest()
|
|
92
|
+
harvester.on('jserrors', () => ({
|
|
93
|
+
body: { bar: 'foo', nonString: nonStringValue },
|
|
94
|
+
qs: { foo: 'bar', nonString: nonStringValue }
|
|
95
|
+
}))
|
|
96
|
+
|
|
97
|
+
harvester.sendX({ endpoint: 'jserrors', cbFinished: jest.fn() })
|
|
98
|
+
|
|
99
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
100
|
+
url: expect.stringContaining(`&nonString=${nonStringValue}`),
|
|
101
|
+
body: JSON.stringify({ bar: 'foo', nonString: nonStringValue })
|
|
102
|
+
}))
|
|
103
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
104
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('send', () => {
|
|
109
|
+
test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', (sendEmptyBody) => {
|
|
110
|
+
const sendCallback = jest.fn()
|
|
111
|
+
const harvester = new Harvest()
|
|
112
|
+
|
|
113
|
+
harvester.send({ endpoint: 'rum', payload: { qs: {}, body: {} }, opts: { sendEmptyBody }, cbFinished: sendCallback })
|
|
114
|
+
|
|
115
|
+
expect(sendCallback).toHaveBeenCalledWith({ sent: false })
|
|
116
|
+
expect(submitData.xhr).not.toHaveBeenCalled()
|
|
117
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
118
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('should send request when body is empty and sendEmptyBody is true', () => {
|
|
122
|
+
const harvester = new Harvest()
|
|
123
|
+
|
|
124
|
+
harvester.send({ endpoint: 'rum', payload: { qs: {}, body: {} }, opts: { sendEmptyBody: true } })
|
|
125
|
+
|
|
126
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
127
|
+
url: expect.stringContaining('https://example.com/1/abcd?'),
|
|
128
|
+
body: undefined
|
|
129
|
+
}))
|
|
130
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
131
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test.each([null, undefined, []])('should remove %s values from the body and query string when sending', (emptyValue) => {
|
|
135
|
+
const harvester = new Harvest()
|
|
136
|
+
|
|
137
|
+
harvester.send({
|
|
138
|
+
endpoint: 'rum',
|
|
139
|
+
payload: { qs: { foo: 'bar', empty: emptyValue }, body: { bar: 'foo', empty: emptyValue } }
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
143
|
+
url: expect.stringContaining('&foo=bar'),
|
|
144
|
+
body: JSON.stringify({ bar: 'foo' })
|
|
145
|
+
}))
|
|
146
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
147
|
+
url: expect.not.stringContaining('&empty'),
|
|
148
|
+
body: expect.not.stringContaining('empty')
|
|
149
|
+
}))
|
|
150
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
151
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', (nonStringValue) => {
|
|
155
|
+
const harvester = new Harvest()
|
|
156
|
+
|
|
157
|
+
harvester.send({
|
|
158
|
+
endpoint: 'rum',
|
|
159
|
+
payload: { qs: { foo: 'bar', nonString: nonStringValue }, body: { bar: 'foo', nonString: nonStringValue } }
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
163
|
+
url: expect.stringContaining(`&nonString=${nonStringValue}`),
|
|
164
|
+
body: JSON.stringify({ bar: 'foo', nonString: nonStringValue })
|
|
165
|
+
}))
|
|
166
|
+
expect(submitData.img).not.toHaveBeenCalled()
|
|
167
|
+
expect(submitData.beacon).not.toHaveBeenCalled()
|
|
168
|
+
})
|
|
169
|
+
})
|
|
@@ -98,7 +98,7 @@ export class Harvest extends SharedContext {
|
|
|
98
98
|
|
|
99
99
|
var agentRuntime = getRuntime(this.sharedContext.agentIdentifier)
|
|
100
100
|
|
|
101
|
-
if (!payload.body) { // no payload body? nothing to send, just run onfinish stuff and return
|
|
101
|
+
if (!payload.body && !opts?.sendEmptyBody) { // no payload body? nothing to send, just run onfinish stuff and return
|
|
102
102
|
if (cbFinished) {
|
|
103
103
|
cbFinished({ sent: false })
|
|
104
104
|
}
|
|
@@ -108,7 +108,7 @@ export class Harvest extends SharedContext {
|
|
|
108
108
|
let url = ''
|
|
109
109
|
if (customUrl) url = customUrl
|
|
110
110
|
else if (raw) url = `${this.getScheme()}://${info.errorBeacon}/${endpoint}`
|
|
111
|
-
else url = `${this.getScheme()}://${info.errorBeacon}
|
|
111
|
+
else url = `${this.getScheme()}://${info.errorBeacon}${endpoint !== 'rum' ? `/${endpoint}` : ''}/1/${info.licenseKey}`
|
|
112
112
|
|
|
113
113
|
var baseParams = !raw && includeBaseParams ? this.baseQueryString() : ''
|
|
114
114
|
var payloadParams = payload.qs ? encodeObj(payload.qs, agentRuntime.maxBytes) : ''
|
|
@@ -208,6 +208,7 @@ export class Harvest extends SharedContext {
|
|
|
208
208
|
if (singlePayload.body) mapOwn(singlePayload.body, makeBody)
|
|
209
209
|
if (singlePayload.qs) mapOwn(singlePayload.qs, makeQueryString)
|
|
210
210
|
}
|
|
211
|
+
|
|
211
212
|
return { body: makeBody(), qs: makeQueryString() }
|
|
212
213
|
}
|
|
213
214
|
|
|
@@ -223,17 +224,12 @@ export class Harvest extends SharedContext {
|
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
function or (a, b) { return a || b }
|
|
227
|
-
|
|
228
227
|
export function getSubmitMethod (endpoint, opts) {
|
|
229
228
|
opts = opts || {}
|
|
230
229
|
var method
|
|
231
230
|
var useBody
|
|
232
231
|
|
|
233
|
-
if (opts.
|
|
234
|
-
useBody = true
|
|
235
|
-
method = submitData.xhr
|
|
236
|
-
} else if (opts.unload && isBrowserScope) { // all the features' final harvest; neither methods work outside window context
|
|
232
|
+
if (opts.unload && isBrowserScope) { // all the features' final harvest; neither methods work outside window context
|
|
237
233
|
useBody = haveSendBeacon
|
|
238
234
|
method = haveSendBeacon ? submitData.beacon : submitData.img // really only IE doesn't have Beacon API for web browsers
|
|
239
235
|
} else {
|
|
@@ -263,7 +259,7 @@ function createAccumulator () {
|
|
|
263
259
|
var accumulator = {}
|
|
264
260
|
var hasData = false
|
|
265
261
|
return function (key, val) {
|
|
266
|
-
if (val !== null && val !== undefined && val.length) {
|
|
262
|
+
if (val !== null && val !== undefined && val.toString()?.length) {
|
|
267
263
|
accumulator[key] = val
|
|
268
264
|
hasData = true
|
|
269
265
|
}
|
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
import { LocalMemory } from '../storage/local-memory'
|
|
3
|
-
import { LocalStorage } from '../storage/local-storage'
|
|
4
|
-
|
|
5
1
|
import { PREFIX } from './constants'
|
|
6
2
|
import { SessionEntity } from './session-entity'
|
|
7
3
|
|
|
8
4
|
const agentIdentifier = 'test_agent_identifier'
|
|
9
5
|
const key = 'test_key'
|
|
10
6
|
const value = 'test_value'
|
|
7
|
+
class LocalMemory {
|
|
8
|
+
constructor (initialState = {}) {
|
|
9
|
+
this.state = initialState
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get (key) {
|
|
13
|
+
try {
|
|
14
|
+
return this.state[key]
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return ''
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
set (key, value) {
|
|
21
|
+
try {
|
|
22
|
+
if (value === undefined || value === null) return this.remove(key)
|
|
23
|
+
this.state[key] = value
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
remove (key) {
|
|
30
|
+
try {
|
|
31
|
+
delete this.state[key]
|
|
32
|
+
} catch (err) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
11
37
|
|
|
12
38
|
jest.mock('../timer/timer')
|
|
13
39
|
jest.mock('../timer/interaction-timer')
|
|
@@ -24,9 +50,11 @@ jest.mock('../util/global-scope', () => ({
|
|
|
24
50
|
}
|
|
25
51
|
}))
|
|
26
52
|
|
|
53
|
+
let storage
|
|
27
54
|
beforeEach(() => {
|
|
28
55
|
jest.restoreAllMocks()
|
|
29
56
|
mockBrowserScope.mockReturnValue(true)
|
|
57
|
+
storage = new LocalMemory()
|
|
30
58
|
})
|
|
31
59
|
|
|
32
60
|
describe('constructor', () => {
|
|
@@ -37,7 +65,7 @@ describe('constructor', () => {
|
|
|
37
65
|
})
|
|
38
66
|
|
|
39
67
|
test('top-level properties are set and exposed', () => {
|
|
40
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
68
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
41
69
|
expect(session).toMatchObject({
|
|
42
70
|
agentIdentifier: expect.any(String),
|
|
43
71
|
key: expect.any(String),
|
|
@@ -52,119 +80,113 @@ describe('constructor', () => {
|
|
|
52
80
|
expiresAt: expect.any(Number),
|
|
53
81
|
inactiveAt: expect.any(Number),
|
|
54
82
|
sessionReplay: expect.any(Number),
|
|
55
|
-
|
|
83
|
+
sessionTraceMode: expect.any(Number)
|
|
56
84
|
})
|
|
57
85
|
})
|
|
58
86
|
})
|
|
59
87
|
|
|
60
88
|
test('can use sane defaults', () => {
|
|
61
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
89
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
62
90
|
expect(session.state).toEqual(expect.objectContaining({
|
|
63
91
|
value: expect.any(String),
|
|
64
92
|
expiresAt: expect.any(Number),
|
|
65
93
|
inactiveAt: expect.any(Number),
|
|
66
94
|
updatedAt: expect.any(Number),
|
|
67
95
|
sessionReplay: expect.any(Number),
|
|
68
|
-
|
|
96
|
+
sessionTraceMode: expect.any(Number)
|
|
69
97
|
}))
|
|
70
98
|
})
|
|
71
99
|
|
|
72
|
-
test('Workers are forced to use local memory', () => {
|
|
73
|
-
mockBrowserScope.mockReturnValueOnce(false)
|
|
74
|
-
const session = new SessionEntity({ agentIdentifier, key, storageAPI: new LocalStorage() })
|
|
75
|
-
expect(session.storage instanceof LocalMemory).toEqual(true)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
100
|
test('expiresAt is the correct future timestamp - new session', () => {
|
|
79
101
|
const now = Date.now()
|
|
80
102
|
jest.setSystemTime(now)
|
|
81
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100 })
|
|
103
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 100 })
|
|
82
104
|
expect(session.state.expiresAt).toEqual(now + 100)
|
|
83
105
|
})
|
|
84
106
|
|
|
85
107
|
test('expiresAt is the correct future timestamp - existing session', () => {
|
|
86
108
|
const now = Date.now()
|
|
87
109
|
jest.setSystemTime(now)
|
|
88
|
-
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now + 5000, inactiveAt: Infinity, updatedAt: now, sessionReplay: 0,
|
|
89
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100,
|
|
110
|
+
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now + 5000, inactiveAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
111
|
+
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100, storage: existingData })
|
|
90
112
|
expect(session.state.expiresAt).toEqual(now + 5000)
|
|
91
113
|
})
|
|
92
114
|
|
|
93
115
|
test('expiresAt never expires if 0', () => {
|
|
94
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 0 })
|
|
116
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 0 })
|
|
95
117
|
expect(session.state.expiresAt).toEqual(Infinity)
|
|
96
118
|
})
|
|
97
119
|
|
|
98
120
|
test('inactiveAt is the correct future timestamp - new session', () => {
|
|
99
121
|
const now = Date.now()
|
|
100
122
|
jest.setSystemTime(now)
|
|
101
|
-
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100 })
|
|
123
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
|
|
102
124
|
expect(session.state.inactiveAt).toEqual(now + 100)
|
|
103
125
|
})
|
|
104
126
|
|
|
105
127
|
test('inactiveAt is the correct future timestamp - existing session', () => {
|
|
106
128
|
const now = Date.now()
|
|
107
129
|
jest.setSystemTime(now)
|
|
108
|
-
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now + 5000, expiresAt: Infinity, updatedAt: now, sessionReplay: 0,
|
|
109
|
-
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100,
|
|
130
|
+
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now + 5000, expiresAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
131
|
+
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100, storage: existingData })
|
|
110
132
|
expect(session.state.inactiveAt).toEqual(now + 5000)
|
|
111
133
|
})
|
|
112
134
|
|
|
113
135
|
test('inactiveAt never expires if 0', () => {
|
|
114
|
-
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 0 })
|
|
136
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 0 })
|
|
115
137
|
expect(session.state.inactiveAt).toEqual(Infinity)
|
|
116
138
|
})
|
|
117
139
|
|
|
118
140
|
test('should handle isNew', () => {
|
|
119
|
-
const newSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
|
|
141
|
+
const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
120
142
|
expect(newSession.isNew).toBeTruthy()
|
|
121
143
|
|
|
122
|
-
const
|
|
123
|
-
const existingSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10,
|
|
144
|
+
const newStorage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
145
|
+
const existingSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10, storage: newStorage })
|
|
124
146
|
expect(existingSession.isNew).toBeFalsy()
|
|
125
147
|
})
|
|
126
148
|
|
|
127
149
|
test('invalid stored values sets new defaults', () => {
|
|
128
150
|
// missing required fields
|
|
129
|
-
const
|
|
130
|
-
const session = new SessionEntity({ agentIdentifier, key,
|
|
151
|
+
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { invalid_fields: true } })
|
|
152
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
131
153
|
expect(session.state).toEqual(expect.objectContaining({
|
|
132
154
|
value: expect.any(String),
|
|
133
155
|
expiresAt: expect.any(Number),
|
|
134
156
|
inactiveAt: expect.any(Number),
|
|
135
157
|
updatedAt: expect.any(Number),
|
|
136
158
|
sessionReplay: expect.any(Number),
|
|
137
|
-
|
|
159
|
+
sessionTraceMode: expect.any(Number)
|
|
138
160
|
}))
|
|
139
161
|
})
|
|
140
162
|
|
|
141
163
|
test('expired expiresAt value in storage sets new defaults', () => {
|
|
142
164
|
const now = Date.now()
|
|
143
165
|
jest.setSystemTime(now)
|
|
144
|
-
const
|
|
145
|
-
const session = new SessionEntity({ agentIdentifier, key,
|
|
166
|
+
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now - 100, inactiveAt: Infinity } })
|
|
167
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
146
168
|
expect(session.state).toEqual(expect.objectContaining({
|
|
147
169
|
value: expect.any(String),
|
|
148
170
|
expiresAt: expect.any(Number),
|
|
149
171
|
inactiveAt: expect.any(Number),
|
|
150
172
|
updatedAt: expect.any(Number),
|
|
151
173
|
sessionReplay: expect.any(Number),
|
|
152
|
-
|
|
174
|
+
sessionTraceMode: expect.any(Number)
|
|
153
175
|
}))
|
|
154
176
|
})
|
|
155
177
|
|
|
156
178
|
test('expired inactiveAt value in storage sets new defaults', () => {
|
|
157
179
|
const now = Date.now()
|
|
158
180
|
jest.setSystemTime(now)
|
|
159
|
-
const
|
|
160
|
-
const session = new SessionEntity({ agentIdentifier, key,
|
|
181
|
+
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now - 100, expiresAt: Infinity } })
|
|
182
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
161
183
|
expect(session.state).toEqual(expect.objectContaining({
|
|
162
184
|
value: expect.any(String),
|
|
163
185
|
expiresAt: expect.any(Number),
|
|
164
186
|
inactiveAt: expect.any(Number),
|
|
165
187
|
updatedAt: expect.any(Number),
|
|
166
188
|
sessionReplay: expect.any(Number),
|
|
167
|
-
|
|
189
|
+
sessionTraceMode: expect.any(Number)
|
|
168
190
|
}))
|
|
169
191
|
})
|
|
170
192
|
})
|
|
@@ -173,7 +195,7 @@ describe('reset()', () => {
|
|
|
173
195
|
test('should create new default values when resetting', () => {
|
|
174
196
|
const now = Date.now()
|
|
175
197
|
jest.setSystemTime(now)
|
|
176
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
|
|
198
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
177
199
|
const sessionVal = session.value
|
|
178
200
|
expect(session.state.value).toBeTruthy()
|
|
179
201
|
session.reset()
|
|
@@ -184,7 +206,7 @@ describe('reset()', () => {
|
|
|
184
206
|
test('custom data should be wiped on reset', () => {
|
|
185
207
|
const now = Date.now()
|
|
186
208
|
jest.setSystemTime(now)
|
|
187
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
|
|
209
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
188
210
|
session.syncCustomAttribute('test', 123)
|
|
189
211
|
expect(session.state.custom.test).toEqual(123)
|
|
190
212
|
expect(session.read().custom.test).toEqual(123)
|
|
@@ -198,7 +220,7 @@ describe('reset()', () => {
|
|
|
198
220
|
|
|
199
221
|
describe('read()', () => {
|
|
200
222
|
test('"new" sessions get data from read()', () => {
|
|
201
|
-
const newSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
|
|
223
|
+
const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
202
224
|
expect(newSession.isNew).toBeTruthy()
|
|
203
225
|
|
|
204
226
|
expect(newSession.read()).toEqual(expect.objectContaining({
|
|
@@ -206,13 +228,13 @@ describe('read()', () => {
|
|
|
206
228
|
expiresAt: expect.any(Number),
|
|
207
229
|
inactiveAt: expect.any(Number),
|
|
208
230
|
sessionReplay: expect.any(Number),
|
|
209
|
-
|
|
231
|
+
sessionTraceMode: expect.any(Number)
|
|
210
232
|
}))
|
|
211
233
|
})
|
|
212
234
|
|
|
213
235
|
test('"pre-existing" sessions get data from read()', () => {
|
|
214
|
-
const
|
|
215
|
-
const session = new SessionEntity({ agentIdentifier, key,
|
|
236
|
+
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
237
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
216
238
|
expect(session.isNew).toBeFalsy()
|
|
217
239
|
expect(session.read()).toEqual(expect.objectContaining({
|
|
218
240
|
value,
|
|
@@ -224,7 +246,7 @@ describe('read()', () => {
|
|
|
224
246
|
|
|
225
247
|
describe('write()', () => {
|
|
226
248
|
test('write() sets data to top-level wrapper', () => {
|
|
227
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
249
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
228
250
|
expect(session.state.value).not.toEqual(value)
|
|
229
251
|
expect(session.state.expiresAt).not.toEqual(Infinity)
|
|
230
252
|
expect(session.state.inactiveAt).not.toEqual(Infinity)
|
|
@@ -237,7 +259,7 @@ describe('write()', () => {
|
|
|
237
259
|
test('write() sets data that read() can access', () => {
|
|
238
260
|
const now = Date.now()
|
|
239
261
|
jest.setSystemTime(now)
|
|
240
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
262
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
241
263
|
session.write({ ...session.state, value, expiresAt: now + 100, inactiveAt: now + 100 })
|
|
242
264
|
const read = session.read()
|
|
243
265
|
expect(read.value).toEqual(value)
|
|
@@ -246,7 +268,7 @@ describe('write()', () => {
|
|
|
246
268
|
})
|
|
247
269
|
|
|
248
270
|
test('write() does not run with invalid data', () => {
|
|
249
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
271
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
250
272
|
let out = session.write()
|
|
251
273
|
expect(out).toEqual(undefined)
|
|
252
274
|
out = session.write('string')
|
|
@@ -264,7 +286,7 @@ describe('refresh()', () => {
|
|
|
264
286
|
test('refresh sets inactiveAt to future time', () => {
|
|
265
287
|
const now = Date.now()
|
|
266
288
|
jest.setSystemTime(now)
|
|
267
|
-
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100 })
|
|
289
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
|
|
268
290
|
expect(session.state.inactiveAt).toEqual(now + 100)
|
|
269
291
|
jest.setSystemTime(now + 1000)
|
|
270
292
|
session.refresh()
|
|
@@ -274,7 +296,7 @@ describe('refresh()', () => {
|
|
|
274
296
|
test('refresh resets the entity if expiresTimer is invalid', () => {
|
|
275
297
|
const now = Date.now()
|
|
276
298
|
jest.setSystemTime(now)
|
|
277
|
-
const session = new SessionEntity({ agentIdentifier, key, value })
|
|
299
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, value })
|
|
278
300
|
expect(session.state.value).toEqual(value)
|
|
279
301
|
session.write({ ...session.state, expiresAt: now - 1 })
|
|
280
302
|
session.refresh()
|
|
@@ -284,7 +306,7 @@ describe('refresh()', () => {
|
|
|
284
306
|
test('refresh resets the entity if inactiveTimer is invalid', () => {
|
|
285
307
|
const now = Date.now()
|
|
286
308
|
jest.setSystemTime(now)
|
|
287
|
-
const session = new SessionEntity({ agentIdentifier, key, value })
|
|
309
|
+
const session = new SessionEntity({ agentIdentifier, key, storage, value })
|
|
288
310
|
expect(session.state.value).toEqual(value)
|
|
289
311
|
session.write({ ...session.state, inactiveAt: now - 1 })
|
|
290
312
|
session.refresh()
|
|
@@ -294,7 +316,7 @@ describe('refresh()', () => {
|
|
|
294
316
|
|
|
295
317
|
describe('syncCustomAttribute()', () => {
|
|
296
318
|
test('Custom data can be managed by session entity', () => {
|
|
297
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
319
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
298
320
|
|
|
299
321
|
// if custom has never been set, and a "delete" action is triggered, do nothing
|
|
300
322
|
session.syncCustomAttribute('test', null)
|
|
@@ -316,7 +338,7 @@ describe('syncCustomAttribute()', () => {
|
|
|
316
338
|
|
|
317
339
|
test('Only runs in browser scope', () => {
|
|
318
340
|
mockBrowserScope.mockReturnValue(false)
|
|
319
|
-
const session = new SessionEntity({ agentIdentifier, key })
|
|
341
|
+
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
320
342
|
session.syncCustomAttribute('test', 1)
|
|
321
343
|
expect(session.read().custom?.test).toEqual(undefined)
|
|
322
344
|
})
|
|
@@ -5,7 +5,6 @@ import { ee } from '../event-emitter/contextual-ee'
|
|
|
5
5
|
import { Timer } from '../timer/timer'
|
|
6
6
|
import { isBrowserScope } from '../util/global-scope'
|
|
7
7
|
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, PREFIX } from './constants'
|
|
8
|
-
import { LocalMemory } from '../storage/local-memory'
|
|
9
8
|
import { InteractionTimer } from '../timer/interaction-timer'
|
|
10
9
|
import { wrapEvents } from '../wrap'
|
|
11
10
|
import { getModeledObject } from '../config/state/configurable'
|
|
@@ -13,6 +12,11 @@ import { handle } from '../event-emitter/handle'
|
|
|
13
12
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
|
|
14
13
|
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
15
14
|
|
|
15
|
+
export const MODE = {
|
|
16
|
+
OFF: 0,
|
|
17
|
+
FULL: 1,
|
|
18
|
+
ERROR: 2
|
|
19
|
+
}
|
|
16
20
|
// this is what can be stored in local storage (not enforced but probably should be)
|
|
17
21
|
// these values should sync between local storage and the parent class props
|
|
18
22
|
const model = {
|
|
@@ -20,11 +24,10 @@ const model = {
|
|
|
20
24
|
inactiveAt: 0,
|
|
21
25
|
expiresAt: 0,
|
|
22
26
|
updatedAt: Date.now(),
|
|
23
|
-
sessionReplay:
|
|
24
|
-
|
|
27
|
+
sessionReplay: MODE.OFF,
|
|
28
|
+
sessionTraceMode: MODE.OFF,
|
|
25
29
|
custom: {}
|
|
26
30
|
}
|
|
27
|
-
|
|
28
31
|
export const SESSION_EVENTS = {
|
|
29
32
|
PAUSE: 'session-pause',
|
|
30
33
|
RESET: 'session-reset',
|
|
@@ -42,16 +45,16 @@ export class SessionEntity {
|
|
|
42
45
|
this.setup(opts)
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
setup ({ agentIdentifier, key, value = generateRandomHexString(16), expiresMs = DEFAULT_EXPIRES_MS, inactiveMs = DEFAULT_INACTIVE_MS
|
|
46
|
-
if (!agentIdentifier || !key
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
setup ({ agentIdentifier, key, storage, value = generateRandomHexString(16), expiresMs = DEFAULT_EXPIRES_MS, inactiveMs = DEFAULT_INACTIVE_MS }) {
|
|
49
|
+
if (!agentIdentifier || !key || !storage) {
|
|
50
|
+
throw new Error(`Missing required field(s):${!agentIdentifier ? ' agentID' : ''}${!key ? ' key' : ''}${!storage ? ' storage' : ''}`)
|
|
51
|
+
}
|
|
52
|
+
this.agentIdentifier = agentIdentifier
|
|
53
|
+
this.storage = storage
|
|
50
54
|
this.state = {}
|
|
51
55
|
|
|
52
56
|
this.sync(model)
|
|
53
57
|
|
|
54
|
-
this.agentIdentifier = agentIdentifier
|
|
55
58
|
// key is intended to act as the k=v pair
|
|
56
59
|
this.key = key
|
|
57
60
|
// value is intended to act as the primary value of the k=v pair
|
|
@@ -183,7 +186,7 @@ export class SessionEntity {
|
|
|
183
186
|
this.sync(data) // update the parent class "state" properties with the local storage values
|
|
184
187
|
//
|
|
185
188
|
// TODO - compression would need happen here if we decide to do it
|
|
186
|
-
this.storage.set(this.lookupKey, stringify(
|
|
189
|
+
this.storage.set(this.lookupKey, stringify(this.state))
|
|
187
190
|
return data
|
|
188
191
|
} catch (e) {
|
|
189
192
|
// storage is inaccessible
|
|
@@ -207,7 +210,7 @@ export class SessionEntity {
|
|
|
207
210
|
this.setup({
|
|
208
211
|
agentIdentifier: this.agentIdentifier,
|
|
209
212
|
key: this.key,
|
|
210
|
-
|
|
213
|
+
storage: this.storage,
|
|
211
214
|
expiresMs: this.expiresMs,
|
|
212
215
|
inactiveMs: this.inactiveMs
|
|
213
216
|
})
|
|
@@ -44,8 +44,8 @@ export class InteractionTimer extends Timer {
|
|
|
44
44
|
if (state === 'hidden') this.pause()
|
|
45
45
|
// vis change --> visible is treated like a new interaction with the page
|
|
46
46
|
else {
|
|
47
|
-
this.onResume()
|
|
48
47
|
this.refresh()
|
|
48
|
+
this.onResume() // emit resume event after state updated
|
|
49
49
|
}
|
|
50
50
|
}, false, false, this.abortController?.signal)
|
|
51
51
|
}
|