diff --git a/src/plugins/event-plugins/WebVitalsPlugin.ts b/src/plugins/event-plugins/WebVitalsPlugin.ts index bc9a0d7b..1f21de41 100644 --- a/src/plugins/event-plugins/WebVitalsPlugin.ts +++ b/src/plugins/event-plugins/WebVitalsPlugin.ts @@ -85,13 +85,15 @@ export class WebVitalsPlugin extends InternalPlugin { timeToFirstByte: a.timeToFirstByte, resourceLoadDelay: a.resourceLoadDelay, resourceLoadTime: a.resourceLoadTime, - elementRenderDelay: a.elementRenderDelay, - navigationEntry: this.navigationEventId + elementRenderDelay: a.elementRenderDelay }; if (a.lcpResourceEntry) { const key = performanceKey(a.lcpResourceEntry as HasLatency); attribution.lcpResourceEntry = this.resourceEventIds.get(key); } + if (this.navigationEventId) { + attribution.navigationEntry = this.navigationEventId; + } this.context?.record(LCP_EVENT_TYPE, { version: '1.0.0', value: metric.value, diff --git a/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts b/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts index 8871ff66..e37d8ca9 100644 --- a/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts +++ b/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts @@ -3,11 +3,13 @@ import { CLS_EVENT_TYPE, FID_EVENT_TYPE, LCP_EVENT_TYPE, + PERFORMANCE_NAVIGATION_EVENT_TYPE, PERFORMANCE_RESOURCE_EVENT_TYPE } from '../../../plugins/utils/constant'; import { context, record } from '../../../test-utils/test-utils'; import { Topic } from '../../../event-bus/EventBus'; import { WebVitalsPlugin } from '../WebVitalsPlugin'; +import { navigationEvent } from '../../../test-utils/mock-data'; const mockLCPData = { delta: 239.51, @@ -50,6 +52,7 @@ const mockCLSData = { } }; +// only need hasLatency fields const imagePerformanceEntry = { duration: 50, startTime: 100 @@ -64,19 +67,24 @@ const imageResourceRumEvent: any = { } }; +const navigationRumEvent: any = { + id: 'nav-id', + type: PERFORMANCE_NAVIGATION_EVENT_TYPE, + details: navigationEvent +}; + const mockLCPDataWithImage = Object.assign({}, mockLCPData, { attribution: { ...mockLCPData.attribution, lcpResourceEntry: imagePerformanceEntry - }, - onFID: jest.fn(), - onCLS: jest.fn() + } }); jest.mock('web-vitals/attribution', () => { return { onLCP: jest.fn().mockImplementation((callback) => { context.eventBus.dispatch(Topic.EVENT, imageResourceRumEvent); + context.eventBus.dispatch(Topic.EVENT, navigationRumEvent); callback(mockLCPDataWithImage); }), onFID: jest @@ -97,7 +105,6 @@ describe('WebVitalsPlugin tests', () => { // Run plugin.load(context); - window.dispatchEvent(new Event('load')); // Assert expect(record).toHaveBeenCalledTimes(3); @@ -127,7 +134,6 @@ describe('WebVitalsPlugin tests', () => { // Run plugin.load(context); - window.dispatchEvent(new Event('load')); // Assert expect(record).toHaveBeenCalledTimes(3); @@ -153,7 +159,6 @@ describe('WebVitalsPlugin tests', () => { // Run plugin.load(context); - window.dispatchEvent(new Event('load')); // Assert expect(record).toHaveBeenCalledTimes(3); @@ -181,7 +186,6 @@ describe('WebVitalsPlugin tests', () => { plugin.load(context); plugin.disable(); plugin.enable(); - window.dispatchEvent(new Event('load')); // Assert expect(record).toHaveBeenCalled(); @@ -192,7 +196,6 @@ describe('WebVitalsPlugin tests', () => { plugin.load(context); plugin.disable(); - window.dispatchEvent(new Event('load')); // Assert expect(record).toHaveBeenCalled(); @@ -272,4 +275,35 @@ describe('WebVitalsPlugin tests', () => { expect(recordSpy).toHaveBeenCalled(); expect(unsubscribeSpy).toHaveBeenCalled(); }); + + test('when navigation is recorded then it is attributed to lcp', async () => { + const plugin = new WebVitalsPlugin(); + + plugin.load(context); + expect(record).toHaveBeenCalledWith( + LCP_EVENT_TYPE, + expect.objectContaining({ + attribution: expect.objectContaining({ + navigationEntry: navigationRumEvent.id + }) + }) + ); + }); + + test('when navigation is not recorded then it is not attributed to lcp', async () => { + navigationRumEvent.type = 'invalid'; + const plugin = new WebVitalsPlugin(); + + plugin.load(context); + expect(record).not.toHaveBeenCalledWith( + LCP_EVENT_TYPE, + expect.objectContaining({ + attribution: expect.objectContaining({ + navigationEntry: expect.anything() + }) + }) + ); + + navigationEvent.type = PERFORMANCE_NAVIGATION_EVENT_TYPE; + }); });