@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
265 lines (239 loc) • 8.59 kB
text/typescript
import './testUtility/asciiTimelineSerializer'
import { describe, expect, it } from 'vitest'
import { createCPUIdleProcessor } from './firstCPUIdle'
import {
Check,
FMP,
Idle,
LongTask,
makeEntries,
} from './testUtility/makeTimeline'
function getFirstCPUIdleEntry({
fmpTime,
entries,
}: {
fmpTime: number | null
entries: PerformanceEntry[]
}) {
const processor = createCPUIdleProcessor(fmpTime ?? 0)
let firstCPUIdle
for (const entry of entries) {
const result = processor.processPerformanceEntry(entry)
if (result !== undefined) {
firstCPUIdle = result
}
}
return firstCPUIdle
}
describe('createCPUIdleProcessor', () => {
it('No long tasks after FMP, FirstCPUIdle immediately after FMP + quiet window', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
Idle(4_000),
LongTask(400),
])
expect(entries).toMatchInlineSnapshot(`
events | fmp task(400)
timeline | |-<⋯ +4000 ⋯>-[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]
time (ms) | 200 4200
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
expect(firstCPUIdle).toEqual({ firstCpuIdle: 200 })
})
it('One light cluster after FMP, FirstCPUIdle at FMP', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
Idle(100),
LongTask(50),
Idle(50),
LongTask(50),
LongTask(50),
Idle(2_550),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | fmp task(50) task(50) task(50) check
timeline | |-------------------[++++++++]----------[++++++++]-[++++++++]-<⋯ +2550 ⋯>-|
time (ms) | 200 300 400 450 3050
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
expect(firstCPUIdle).toEqual({ firstCpuIdle: 200 })
})
it('One heavy cluster after FMP, FirstCPUIdle after the cluster', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
Idle(100),
LongTask(50),
Idle(50),
LongTask(200),
Idle(50),
LongTask(50),
Idle(2_500),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | fmp task(50) task(200) task(50) check
timeline | |-----------[++++]------[+++++++++++++++++++++++]------[++++]-<⋯ +2500 ⋯>--|
time (ms) | 200 300 400 650 3200
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
expect(firstCPUIdle).toEqual({ firstCpuIdle: 700 })
})
it('Multiple heavy clusters, FirstCPUIdle updated to end of last cluster', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
Idle(100),
LongTask(200),
Idle(400),
LongTask(200),
Idle(400),
LongTask(200),
Idle(2_100),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | fmp task(200) task(200) task(200) check
timeline | |---[+++++++]------------------[+++++++]------------------[+++++++]-<⋯ +2100 ⋯>--|
time (ms) | 200 300 900 1500 3800
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
const lastLongTask = entries.at(-2)!
const expectedResult = lastLongTask.startTime + lastLongTask.duration
expect(firstCPUIdle).toEqual({ firstCpuIdle: expectedResult })
})
it('Checking before the quiet window has passed - no long tasks processed, FirstCPUIdle not found', () => {
const { entries, fmpTime } = makeEntries([Idle(200), FMP, Idle(200), Check])
expect(entries).toMatchInlineSnapshot(`
events | fmp check
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 200 400
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
expect(firstCPUIdle).toEqual({ nextCheck: 2_400 })
})
it('One heavy cluster, followed by two light, value is after 1st heavy cluster', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
Idle(100),
LongTask(200),
Idle(100),
LongTask(100),
Idle(1_000),
LongTask(200),
Idle(1_000),
LongTask(200),
Idle(1_550),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | fmp task(200) task(100) task(200) task(200) check
timeline | |----[+++++++++]-----[+++]-<⋯ +1000 ⋯>--[+++++++++]-<⋯ +1000 ⋯>-[+++++++++]-<⋯ +1550 ⋯>-|
time (ms) | 200 300 600 1700 2900 4650
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
const lastHeavyClusterLongTask = entries.at(2)!
const expectedResult =
lastHeavyClusterLongTask.startTime + lastHeavyClusterLongTask.duration
expect(firstCPUIdle).toEqual({ firstCpuIdle: expectedResult })
})
it('Continuous heavy clusters', () => {
const { entries, fmpTime } = makeEntries([
FMP,
Idle(200),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
LongTask(300),
Idle(50),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | task(300) task(300) task(300) task(300) task(300) task(300) task(300) task(300)
events | fmp task(300) task(300) task(300) task(300) task(300) task(300) task(300) check
timeline | |-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-|-
time (ms) | 0 200 550 900 1250 1600 1950 2300 2650 3000 3350 3700 4050 4400 4750 5100 5450
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
expect(firstCPUIdle).toEqual({ nextCheck: 7_450 })
})
it('Light cluster followed by a heavy cluster a second later, FirstCPUIdle updated', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
LongTask(50),
Idle(50),
LongTask(50),
LongTask(50),
Idle(1_050),
LongTask(50),
Idle(50),
LongTask(50),
Idle(50),
LongTask(200),
Idle(50),
LongTask(200),
Idle(2_050),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events | task(50) task(50) task(50)
events | fmp task(50) task(50) task(200) task(200) check
timeline | [+]--[+]--[+]-<⋯ +1050 ⋯>[+]--[+]---[+++++++++++]---[+++++++++++]-<⋯ +2050 ⋯>--|
time (ms) | 200 300 350 1450 1550 1650 1900 4150
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
const lastLongTask = entries.at(-2)!
const expectedResult = lastLongTask.startTime + lastLongTask.duration
expect(firstCPUIdle).toEqual({ firstCpuIdle: expectedResult })
})
it('A long task overlaps FMP, we consider FirstCPUIdle after the long task', () => {
const { entries, fmpTime } = makeEntries([
Idle(200),
FMP,
LongTask(110, { start: 150 }), // Overlaps with FMP
Idle(2_300),
Check,
])
expect(entries).toMatchInlineSnapshot(`
events |
events | task(110) fmp check
timeline | [+++++++++++++++++++++++++++++++++++++++++++++++++++++]-<⋯ +2240 ⋯>-|
timeline | -------------------------|-<⋯ +2300 ⋯>-------------------------------
time (ms) | 150 200 2500
`)
const firstCPUIdle = getFirstCPUIdleEntry({ fmpTime, entries })
const lastLongTask = entries.at(-2)!
const expectedResult = lastLongTask.startTime + lastLongTask.duration
expect(firstCPUIdle).toEqual({ firstCpuIdle: expectedResult })
})
})