Skip to content

Commit 606628c

Browse files
authored
[RUM Profiler] Fix discrepancy on view-id correlation (#3776)
1 parent cfd2dc8 commit 606628c

File tree

2 files changed

+107
-3
lines changed

2 files changed

+107
-3
lines changed

packages/rum/src/domain/profiling/profiler.spec.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,105 @@ describe('profiler', () => {
276276
expect(lastCall.views[1].viewId).toBe('view-profile')
277277
expect(lastCall.views[1].viewName).toBe('/v1/user/?/profile')
278278
})
279+
280+
it('should keep track of the latest view in the Profiler', async () => {
281+
const { profiler, profilingContextManager, mockedRumProfilerTrace } = setupProfiler()
282+
283+
// Navigate to the user view
284+
history.pushState({}, '', '/user/123')
285+
286+
const initialViewEntry = {
287+
id: 'view-initial',
288+
name: 'view-initial',
289+
startClocks: {
290+
relative: relativeNow(),
291+
timeStamp: timeStampNow(),
292+
},
293+
}
294+
295+
profiler.start(initialViewEntry)
296+
297+
await waitForBoolean(() => profiler.isRunning())
298+
expect(profilingContextManager.get()?.status).toBe('running')
299+
300+
// Navigate to a new profile view
301+
history.pushState({}, '', '/v1/user/3A2/profile')
302+
303+
const nextViewEntry = {
304+
id: 'view-next',
305+
name: 'view-next',
306+
startClocks: {
307+
relative: relativeNow(),
308+
timeStamp: timeStampNow(),
309+
},
310+
}
311+
312+
// Emit a view created event
313+
lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, nextViewEntry)
314+
315+
// Emulate visibility change to `hidden` state
316+
setVisibilityState('hidden')
317+
318+
// Wait for profiler to pause
319+
await waitForBoolean(() => profiler.isPaused())
320+
321+
// Assert that the profiler has collected data on pause.
322+
expect(sendProfileSpy).toHaveBeenCalledTimes(1)
323+
324+
// Check the the sendProfilesSpy was called with the mocked trace
325+
expect(sendProfileSpy).toHaveBeenCalledWith(
326+
{
327+
...mockedRumProfilerTrace,
328+
views: [
329+
{
330+
viewId: initialViewEntry.id,
331+
viewName: initialViewEntry.name,
332+
startClocks: initialViewEntry.startClocks,
333+
},
334+
{
335+
viewId: nextViewEntry.id,
336+
viewName: nextViewEntry.name,
337+
startClocks: nextViewEntry.startClocks,
338+
},
339+
],
340+
},
341+
jasmine.any(Object),
342+
'session-id-1'
343+
)
344+
345+
// Change back to visible
346+
setVisibilityState('visible')
347+
document.dispatchEvent(new Event('visibilitychange'))
348+
349+
// Wait for profiler to restart
350+
await waitForBoolean(() => profiler.isRunning())
351+
expect(profilingContextManager.get()?.status).toBe('running')
352+
353+
// Stop collection of profile.
354+
await profiler.stop()
355+
356+
// Wait for stop of collection.
357+
await waitForBoolean(() => profiler.isStopped())
358+
expect(profilingContextManager.get()?.status).toBe('stopped')
359+
360+
expect(sendProfileSpy).toHaveBeenCalledTimes(2)
361+
362+
// Check the the sendProfilesSpy was called with the mocked trace
363+
expect(sendProfileSpy).toHaveBeenCalledWith(
364+
{
365+
...mockedRumProfilerTrace,
366+
views: [
367+
{
368+
viewId: nextViewEntry.id, // The view id should be the last one collected (in this case the "next" view)
369+
viewName: nextViewEntry.name,
370+
startClocks: nextViewEntry.startClocks,
371+
},
372+
],
373+
},
374+
jasmine.any(Object),
375+
'session-id-1'
376+
)
377+
})
279378
})
280379

281380
function waitForBoolean(booleanCallback: () => boolean) {

packages/rum/src/domain/profiling/profiler.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,17 @@ export function createRumProfiler(
128128

129129
// Whenever the View is updated, we add a views entry to the profiler instance.
130130
const viewUpdatedSubscription = lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, (view) => {
131-
// Note: `view.name` is only filled when users use manual view creation via `startView` method.
132-
collectViewEntry({
131+
const viewEntry = {
133132
viewId: view.id,
133+
// Note: `viewName` is only filled when users use manual view creation via `startView` method.
134134
viewName: getCustomOrDefaultViewName(view.name, document.location.pathname),
135135
startClocks: view.startClocks,
136-
})
136+
}
137+
138+
collectViewEntry(viewEntry)
139+
140+
// Update last view entry
141+
lastViewEntry = viewEntry
137142
})
138143
cleanupTasks.push(viewUpdatedSubscription.unsubscribe)
139144

0 commit comments

Comments
 (0)