From 6d19c2096ce3b312fac69716cb66c4c1ac6e1ab8 Mon Sep 17 00:00:00 2001 From: "roman.gaignault" Date: Tue, 9 Jul 2024 16:27:07 +0200 Subject: [PATCH 1/3] update view context history with the new name --- .../src/domain/contexts/viewContexts.spec.ts | 69 ++++++++++++++++++- .../src/domain/contexts/viewContexts.ts | 9 ++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/packages/rum-core/src/domain/contexts/viewContexts.spec.ts b/packages/rum-core/src/domain/contexts/viewContexts.spec.ts index 5e8bd154f0..a970c36436 100644 --- a/packages/rum-core/src/domain/contexts/viewContexts.spec.ts +++ b/packages/rum-core/src/domain/contexts/viewContexts.spec.ts @@ -1,15 +1,64 @@ -import type { RelativeTime } from '@datadog/browser-core' +import type { RelativeTime, Duration, TimeStamp } from '@datadog/browser-core' import { relativeToClocks, CLEAR_OLD_VALUES_INTERVAL } from '@datadog/browser-core' import type { TestSetupBuilder } from '../../../test' import { setup } from '../../../test' import { LifeCycleEventType } from '../lifeCycle' -import type { ViewCreatedEvent } from '../view/trackViews' +import type { ViewCreatedEvent, ViewEvent } from '../view/trackViews' +import { ViewLoadingType } from '../../rawRumEvent.types' import type { ViewContexts } from './viewContexts' import { startViewContexts, VIEW_CONTEXT_TIME_OUT_DELAY } from './viewContexts' describe('viewContexts', () => { const FAKE_ID = 'fake' const startClocks = relativeToClocks(10 as RelativeTime) + const VIEW: ViewEvent = { + customTimings: { + bar: 20 as Duration, + foo: 10 as Duration, + }, + documentVersion: 3, + duration: 100 as Duration, + eventCounts: { + errorCount: 10, + longTaskCount: 10, + resourceCount: 10, + actionCount: 10, + frustrationCount: 10, + }, + id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', + name: 'Fake Name', + isActive: false, + loadingType: ViewLoadingType.INITIAL_LOAD, + location: {} as Location, + startClocks: { relative: 1234 as RelativeTime, timeStamp: 123456789 as TimeStamp }, + initialViewMetrics: { + navigationTimings: { + firstByte: 10 as Duration, + domComplete: 10 as Duration, + domContentLoaded: 10 as Duration, + domInteractive: 10 as Duration, + loadEvent: 10 as Duration, + }, + firstInput: { + delay: 12 as Duration, + time: 10 as RelativeTime, + }, + firstContentfulPaint: 10 as Duration, + largestContentfulPaint: { value: 10 as RelativeTime }, + }, + commonViewMetrics: { + loadingTime: 20 as Duration, + cumulativeLayoutShift: { value: 1, time: 100 as Duration }, + interactionToNextPaint: { value: 10 as Duration, time: 100 as Duration }, + scroll: { + maxDepth: 2000, + maxScrollHeight: 3000, + maxScrollHeightTime: 4000000000 as Duration, + maxDepthScrollTop: 1000, + }, + }, + sessionIsActive: true, + } function buildViewCreatedEvent(partialViewCreatedEvent: Partial = {}): ViewCreatedEvent { return { @@ -105,6 +154,22 @@ describe('viewContexts', () => { lifeCycle.notify(LifeCycleEventType.BEFORE_VIEW_CREATED, buildViewCreatedEvent({ name: 'Fake name' })) expect(viewContexts.findView()!.name).toBe('Fake name') }) + + it('should update the view name for the current context', () => { + const { lifeCycle } = setupBuilder.build() + lifeCycle.notify( + LifeCycleEventType.BEFORE_VIEW_CREATED, + buildViewCreatedEvent({ + id: '0', + name: 'foo', + startClocks: relativeToClocks(10 as RelativeTime), + service: 'test', + version: '1', + }) + ) + lifeCycle.notify(LifeCycleEventType.VIEW_UPDATED, VIEW) + expect(viewContexts.findView()!.name).toBe('Fake Name') + }) }) describe('history contexts', () => { diff --git a/packages/rum-core/src/domain/contexts/viewContexts.ts b/packages/rum-core/src/domain/contexts/viewContexts.ts index 93d404284a..bd3eef7227 100644 --- a/packages/rum-core/src/domain/contexts/viewContexts.ts +++ b/packages/rum-core/src/domain/contexts/viewContexts.ts @@ -2,7 +2,7 @@ import type { RelativeTime, ClocksState } from '@datadog/browser-core' import { SESSION_TIME_OUT_DELAY, ValueHistory } from '@datadog/browser-core' import type { LifeCycle } from '../lifeCycle' import { LifeCycleEventType } from '../lifeCycle' -import type { ViewCreatedEvent } from '../view/trackViews' +import type { ViewCreatedEvent, ViewEvent } from '../view/trackViews' export const VIEW_CONTEXT_TIME_OUT_DELAY = SESSION_TIME_OUT_DELAY @@ -30,6 +30,13 @@ export function startViewContexts(lifeCycle: LifeCycle): ViewContexts { viewContextHistory.closeActive(endClocks.relative) }) + lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, (data: ViewEvent) => { + const currentView = viewContextHistory.find() + if (currentView && data.name) { + currentView.name = data.name + } + }) + lifeCycle.subscribe(LifeCycleEventType.SESSION_RENEWED, () => { viewContextHistory.reset() }) From a3851298b4ce78a977ffc125e76a4b00408036d1 Mon Sep 17 00:00:00 2001 From: "roman.gaignault" Date: Tue, 9 Jul 2024 17:13:41 +0200 Subject: [PATCH 2/3] add e2e test --- test/e2e/scenario/rum/init.scenario.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/e2e/scenario/rum/init.scenario.ts b/test/e2e/scenario/rum/init.scenario.ts index cd3d829500..1949ae5dd7 100644 --- a/test/e2e/scenario/rum/init.scenario.ts +++ b/test/e2e/scenario/rum/init.scenario.ts @@ -117,7 +117,7 @@ describe('API calls and events around init', () => { intakeRegistry, { name: 'before init', viewId: initialView.view.id }, { name: 'before manual view', viewId: initialView.view.id }, - { name: 'after manual view', viewId: initialView.view.id } + { name: 'after manual view', viewId: initialView.view.id, viewName: 'after manual view' } ) }) }) @@ -173,12 +173,18 @@ function expectToHaveErrors(events: IntakeRegistry, ...errors: Array<{ message: } } -function expectToHaveActions(events: IntakeRegistry, ...actions: Array<{ name: string; viewId: string }>) { +function expectToHaveActions( + events: IntakeRegistry, + ...actions: Array<{ name: string; viewId: string; viewName?: string }> +) { expect(events.rumActionEvents.length).toBe(actions.length) for (let i = 0; i < actions.length; i++) { const registryAction = events.rumActionEvents[i] const expectedAction = actions[i] expect(registryAction.action.target!.name).toBe(expectedAction.name) expect(registryAction.view.id).toBe(expectedAction.viewId) + if (i === 0 && expectedAction.viewName) { + expect(registryAction.view.name).toBe(expectedAction.viewName) + } } } From 45c6bed16c105e734d7f9ed04a0d9c2648bc0665 Mon Sep 17 00:00:00 2001 From: "roman.gaignault" Date: Thu, 11 Jul 2024 14:02:52 +0200 Subject: [PATCH 3/3] update unit test with shorter input --- .../src/domain/contexts/viewContexts.spec.ts | 67 ++----------------- .../src/domain/contexts/viewContexts.ts | 8 +-- 2 files changed, 10 insertions(+), 65 deletions(-) diff --git a/packages/rum-core/src/domain/contexts/viewContexts.spec.ts b/packages/rum-core/src/domain/contexts/viewContexts.spec.ts index a970c36436..d53d9a9f3e 100644 --- a/packages/rum-core/src/domain/contexts/viewContexts.spec.ts +++ b/packages/rum-core/src/domain/contexts/viewContexts.spec.ts @@ -1,64 +1,15 @@ -import type { RelativeTime, Duration, TimeStamp } from '@datadog/browser-core' +import type { RelativeTime } from '@datadog/browser-core' import { relativeToClocks, CLEAR_OLD_VALUES_INTERVAL } from '@datadog/browser-core' import type { TestSetupBuilder } from '../../../test' import { setup } from '../../../test' import { LifeCycleEventType } from '../lifeCycle' import type { ViewCreatedEvent, ViewEvent } from '../view/trackViews' -import { ViewLoadingType } from '../../rawRumEvent.types' import type { ViewContexts } from './viewContexts' import { startViewContexts, VIEW_CONTEXT_TIME_OUT_DELAY } from './viewContexts' describe('viewContexts', () => { const FAKE_ID = 'fake' const startClocks = relativeToClocks(10 as RelativeTime) - const VIEW: ViewEvent = { - customTimings: { - bar: 20 as Duration, - foo: 10 as Duration, - }, - documentVersion: 3, - duration: 100 as Duration, - eventCounts: { - errorCount: 10, - longTaskCount: 10, - resourceCount: 10, - actionCount: 10, - frustrationCount: 10, - }, - id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - name: 'Fake Name', - isActive: false, - loadingType: ViewLoadingType.INITIAL_LOAD, - location: {} as Location, - startClocks: { relative: 1234 as RelativeTime, timeStamp: 123456789 as TimeStamp }, - initialViewMetrics: { - navigationTimings: { - firstByte: 10 as Duration, - domComplete: 10 as Duration, - domContentLoaded: 10 as Duration, - domInteractive: 10 as Duration, - loadEvent: 10 as Duration, - }, - firstInput: { - delay: 12 as Duration, - time: 10 as RelativeTime, - }, - firstContentfulPaint: 10 as Duration, - largestContentfulPaint: { value: 10 as RelativeTime }, - }, - commonViewMetrics: { - loadingTime: 20 as Duration, - cumulativeLayoutShift: { value: 1, time: 100 as Duration }, - interactionToNextPaint: { value: 10 as Duration, time: 100 as Duration }, - scroll: { - maxDepth: 2000, - maxScrollHeight: 3000, - maxScrollHeightTime: 4000000000 as Duration, - maxDepthScrollTop: 1000, - }, - }, - sessionIsActive: true, - } function buildViewCreatedEvent(partialViewCreatedEvent: Partial = {}): ViewCreatedEvent { return { @@ -157,17 +108,11 @@ describe('viewContexts', () => { it('should update the view name for the current context', () => { const { lifeCycle } = setupBuilder.build() - lifeCycle.notify( - LifeCycleEventType.BEFORE_VIEW_CREATED, - buildViewCreatedEvent({ - id: '0', - name: 'foo', - startClocks: relativeToClocks(10 as RelativeTime), - service: 'test', - version: '1', - }) - ) - lifeCycle.notify(LifeCycleEventType.VIEW_UPDATED, VIEW) + lifeCycle.notify(LifeCycleEventType.BEFORE_VIEW_CREATED, buildViewCreatedEvent({ name: 'foo' })) + lifeCycle.notify(LifeCycleEventType.VIEW_UPDATED, { + startClocks, + name: 'Fake Name', + } as ViewEvent) expect(viewContexts.findView()!.name).toBe('Fake Name') }) }) diff --git a/packages/rum-core/src/domain/contexts/viewContexts.ts b/packages/rum-core/src/domain/contexts/viewContexts.ts index bd3eef7227..d83bb945fb 100644 --- a/packages/rum-core/src/domain/contexts/viewContexts.ts +++ b/packages/rum-core/src/domain/contexts/viewContexts.ts @@ -30,10 +30,10 @@ export function startViewContexts(lifeCycle: LifeCycle): ViewContexts { viewContextHistory.closeActive(endClocks.relative) }) - lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, (data: ViewEvent) => { - const currentView = viewContextHistory.find() - if (currentView && data.name) { - currentView.name = data.name + lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, (viewUpdate: ViewEvent) => { + const currentView = viewContextHistory.find(viewUpdate.startClocks.relative) + if (currentView && viewUpdate.name) { + currentView.name = viewUpdate.name } })