@newrelic/browser-agent 1.242.0 → 1.243.1
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 +1472 -0
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- 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 +89 -53
- package/dist/cjs/features/utils/feature-base.js +1 -2
- 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/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- 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 +88 -53
- package/dist/esm/features/utils/feature-base.js +1 -2
- 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/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/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/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 +86 -36
- package/src/features/utils/feature-base.js +1 -2
- 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 -68
- 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/dom/query-selector.test.js +0 -24
- 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,92 +0,0 @@
|
|
|
1
|
-
let idFn
|
|
2
|
-
|
|
3
|
-
beforeEach(async () => {
|
|
4
|
-
idFn = (await import('./id')).id
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
afterEach(() => {
|
|
8
|
-
jest.resetModules()
|
|
9
|
-
jest.clearAllMocks()
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test.each([
|
|
13
|
-
{ input: undefined, expected: -1, title: 'id of undefined is -1' },
|
|
14
|
-
{ input: null, expected: -1, title: 'id of null is -1' },
|
|
15
|
-
{ input: 2, expected: -1, title: 'id of number is -1' },
|
|
16
|
-
{ input: 'foo', expected: -1, title: 'id of string is -1' }
|
|
17
|
-
])('$title', ({ input, expected }) => {
|
|
18
|
-
const result = idFn(input)
|
|
19
|
-
|
|
20
|
-
expect(typeof result).toEqual('number')
|
|
21
|
-
expect(result).toEqual(expected)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('id values increment sequentially', () => {
|
|
25
|
-
const inputA = {}
|
|
26
|
-
const inputB = {}
|
|
27
|
-
|
|
28
|
-
const resultA = idFn(inputA)
|
|
29
|
-
const resultB = idFn(inputB)
|
|
30
|
-
|
|
31
|
-
expect(resultA - resultB).toEqual(-1)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('id is correctly assigned to function type', () => {
|
|
35
|
-
const input = jest.fn()
|
|
36
|
-
|
|
37
|
-
const result = idFn(input)
|
|
38
|
-
|
|
39
|
-
expect(result).toEqual(1)
|
|
40
|
-
expect(input['nr@id']).toEqual(1)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('id is correctly assigned to object type', () => {
|
|
44
|
-
const input = {}
|
|
45
|
-
|
|
46
|
-
const result = idFn(input)
|
|
47
|
-
|
|
48
|
-
expect(result).toEqual(1)
|
|
49
|
-
expect(input['nr@id']).toEqual(1)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('id is the same when called twice on the same input', () => {
|
|
53
|
-
const input = {}
|
|
54
|
-
|
|
55
|
-
const result1 = idFn(input)
|
|
56
|
-
const result2 = idFn(input)
|
|
57
|
-
|
|
58
|
-
expect(result1).toEqual(1)
|
|
59
|
-
expect(result2).toEqual(1)
|
|
60
|
-
expect(input['nr@id']).toEqual(1)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('id is zero on global scope', async () => {
|
|
64
|
-
const result = idFn(global)
|
|
65
|
-
|
|
66
|
-
expect(result).toEqual(0)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('id on prototype is correctly inherited', () => {
|
|
70
|
-
const Ctor = jest.fn()
|
|
71
|
-
const a = {}
|
|
72
|
-
|
|
73
|
-
idFn(a)
|
|
74
|
-
Ctor.prototype = a
|
|
75
|
-
|
|
76
|
-
const b = new Ctor()
|
|
77
|
-
|
|
78
|
-
expect(b['nr@id']).toEqual(a['nr@id'])
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('id on prototype is different from instance', () => {
|
|
82
|
-
const Ctor = jest.fn()
|
|
83
|
-
const a = {}
|
|
84
|
-
|
|
85
|
-
idFn(a)
|
|
86
|
-
Ctor.prototype = a
|
|
87
|
-
|
|
88
|
-
const b = new Ctor()
|
|
89
|
-
const result = idFn(b)
|
|
90
|
-
|
|
91
|
-
expect(b['nr@id']).toEqual(result)
|
|
92
|
-
})
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto'
|
|
2
|
-
import * as uniqueId from './unique-id'
|
|
3
|
-
|
|
4
|
-
const getRandomValues = jest.fn(arr => crypto.randomBytes(arr.length))
|
|
5
|
-
|
|
6
|
-
afterEach(() => {
|
|
7
|
-
delete global.crypto
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
describe('generateUuid', () => {
|
|
11
|
-
const uuidv4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
|
|
12
|
-
|
|
13
|
-
test('should generate a uuidv4 that matches the expected format', () => {
|
|
14
|
-
const id = uniqueId.generateUuid()
|
|
15
|
-
|
|
16
|
-
expect(uuidv4Regex.test(id)).toEqual(true)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('should support using native crypto library', () => {
|
|
20
|
-
global.crypto = { getRandomValues }
|
|
21
|
-
|
|
22
|
-
const id = uniqueId.generateUuid()
|
|
23
|
-
|
|
24
|
-
expect(uuidv4Regex.test(id)).toEqual(true)
|
|
25
|
-
expect(getRandomValues).toHaveBeenCalledTimes(1)
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe('generateRandomHexString', () => {
|
|
30
|
-
const hexRegex = /^[0-9a-f]{8}$/
|
|
31
|
-
|
|
32
|
-
test('should generate a valid hex string', () => {
|
|
33
|
-
const id = uniqueId.generateRandomHexString(8)
|
|
34
|
-
|
|
35
|
-
expect(hexRegex.test(id)).toEqual(true)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('should support using native crypto library', () => {
|
|
39
|
-
global.crypto = { getRandomValues }
|
|
40
|
-
|
|
41
|
-
const id = uniqueId.generateRandomHexString(8)
|
|
42
|
-
|
|
43
|
-
expect(hexRegex.test(id)).toEqual(true)
|
|
44
|
-
expect(getRandomValues).toHaveBeenCalledTimes(1)
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('generateSpanId should generate a 16 character hex string', () => {
|
|
49
|
-
const id = uniqueId.generateSpanId()
|
|
50
|
-
|
|
51
|
-
expect(/^[0-9a-f]{16}$/.test(id)).toEqual(true)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('generateTraceId should generate a 32 character hex string', () => {
|
|
55
|
-
const id = uniqueId.generateTraceId()
|
|
56
|
-
|
|
57
|
-
expect(/^[0-9a-f]{32}$/.test(id)).toEqual(true)
|
|
58
|
-
})
|
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
import { PREFIX } from './constants'
|
|
2
|
-
import { SessionEntity } from './session-entity'
|
|
3
|
-
|
|
4
|
-
const agentIdentifier = 'test_agent_identifier'
|
|
5
|
-
const key = 'test_key'
|
|
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
|
-
// Error is ignored
|
|
17
|
-
return ''
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
set (key, value) {
|
|
22
|
-
try {
|
|
23
|
-
if (value === undefined || value === null) return this.remove(key)
|
|
24
|
-
this.state[key] = value
|
|
25
|
-
} catch (err) {
|
|
26
|
-
// Error is ignored
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
remove (key) {
|
|
31
|
-
try {
|
|
32
|
-
delete this.state[key]
|
|
33
|
-
} catch (err) {
|
|
34
|
-
// Error is ignored
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
jest.mock('../timer/timer')
|
|
40
|
-
jest.mock('../timer/interaction-timer')
|
|
41
|
-
jest.useFakeTimers()
|
|
42
|
-
|
|
43
|
-
const mockBrowserScope = jest.fn().mockImplementation(() => true)
|
|
44
|
-
jest.mock('../constants/runtime', () => ({
|
|
45
|
-
__esModule: true,
|
|
46
|
-
get isBrowserScope () {
|
|
47
|
-
return mockBrowserScope()
|
|
48
|
-
},
|
|
49
|
-
get globalScope () {
|
|
50
|
-
return global.window
|
|
51
|
-
}
|
|
52
|
-
}))
|
|
53
|
-
|
|
54
|
-
let storage
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
jest.restoreAllMocks()
|
|
57
|
-
mockBrowserScope.mockReturnValue(true)
|
|
58
|
-
storage = new LocalMemory()
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
describe('constructor', () => {
|
|
62
|
-
test('must use required fields', () => {
|
|
63
|
-
try {
|
|
64
|
-
expect(new SessionEntity({})).toThrow(new Error('Missing Required Fields'))
|
|
65
|
-
} catch (err) {}
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('top-level properties are set and exposed', () => {
|
|
69
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
70
|
-
expect(session).toMatchObject({
|
|
71
|
-
agentIdentifier: expect.any(String),
|
|
72
|
-
key: expect.any(String),
|
|
73
|
-
expiresMs: expect.any(Number),
|
|
74
|
-
expiresTimer: expect.any(Object),
|
|
75
|
-
inactiveMs: expect.any(Number),
|
|
76
|
-
inactiveTimer: expect.any(Object),
|
|
77
|
-
isNew: expect.any(Boolean),
|
|
78
|
-
storage: expect.any(Object),
|
|
79
|
-
state: expect.objectContaining({
|
|
80
|
-
value: expect.any(String),
|
|
81
|
-
expiresAt: expect.any(Number),
|
|
82
|
-
inactiveAt: expect.any(Number),
|
|
83
|
-
sessionReplay: expect.any(Number),
|
|
84
|
-
sessionTraceMode: expect.any(Number)
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
test('can use sane defaults', () => {
|
|
90
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
91
|
-
expect(session.state).toEqual(expect.objectContaining({
|
|
92
|
-
value: expect.any(String),
|
|
93
|
-
expiresAt: expect.any(Number),
|
|
94
|
-
inactiveAt: expect.any(Number),
|
|
95
|
-
updatedAt: expect.any(Number),
|
|
96
|
-
sessionReplay: expect.any(Number),
|
|
97
|
-
sessionTraceMode: expect.any(Number)
|
|
98
|
-
}))
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
test('expiresAt is the correct future timestamp - new session', () => {
|
|
102
|
-
const now = Date.now()
|
|
103
|
-
jest.setSystemTime(now)
|
|
104
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 100 })
|
|
105
|
-
expect(session.state.expiresAt).toEqual(now + 100)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
test('expiresAt is the correct future timestamp - existing session', () => {
|
|
109
|
-
const now = Date.now()
|
|
110
|
-
jest.setSystemTime(now)
|
|
111
|
-
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now + 5000, inactiveAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
112
|
-
const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100, storage: existingData })
|
|
113
|
-
expect(session.state.expiresAt).toEqual(now + 5000)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('expiresAt never expires if 0', () => {
|
|
117
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 0 })
|
|
118
|
-
expect(session.state.expiresAt).toEqual(Infinity)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
test('inactiveAt is the correct future timestamp - new session', () => {
|
|
122
|
-
const now = Date.now()
|
|
123
|
-
jest.setSystemTime(now)
|
|
124
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
|
|
125
|
-
expect(session.state.inactiveAt).toEqual(now + 100)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
test('inactiveAt is the correct future timestamp - existing session', () => {
|
|
129
|
-
const now = Date.now()
|
|
130
|
-
jest.setSystemTime(now)
|
|
131
|
-
const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now + 5000, expiresAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
132
|
-
const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100, storage: existingData })
|
|
133
|
-
expect(session.state.inactiveAt).toEqual(now + 5000)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('inactiveAt never expires if 0', () => {
|
|
137
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 0 })
|
|
138
|
-
expect(session.state.inactiveAt).toEqual(Infinity)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('should handle isNew', () => {
|
|
142
|
-
const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
143
|
-
expect(newSession.isNew).toBeTruthy()
|
|
144
|
-
|
|
145
|
-
const newStorage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
146
|
-
const existingSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10, storage: newStorage })
|
|
147
|
-
expect(existingSession.isNew).toBeFalsy()
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test('invalid stored values sets new defaults', () => {
|
|
151
|
-
// missing required fields
|
|
152
|
-
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { invalid_fields: true } })
|
|
153
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
154
|
-
expect(session.state).toEqual(expect.objectContaining({
|
|
155
|
-
value: expect.any(String),
|
|
156
|
-
expiresAt: expect.any(Number),
|
|
157
|
-
inactiveAt: expect.any(Number),
|
|
158
|
-
updatedAt: expect.any(Number),
|
|
159
|
-
sessionReplay: expect.any(Number),
|
|
160
|
-
sessionTraceMode: expect.any(Number)
|
|
161
|
-
}))
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
test('expired expiresAt value in storage sets new defaults', () => {
|
|
165
|
-
const now = Date.now()
|
|
166
|
-
jest.setSystemTime(now)
|
|
167
|
-
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now - 100, inactiveAt: Infinity } })
|
|
168
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
169
|
-
expect(session.state).toEqual(expect.objectContaining({
|
|
170
|
-
value: expect.any(String),
|
|
171
|
-
expiresAt: expect.any(Number),
|
|
172
|
-
inactiveAt: expect.any(Number),
|
|
173
|
-
updatedAt: expect.any(Number),
|
|
174
|
-
sessionReplay: expect.any(Number),
|
|
175
|
-
sessionTraceMode: expect.any(Number)
|
|
176
|
-
}))
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
test('expired inactiveAt value in storage sets new defaults', () => {
|
|
180
|
-
const now = Date.now()
|
|
181
|
-
jest.setSystemTime(now)
|
|
182
|
-
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now - 100, expiresAt: Infinity } })
|
|
183
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
184
|
-
expect(session.state).toEqual(expect.objectContaining({
|
|
185
|
-
value: expect.any(String),
|
|
186
|
-
expiresAt: expect.any(Number),
|
|
187
|
-
inactiveAt: expect.any(Number),
|
|
188
|
-
updatedAt: expect.any(Number),
|
|
189
|
-
sessionReplay: expect.any(Number),
|
|
190
|
-
sessionTraceMode: expect.any(Number)
|
|
191
|
-
}))
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
describe('reset()', () => {
|
|
196
|
-
test('should create new default values when resetting', () => {
|
|
197
|
-
const now = Date.now()
|
|
198
|
-
jest.setSystemTime(now)
|
|
199
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
200
|
-
const sessionVal = session.value
|
|
201
|
-
expect(session.state.value).toBeTruthy()
|
|
202
|
-
session.reset()
|
|
203
|
-
expect(session.state.value).toBeTruthy()
|
|
204
|
-
expect(session.state.value).not.toEqual(sessionVal)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
test('custom data should be wiped on reset', () => {
|
|
208
|
-
const now = Date.now()
|
|
209
|
-
jest.setSystemTime(now)
|
|
210
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
211
|
-
session.syncCustomAttribute('test', 123)
|
|
212
|
-
expect(session.state.custom.test).toEqual(123)
|
|
213
|
-
expect(session.read().custom.test).toEqual(123)
|
|
214
|
-
|
|
215
|
-
// simulate a timer expiring
|
|
216
|
-
session.reset()
|
|
217
|
-
expect(session.state.custom?.test).toEqual(undefined)
|
|
218
|
-
expect(session.read()?.custom?.test).toEqual(undefined)
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
describe('read()', () => {
|
|
223
|
-
test('"new" sessions get data from read()', () => {
|
|
224
|
-
const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
|
|
225
|
-
expect(newSession.isNew).toBeTruthy()
|
|
226
|
-
|
|
227
|
-
expect(newSession.read()).toEqual(expect.objectContaining({
|
|
228
|
-
value: expect.any(String),
|
|
229
|
-
expiresAt: expect.any(Number),
|
|
230
|
-
inactiveAt: expect.any(Number),
|
|
231
|
-
sessionReplay: expect.any(Number),
|
|
232
|
-
sessionTraceMode: expect.any(Number)
|
|
233
|
-
}))
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
test('"pre-existing" sessions get data from read()', () => {
|
|
237
|
-
const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
|
|
238
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
239
|
-
expect(session.isNew).toBeFalsy()
|
|
240
|
-
expect(session.read()).toEqual(expect.objectContaining({
|
|
241
|
-
value,
|
|
242
|
-
expiresAt: Infinity,
|
|
243
|
-
inactiveAt: Infinity
|
|
244
|
-
}))
|
|
245
|
-
})
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
describe('write()', () => {
|
|
249
|
-
test('write() sets data to top-level wrapper', () => {
|
|
250
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
251
|
-
expect(session.state.value).not.toEqual(value)
|
|
252
|
-
expect(session.state.expiresAt).not.toEqual(Infinity)
|
|
253
|
-
expect(session.state.inactiveAt).not.toEqual(Infinity)
|
|
254
|
-
session.write({ ...session.state, value, expiresAt: Infinity, inactiveAt: Infinity })
|
|
255
|
-
expect(session.state.value).toEqual(value)
|
|
256
|
-
expect(session.state.expiresAt).toEqual(Infinity)
|
|
257
|
-
expect(session.state.inactiveAt).toEqual(Infinity)
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test('write() sets data that read() can access', () => {
|
|
261
|
-
const now = Date.now()
|
|
262
|
-
jest.setSystemTime(now)
|
|
263
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
264
|
-
session.write({ ...session.state, value, expiresAt: now + 100, inactiveAt: now + 100 })
|
|
265
|
-
const read = session.read()
|
|
266
|
-
expect(read.value).toEqual(value)
|
|
267
|
-
expect(read.expiresAt).toEqual(now + 100)
|
|
268
|
-
expect(read.inactiveAt).toEqual(now + 100)
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
test('write() does not run with invalid data', () => {
|
|
272
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
273
|
-
let out = session.write()
|
|
274
|
-
expect(out).toEqual(undefined)
|
|
275
|
-
out = session.write('string')
|
|
276
|
-
expect(out).toEqual(undefined)
|
|
277
|
-
out = session.write(123)
|
|
278
|
-
expect(out).toEqual(undefined)
|
|
279
|
-
out = session.write(true)
|
|
280
|
-
expect(out).toEqual(undefined)
|
|
281
|
-
out = session.write(false)
|
|
282
|
-
expect(out).toEqual(undefined)
|
|
283
|
-
})
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
describe('refresh()', () => {
|
|
287
|
-
test('refresh sets inactiveAt to future time', () => {
|
|
288
|
-
const now = Date.now()
|
|
289
|
-
jest.setSystemTime(now)
|
|
290
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
|
|
291
|
-
expect(session.state.inactiveAt).toEqual(now + 100)
|
|
292
|
-
jest.setSystemTime(now + 1000)
|
|
293
|
-
session.refresh()
|
|
294
|
-
expect(session.state.inactiveAt).toEqual(now + 100 + 1000)
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
test('refresh resets the entity if expiresTimer is invalid', () => {
|
|
298
|
-
const now = Date.now()
|
|
299
|
-
jest.setSystemTime(now)
|
|
300
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, value })
|
|
301
|
-
expect(session.state.value).toEqual(value)
|
|
302
|
-
session.write({ ...session.state, expiresAt: now - 1 })
|
|
303
|
-
session.refresh()
|
|
304
|
-
expect(session.state.value).not.toEqual(value)
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
test('refresh resets the entity if inactiveTimer is invalid', () => {
|
|
308
|
-
const now = Date.now()
|
|
309
|
-
jest.setSystemTime(now)
|
|
310
|
-
const session = new SessionEntity({ agentIdentifier, key, storage, value })
|
|
311
|
-
expect(session.state.value).toEqual(value)
|
|
312
|
-
session.write({ ...session.state, inactiveAt: now - 1 })
|
|
313
|
-
session.refresh()
|
|
314
|
-
expect(session.state.value).not.toEqual(value)
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
describe('syncCustomAttribute()', () => {
|
|
319
|
-
test('Custom data can be managed by session entity', () => {
|
|
320
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
321
|
-
|
|
322
|
-
// if custom has never been set, and a "delete" action is triggered, do nothing
|
|
323
|
-
session.syncCustomAttribute('test', null)
|
|
324
|
-
expect(session?.state?.custom?.test).toEqual(undefined)
|
|
325
|
-
|
|
326
|
-
session.syncCustomAttribute('test', 1)
|
|
327
|
-
expect(session?.state?.custom?.test).toEqual(1)
|
|
328
|
-
|
|
329
|
-
session.syncCustomAttribute('test', 'string')
|
|
330
|
-
expect(session?.state?.custom?.test).toEqual('string')
|
|
331
|
-
|
|
332
|
-
session.syncCustomAttribute('test', false)
|
|
333
|
-
expect(session?.state?.custom?.test).toEqual(false)
|
|
334
|
-
|
|
335
|
-
// null specifically deletes the object completely
|
|
336
|
-
session.syncCustomAttribute('test', null)
|
|
337
|
-
expect(session?.state?.custom?.test).toEqual(undefined)
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
test('Only runs in browser scope', () => {
|
|
341
|
-
mockBrowserScope.mockReturnValue(false)
|
|
342
|
-
const session = new SessionEntity({ agentIdentifier, key, storage })
|
|
343
|
-
session.syncCustomAttribute('test', 1)
|
|
344
|
-
expect(session.read().custom?.test).toEqual(undefined)
|
|
345
|
-
})
|
|
346
|
-
})
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { LocalStorage } from './local-storage'
|
|
2
|
-
|
|
3
|
-
test('Local-memory', () => {
|
|
4
|
-
const LS = new LocalStorage()
|
|
5
|
-
|
|
6
|
-
LS.set('test', 1)
|
|
7
|
-
expect(LS.get('test')).toEqual('1')
|
|
8
|
-
|
|
9
|
-
LS.set('test')
|
|
10
|
-
expect(LS.get('test')).toEqual(undefined)
|
|
11
|
-
|
|
12
|
-
LS.set('test', 2)
|
|
13
|
-
expect(LS.get('test')).toEqual('2')
|
|
14
|
-
|
|
15
|
-
LS.remove('test')
|
|
16
|
-
expect(LS.get('test')).toEqual(undefined)
|
|
17
|
-
})
|