Skip to content

Commit

Permalink
Use fixures
Browse files Browse the repository at this point in the history
  • Loading branch information
amortemousque committed Sep 11, 2023
1 parent 24a00dc commit c2653c8
Show file tree
Hide file tree
Showing 14 changed files with 280 additions and 164 deletions.
3 changes: 2 additions & 1 deletion packages/rum-core/src/boot/startRum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '@datadog/browser-core/test'
import type { RumSessionManagerMock, TestSetupBuilder } from '../../test'
import { createRumSessionManagerMock, noopRecorderApi, noopWebVitalTelemetryDebug, setup } from '../../test'
import { RumPerformanceEntryType } from '../browser/performanceCollection'
import type { RumPerformanceNavigationTiming, RumPerformanceEntry } from '../browser/performanceCollection'
import type { LifeCycle } from '../domain/lifeCycle'
import { LifeCycleEventType } from '../domain/lifeCycle'
Expand Down Expand Up @@ -231,7 +232,7 @@ describe('rum events url', () => {
domComplete: 456 as RelativeTime,
domContentLoadedEventEnd: 345 as RelativeTime,
domInteractive: 234 as RelativeTime,
entryType: 'navigation',
entryType: RumPerformanceEntryType.NAVIGATION,
loadEventEnd: 567 as RelativeTime,
}
const VIEW_DURATION = 1000
Expand Down
76 changes: 48 additions & 28 deletions packages/rum-core/src/browser/performanceCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
relativeNow,
runOnReadyState,
addEventListener,
objectHasValue,
} from '@datadog/browser-core'

import type { RumConfiguration } from '../domain/configuration'
Expand All @@ -32,8 +33,22 @@ export interface RumPerformanceObserver extends PerformanceObserver {
observe(options?: PerformanceObserverInit & { durationThreshold: number }): void
}

// We want to use a real enum (i.e. not a const enum) here, to be able to check whether an arbitrary
// string is an expected performance entry
// eslint-disable-next-line no-restricted-syntax
export enum RumPerformanceEntryType {
EVENT = 'event',
FIRST_INPUT = 'first-input',
LARGEST_CONTENTFUL_PAINT = 'largest-contentful-paint',
LAYOUT_SHIFT = 'layout-shift',
LONG_TASK = 'longtask',
NAVIGATION = 'navigation',
PAINT = 'paint',
RESOURCE = 'resource',
}

