Skip to content

Commit 1a87991

Browse files
authored
fix: Undefined stns in blob Trace (#1039)
1 parent f9d7b49 commit 1a87991

File tree

3 files changed

+51
-44
lines changed

3 files changed

+51
-44
lines changed

src/features/session_trace/aggregate/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export class Aggregate extends AggregateBase {
116116

117117
/** Get the ST nodes from the traceStorage buffer. This also returns helpful metadata about the payload. */
118118
const { stns, earliestTimeStamp, latestTimeStamp } = this.traceStorage.takeSTNs()
119+
if (!stns) return // there are no trace nodes
119120
if (options.retry) {
120121
this.sentTrace = stns
121122
}

src/features/session_trace/aggregate/trace/storage.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,7 @@ export class TraceStorage {
274274
// Ajax (FEATURE) events--XML & fetches--pipes into ST here.
275275
storeXhrAgg (type, name, params, metrics) {
276276
if (type !== 'xhr') return
277-
this.storeSTN(new TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, `${params.status} ${params.method}: ${params.host}${params.pathname
278-
}`))
277+
this.storeSTN(new TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, `${params.status} ${params.method}: ${params.host}${params.pathname}`, 'ajax'))
279278
}
280279

281280
restoreNode (name, listOfSTNodes) {

tests/components/session_trace/index.test.js

+49-42
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ jest.mock('../../../src/common/config/config', () => ({
1717
}),
1818
isConfigured: jest.fn().mockReturnValue(true),
1919
getRuntime: jest.fn().mockReturnValue({
20-
session: { state: { value: 'sessionID' }, write: jest.fn() }
20+
session: { state: { value: 'sessionID' }, write: jest.fn() },
21+
timeKeeper: { ready: true, correctedOriginTime: 0, convertRelativeTimestamp: jest.fn() }
2122
})
2223
}))
2324
jest.mock('../../../src/common/constants/runtime', () => ({
@@ -56,51 +57,57 @@ describe('session trace', () => {
5657

5758
document.dispatchEvent(new CustomEvent('DOMContentLoaded')) // simulate natural browser event
5859
window.dispatchEvent(new CustomEvent('load')) // load is actually ignored by Trace as it should be passed by the PVT feature, so it should not be in payload
59-
await traceInstrument.onAggregateImported
6060
ee.get('abcd').emit('rumresp-st', [1])
6161
ee.get('abcd').emit('rumresp-sts', [1])
62-
const traceAggregate = traceInstrument.featAggregate
6362
traceAggregate.traceStorage.storeXhrAgg('xhr', '[200,null,null]', { method: 'GET', status: 200 }, { rxSize: 770, duration: 99, cbTime: 0, time: 217 }) // fake ajax data
6463
traceAggregate.traceStorage.processPVT('fi', 30, { fid: 8 }) // fake pvt data
65-
setTimeout(() => {
66-
const payload = traceAggregate.prepareHarvest()
67-
let res = payload.body
6864

69-
let node = res.filter(node => node.n === 'DOMContentLoaded')[0]
70-
expect(node).toBeTruthy()
71-
expect(node.s).toBeGreaterThan(10) // that DOMContentLoaded node has start time
72-
expect(node.o).toEqual('document') // that DOMContentLoaded origin is the document
73-
node = res.filter(node => node.n === 'load' && (node.o === 'document' || node.o === 'window'))[0]
74-
expect(node).toBeUndefined()
65+
const payload = traceAggregate.prepareHarvest()
66+
let res = payload.body
67+
68+
let node = res.filter(node => node.n === 'DOMContentLoaded')[0]
69+
expect(node).toBeTruthy()
70+
expect(node.s).toBeGreaterThan(10) // that DOMContentLoaded node has start time
71+
expect(node.o).toEqual('document') // that DOMContentLoaded origin is the document
72+
node = res.filter(node => node.n === 'load' && (node.o === 'document' || node.o === 'window'))[0]
73+
expect(node).toBeUndefined()
74+
75+
let hist = res.filter(node => node.n === 'history.pushState')[1]
76+
const originalPath = window.location.pathname
77+
expect(hist.s).toEqual(hist.e) // that hist node has no duration
78+
expect(hist.n).toEqual('history.pushState')
79+
expect(hist.o).toEqual(`${originalPath}#bar`)
80+
expect(hist.t).toEqual(`${originalPath}#foo`)
7581

76-
let hist = res.filter(node => node.n === 'history.pushState')[1]
77-
const originalPath = window.location.pathname
78-
expect(hist.s).toEqual(hist.e) // that hist node has no duration
79-
expect(hist.n).toEqual('history.pushState')
80-
expect(hist.o).toEqual(`${originalPath}#bar`)
81-
expect(hist.t).toEqual(`${originalPath}#foo`)
82+
let ajax = res.filter(node => node.t === 'ajax')[0]
83+
expect(ajax.s).toBeLessThan(ajax.e) // that it has some duration
84+
expect(ajax.n).toEqual('Ajax')
85+
expect(ajax.t).toEqual('ajax')
8286

83-
let ajax = res.filter(node => node.t === 'ajax')[0]
84-
expect(ajax.s).toBeLessThan(ajax.e) // that it has some duration
85-
expect(ajax.n).toEqual('Ajax')
86-
expect(ajax.t).toEqual('ajax')
87+
let pvt = res.filter(node => node.n === 'fi')[0]
88+
expect(pvt.o).toEqual('document')
89+
expect(pvt.s).toEqual(pvt.e) // that FI has no duration
90+
expect(pvt.t).toEqual('timing')
91+
pvt = res.filter(node => node.n === 'fid')[0]
92+
expect(pvt.o).toEqual('document')
93+
expect(pvt.s).toEqual(30) // that FID has a duration relative to FI'
94+
expect(pvt.e).toEqual(30 + 8)
95+
expect(pvt.t).toEqual('event')
8796

88-
let pvt = res.filter(node => node.n === 'fi')[0]
89-
expect(pvt.o).toEqual('document')
90-
expect(pvt.s).toEqual(pvt.e) // that FI has no duration
91-
expect(pvt.t).toEqual('timing')
92-
pvt = res.filter(node => node.n === 'fid')[0]
93-
expect(pvt.o).toEqual('document')
94-
expect(pvt.s).toEqual(30) // that FID has a duration relative to FI'
95-
expect(pvt.e).toEqual(30 + 8)
96-
expect(pvt.t).toEqual('event')
97+
let unknown = res.filter(n => n.o === 'unknown')
98+
expect(unknown.length).toEqual(0) // no events with unknown origin
99+
})
97100

98-
let unknown = res.filter(n => n.o === 'unknown')
99-
expect(unknown.length).toEqual(0) // no events with unknown origin
100-
}, 1000)
101+
test('prepareHarvest returns undefined if there are no trace nodes', () => {
102+
const spy = jest.spyOn(traceAggregate.traceStorage, 'takeSTNs')
103+
let payload
104+
expect(() => (payload = traceAggregate.prepareHarvest())).not.toThrow()
105+
expect(spy).toHaveBeenCalled()
106+
expect(payload).toBeUndefined()
107+
spy.mockRestore()
101108
})
102109

103-
test('tracks previously stored events and processes them once per occurrence', () => {
110+
test('tracks previously stored events and processes them once per occurrence', done => {
104111
document.addEventListener('visibilitychange', () => 1)
105112
document.addEventListener('visibilitychange', () => 2)
106113
document.addEventListener('visibilitychange', () => 3) // additional listeners should not generate additional nodes
@@ -113,12 +120,12 @@ describe('session trace', () => {
113120
}))
114121
expect(traceAggregate.traceStorage.prevStoredEvents.size).toEqual(1)
115122

116-
jest.advanceTimersToNextTimer(1) // this will increase perf.now by the default ~20ms to imitate some time gap
117-
document.dispatchEvent(new Event('visibilitychange'))
118-
expect(traceAggregate.traceStorage.trace.visibilitychange.length).toEqual(2)
119-
expect(traceAggregate.traceStorage.trace.visibilitychange[0].s).not.toEqual(traceAggregate.traceStorage.trace.visibilitychange[1].s) // should not have same start times
120-
expect(traceAggregate.traceStorage.prevStoredEvents.size).toEqual(2)
121-
122-
jest.useRealTimers()
123+
setTimeout(() => { // some time gap
124+
document.dispatchEvent(new Event('visibilitychange'))
125+
expect(traceAggregate.traceStorage.trace.visibilitychange.length).toEqual(2)
126+
expect(traceAggregate.traceStorage.trace.visibilitychange[0].s).not.toEqual(traceAggregate.traceStorage.trace.visibilitychange[1].s) // should not have same start times
127+
expect(traceAggregate.traceStorage.prevStoredEvents.size).toEqual(2)
128+
done()
129+
}, 1)
123130
})
124131
})

0 commit comments

Comments
 (0)