Skip to content

Commit

Permalink
Take first-input entry into account
Browse files Browse the repository at this point in the history
  • Loading branch information
amortemousque committed Aug 24, 2023
1 parent 9bc714f commit 0a0d5a2
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
3 changes: 3 additions & 0 deletions packages/rum-core/src/browser/performanceCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ export interface RumFirstInputTiming {
entryType: 'first-input'
startTime: RelativeTime
processingStart: RelativeTime
duration: Duration
target?: Node
interactionId?: number
}

export interface RumPerformanceEventTiming {
Expand Down Expand Up @@ -264,6 +266,7 @@ function retrieveFirstInputTiming(configuration: RumConfiguration, callback: (ti
entryType: 'first-input',
processingStart: relativeNow(),
startTime: evt.timeStamp as RelativeTime,
duration: 0 as Duration, // arbitrary value to avoid nullable duration and simplify INP logic
}

if (evt.type === DOM_EVENT.POINTER_DOWN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const FAKE_FIRST_INPUT_ENTRY: RumFirstInputTiming = {
processingStart: 1100 as RelativeTime,
startTime: 1000 as RelativeTime,
target: document.createElement('button'),
duration: 0 as Duration,
}

describe('trackInitialViewTimings', () => {
Expand Down Expand Up @@ -325,6 +326,7 @@ describe('firstInputTimings', () => {
entryType: 'first-input' as const,
processingStart: 900 as RelativeTime,
startTime: 1000 as RelativeTime,
duration: 0 as Duration,
},
])

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Duration } from '@datadog/browser-core'
import type { Duration, RelativeTime } from '@datadog/browser-core'
import {
ExperimentalFeature,
addExperimentalFeatures,
Expand All @@ -7,7 +7,11 @@ import {
} from '@datadog/browser-core'
import type { TestSetupBuilder } from '../../../../test'
import { setup } from '../../../../test'
import type { BrowserWindow, RumPerformanceEventTiming } from '../../../browser/performanceCollection'
import type {
BrowserWindow,
RumFirstInputTiming,
RumPerformanceEventTiming,
} from '../../../browser/performanceCollection'
import { ViewLoadingType } from '../../../rawRumEvent.types'
import type { LifeCycle } from '../../lifeCycle'
import { LifeCycleEventType } from '../../lifeCycle'
Expand All @@ -24,14 +28,19 @@ describe('trackInteractionToNextPaint', () => {

function newInteraction(
lifeCycle: LifeCycle,
{ interactionId, duration = 40 as Duration, entryType = 'event' }: Partial<RumPerformanceEventTiming>
{
interactionId,
duration = 40 as Duration,
entryType = 'event',
}: Partial<RumPerformanceEventTiming | RumFirstInputTiming>
) {
if (interactionId) {
interactionCountStub.incrementInteractionCount()
}
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
entryType,
processingStart: relativeNow(),
startTime: relativeNow(),
duration,
interactionId,
Expand Down Expand Up @@ -92,6 +101,15 @@ describe('trackInteractionToNextPaint', () => {
interactionCountStub.setInteractionCount(1 as Duration) // assumes an interaction happened but no PERFORMANCE_ENTRIES_COLLECTED have been triggered
expect(getInteractionToNextPaint()).toEqual(0 as Duration)
})

it('should take first-input entry into account', () => {
const { lifeCycle } = setupBuilder.build()
newInteraction(lifeCycle, {
interactionId: 1,
entryType: 'first-input',
})
expect(getInteractionToNextPaint()).toEqual(40 as Duration)
})
})

describe('if feature flag disabled', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Duration, noop, isExperimentalFeatureEnabled, ExperimentalFeature } from '@datadog/browser-core'
import { supportPerformanceTimingEvent, type RumPerformanceEventTiming } from '../../../browser/performanceCollection'
import { supportPerformanceTimingEvent } from '../../../browser/performanceCollection'
import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceCollection'
import { LifeCycleEventType, type LifeCycle } from '../../lifeCycle'
import { ViewLoadingType } from '../../../rawRumEvent.types'
import { getInteractionCount, initInteractionCountPolyfill } from './interactionCountPolyfill'
Expand Down Expand Up @@ -30,7 +31,7 @@ export function trackInteractionToNextPaint(viewLoadingType: ViewLoadingType, li

const { unsubscribe: stop } = lifeCycle.subscribe(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, (entries) => {
for (const entry of entries) {
if (entry.entryType === 'event' && entry.interactionId) {
if ((entry.entryType === 'event' || entry.entryType === 'first-input') && entry.interactionId) {
longestInteractions.process(entry)
}
}
Expand All @@ -56,7 +57,7 @@ export function trackInteractionToNextPaint(viewLoadingType: ViewLoadingType, li
}

function trackLongestInteractions(getViewInteractionCount: () => number) {
const longestInteractions: RumPerformanceEventTiming[] = []
const longestInteractions: Array<RumPerformanceEventTiming | RumFirstInputTiming> = []

function sortAndTrimLongestInteractions() {
longestInteractions.sort((a, b) => b.duration - a.duration).splice(MAX_INTERACTION_ENTRIES)
Expand All @@ -68,7 +69,7 @@ function trackLongestInteractions(getViewInteractionCount: () => number) {
* - if its duration is long enough, add the performance entry to the list of worst interactions
* - if an entry with the same interaction id exists and its duration is lower than the new one, then replace it in the list of worst interactions
*/
process(entry: RumPerformanceEventTiming) {
process(entry: RumPerformanceEventTiming | RumFirstInputTiming) {
const interactionIndex = longestInteractions.findIndex(
(interaction) => entry.interactionId === interaction.interactionId
)
Expand Down

0 comments on commit 0a0d5a2

Please sign in to comment.