export interface RumPerformanceResourceTiming {
entryType: 'resource'
entryType: RumPerformanceEntryType.RESOURCE
initiatorType: string
name: string
startTime: RelativeTime
Expand All @@ -54,20 +69,20 @@ export interface RumPerformanceResourceTiming {
}

export interface RumPerformanceLongTaskTiming {
entryType: 'longtask'
entryType: RumPerformanceEntryType.LONG_TASK
startTime: RelativeTime
duration: Duration
toJSON(): PerformanceEntryRepresentation
}

export interface RumPerformancePaintTiming {
entryType: 'paint'
entryType: RumPerformanceEntryType.PAINT
name: 'first-paint' | 'first-contentful-paint'
startTime: RelativeTime
}

export interface RumPerformanceNavigationTiming {
entryType: 'navigation'
entryType: RumPerformanceEntryType.NAVIGATION
domComplete: RelativeTime
domContentLoadedEventEnd: RelativeTime
domInteractive: RelativeTime
Expand All @@ -76,14 +91,14 @@ export interface RumPerformanceNavigationTiming {
}

export interface RumLargestContentfulPaintTiming {
entryType: 'largest-contentful-paint'
entryType: RumPerformanceEntryType.LARGEST_CONTENTFUL_PAINT
startTime: RelativeTime
size: number
element?: Element
}

export interface RumFirstInputTiming {
entryType: 'first-input'
entryType: RumPerformanceEntryType.FIRST_INPUT
startTime: RelativeTime
processingStart: RelativeTime
duration: Duration
Expand All @@ -92,15 +107,15 @@ export interface RumFirstInputTiming {
}

export interface RumPerformanceEventTiming {
entryType: 'event'
entryType: RumPerformanceEntryType.EVENT
startTime: RelativeTime
duration: Duration
interactionId?: number
target?: Node
}

export interface RumLayoutShiftTiming {
entryType: 'layout-shift'
entryType: RumPerformanceEntryType.LAYOUT_SHIFT
startTime: RelativeTime
value: number
hadRecentInput: boolean
Expand Down Expand Up @@ -147,8 +162,18 @@ export function startPerformanceCollection(lifeCycle: LifeCycle, configuration:
const handlePerformanceEntryList = monitor((entries: PerformanceObserverEntryList) =>
handleRumPerformanceEntries(lifeCycle, configuration, entries.getEntries())
)
const mainEntries = ['resource', 'navigation', 'longtask', 'paint']
const experimentalEntries = ['largest-contentful-paint', 'first-input', 'layout-shift', 'event']
const mainEntries = [
RumPerformanceEntryType.RESOURCE,
RumPerformanceEntryType.NAVIGATION,
RumPerformanceEntryType.LONG_TASK,
RumPerformanceEntryType.PAINT,
]
const experimentalEntries = [
RumPerformanceEntryType.LARGEST_CONTENTFUL_PAINT,
RumPerformanceEntryType.FIRST_INPUT,
RumPerformanceEntryType.LAYOUT_SHIFT,
RumPerformanceEntryType.EVENT,
]

try {
// Experimental entries are not retrieved by performance.getEntries()
Expand Down Expand Up @@ -200,12 +225,15 @@ export function retrieveInitialDocumentResourceTiming(
let timing: RumPerformanceResourceTiming

const forcedAttributes = {
entryType: 'resource' as const,
entryType: RumPerformanceEntryType.RESOURCE as const,
initiatorType: FAKE_INITIAL_DOCUMENT,
traceId: getDocumentTraceId(document),
}
if (supportPerformanceTimingEvent('navigation') && performance.getEntriesByType('navigation').length > 0) {
const navigationEntry = performance.getEntriesByType('navigation')[0]
if (
supportPerformanceTimingEvent(RumPerformanceEntryType.NAVIGATION) &&
performance.getEntriesByType(RumPerformanceEntryType.NAVIGATION).length > 0
) {
const navigationEntry = performance.getEntriesByType(RumPerformanceEntryType.NAVIGATION)[0]
timing = assign(navigationEntry.toJSON(), forcedAttributes)
} else {
const relativePerformanceTiming = computeRelativePerformanceTiming()
Expand All @@ -231,7 +259,7 @@ function retrieveNavigationTiming(
function sendFakeTiming() {
callback(
assign(computeRelativePerformanceTiming(), {
entryType: 'navigation' as const,
entryType: RumPerformanceEntryType.NAVIGATION as const,
})
)
}
Expand Down Expand Up @@ -264,7 +292,7 @@ function retrieveFirstInputTiming(configuration: RumConfiguration, callback: (ti
// when the system received the event (e.g. evt.timeStamp) and when it could run the callback
// (e.g. performance.now()).
const timing: RumFirstInputTiming = {
entryType: 'first-input',
entryType: RumPerformanceEntryType.FIRST_INPUT,
processingStart: relativeNow(),
startTime: evt.timeStamp as RelativeTime,
duration: 0 as Duration, // arbitrary value to avoid nullable duration and simplify INP logic
Expand Down Expand Up @@ -338,17 +366,9 @@ function handleRumPerformanceEntries(
configuration: RumConfiguration,
entries: Array<PerformanceEntry | RumPerformanceEntry>
) {
const rumPerformanceEntries = entries.filter(
(entry) =>
entry.entryType === 'resource' ||
entry.entryType === 'navigation' ||
entry.entryType === 'paint' ||
entry.entryType === 'longtask' ||
entry.entryType === 'largest-contentful-paint' ||
entry.entryType === 'first-input' ||
entry.entryType === 'layout-shift' ||
entry.entryType === 'event'
) as RumPerformanceEntry[]
const rumPerformanceEntries = entries.filter((entry): entry is RumPerformanceEntry =>
objectHasValue(RumPerformanceEntryType, entry)
)

const rumAllowedPerformanceEntries = rumPerformanceEntries.filter(
(entry) => !isIncompleteNavigation(entry) && !isForbiddenResource(configuration, entry)
Expand All @@ -360,9 +380,9 @@ function handleRumPerformanceEntries(
}

function isIncompleteNavigation(entry: RumPerformanceEntry) {
return entry.entryType === 'navigation' && entry.loadEventEnd <= 0
return entry.entryType === RumPerformanceEntryType.NAVIGATION && entry.loadEventEnd <= 0
}

function isForbiddenResource(configuration: RumConfiguration, entry: RumPerformanceEntry) {
return entry.entryType === 'resource' && !isAllowedRequestUrl(configuration, entry.name)
return entry.entryType === RumPerformanceEntryType.RESOURCE && !isAllowedRequestUrl(configuration, entry.name)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import type { Duration, RelativeTime, ServerDuration } from '@datadog/browser-core'
import type { RumSessionManagerMock, TestSetupBuilder } from '../../../test'
import { createRumSessionManagerMock, setup } from '../../../test'
import type { RumPerformanceEntry, RumPerformanceLongTaskTiming } from '../../browser/performanceCollection'
import {
RumPerformanceEntryType,
type RumPerformanceEntry,
type RumPerformanceLongTaskTiming,
} from '../../browser/performanceCollection'
import { RumEventType } from '../../rawRumEvent.types'
import { LifeCycleEventType } from '../lifeCycle'
import { startLongTaskCollection } from './longTaskCollection'

const LONG_TASK: RumPerformanceLongTaskTiming = {
duration: 100 as Duration,
entryType: 'longtask',
entryType: RumPerformanceEntryType.LONG_TASK,
startTime: 1234 as RelativeTime,
toJSON() {
return { name: 'self', duration: 100, entryType: 'longtask', startTime: 1234 }
Expand Down
4 changes: 2 additions & 2 deletions packages/rum-core/src/domain/resource/resourceUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Duration, RelativeTime, ServerDuration } from '@datadog/browser-core'
import { SPEC_ENDPOINTS } from '@datadog/browser-core/test'
import type { RumPerformanceResourceTiming } from '../../browser/performanceCollection'
import { RumPerformanceEntryType, type RumPerformanceResourceTiming } from '../../browser/performanceCollection'
import type { RumConfiguration } from '../configuration'
import { validateAndBuildRumConfiguration } from '../configuration'
import {
Expand All @@ -17,7 +17,7 @@ function generateResourceWith(overrides: Partial<RumPerformanceResourceTiming>)
domainLookupEnd: 14 as RelativeTime,
domainLookupStart: 13 as RelativeTime,
duration: 50 as Duration,
entryType: 'resource',
entryType: RumPerformanceEntryType.RESOURCE,
fetchStart: 12 as RelativeTime,
name: 'entry',
redirectEnd: 11 as RelativeTime,
Expand Down
9 changes: 5 additions & 4 deletions packages/rum-core/src/domain/view/setupViewTest.specHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Duration, RelativeTime } from '@datadog/browser-core'
import { noopWebVitalTelemetryDebug } from '../../../test'
import type { BuildContext } from '../../../test'
import { LifeCycleEventType } from '../lifeCycle'
import { RumPerformanceEntryType } from '../../browser/performanceCollection'
import type {
RumFirstInputTiming,
RumLargestContentfulPaintTiming,
Expand Down Expand Up @@ -75,12 +76,12 @@ function spyOnViews(name?: string) {
}

export const FAKE_PAINT_ENTRY: RumPerformancePaintTiming = {
entryType: 'paint',
entryType: RumPerformanceEntryType.PAINT,
name: 'first-contentful-paint',
startTime: 123 as RelativeTime,
}
export const FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY: RumLargestContentfulPaintTiming = {
entryType: 'largest-contentful-paint',
entryType: RumPerformanceEntryType.LARGEST_CONTENTFUL_PAINT,
startTime: 789 as RelativeTime,
size: 10,
}
Expand All @@ -90,12 +91,12 @@ export const FAKE_NAVIGATION_ENTRY: RumPerformanceNavigationTiming = {
domComplete: 456 as RelativeTime,
domContentLoadedEventEnd: 345 as RelativeTime,
domInteractive: 234 as RelativeTime,
entryType: 'navigation',
entryType: RumPerformanceEntryType.NAVIGATION,
loadEventEnd: 567 as RelativeTime,
}

export const FAKE_FIRST_INPUT_ENTRY: RumFirstInputTiming = {
entryType: 'first-input',
entryType: RumPerformanceEntryType.FIRST_INPUT,
processingStart: 1100 as RelativeTime,
startTime: 1000 as RelativeTime,
duration: 0 as Duration,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import {
ExperimentalFeature,
addExperimentalFeatures,
relativeNow,
resetExperimentalFeatures,
} from '@datadog/browser-core'
import { ExperimentalFeature, addExperimentalFeatures, resetExperimentalFeatures } from '@datadog/browser-core'
import type { TestSetupBuilder } from '../../../../test'
import { setup } from '../../../../test'
import { appendElement, appendTextNode, createPerformanceEntry, setup } from '../../../../test'
import type { LifeCycle } from '../../lifeCycle'
import { LifeCycleEventType } from '../../lifeCycle'
import { THROTTLE_VIEW_UPDATE_PERIOD } from '../trackViews'
import type { ViewTest } from '../setupViewTest.specHelper'
import { setupViewTest } from '../setupViewTest.specHelper'
import type { RumLayoutShiftTiming } from '../../../browser/performanceCollection'
import { RumPerformanceEntryType, type RumLayoutShiftTiming } from '../../../browser/performanceCollection'

describe('trackCumulativeLayoutShift', () => {
let setupBuilder: TestSetupBuilder
Expand All @@ -21,13 +16,7 @@ describe('trackCumulativeLayoutShift', () => {

function newLayoutShift(lifeCycle: LifeCycle, overrides: Partial<RumLayoutShiftTiming>) {
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
entryType: 'layout-shift',
startTime: relativeNow(),
hadRecentInput: false,
value: 0.1,
...overrides,
},
createPerformanceEntry(RumPerformanceEntryType.LAYOUT_SHIFT, overrides),
])
}

Expand Down Expand Up @@ -160,27 +149,17 @@ describe('trackCumulativeLayoutShift', () => {
})

describe('cls target element', () => {
let sandbox: HTMLDivElement

beforeEach(() => {
sandbox = document.createElement('div')
document.body.appendChild(sandbox)
})

afterEach(() => {
resetExperimentalFeatures()
sandbox.parentNode!.removeChild(sandbox)
})

it('should return the first target element selector amongst all the shifted nodes when FF enabled', () => {
addExperimentalFeatures([ExperimentalFeature.WEB_VITALS_ATTRIBUTION])
const { lifeCycle } = setupBuilder.build()
const { getViewUpdate, getViewUpdateCount } = viewTest

const textNode = sandbox.appendChild(document.createTextNode(''))
const divElement = sandbox.appendChild(document.createElement('div'))
divElement.setAttribute('id', 'div-element')

const textNode = appendTextNode('')
const divElement = appendElement('div', { id: 'div-element' })
newLayoutShift(lifeCycle, { sources: [{ node: textNode }, { node: divElement }, { node: textNode }] })

expect(getViewUpdateCount()).toEqual(1)
Expand All @@ -191,9 +170,7 @@ describe('trackCumulativeLayoutShift', () => {
const { lifeCycle } = setupBuilder.build()
const { getViewUpdate, getViewUpdateCount } = viewTest

const divElement = sandbox.appendChild(document.createElement('div'))
divElement.setAttribute('id', 'div-element')

const divElement = appendElement('div', { id: 'div-element' })
newLayoutShift(lifeCycle, { sources: [{ node: divElement }] })

expect(getViewUpdateCount()).toEqual(1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { RelativeTime } from '@datadog/browser-core'
import { restorePageVisibility, setPageVisibility } from '@datadog/browser-core/test'
import type { RumPerformancePaintTiming } from 'packages/rum-core/src/browser/performanceCollection'
import { RumPerformanceEntryType, type RumPerformancePaintTiming } from '../../../browser/performanceCollection'
import type { TestSetupBuilder } from '../../../../test'
import { setup } from '../../../../test'
import { LifeCycleEventType } from '../../lifeCycle'
Expand All @@ -9,7 +9,7 @@ import { FCP_MAXIMUM_DELAY, trackFirstContentfulPaint } from './trackFirstConten
import { trackFirstHidden } from './trackFirstHidden'

const FAKE_PAINT_ENTRY: RumPerformancePaintTiming = {
entryType: 'paint',
entryType: RumPerformanceEntryType.PAINT,
name: 'first-contentful-paint',
startTime: 123 as RelativeTime,
}
Expand Down
Loading

0 comments on commit c2653c8

Please sign in to comment.