@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
814 lines • 41.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
require("./testUtility/asciiTimelineSerializer");
const vitest_1 = require("vitest");
const constants_1 = require("./constants");
const getDynamicQuietWindowDuration_1 = require("./getDynamicQuietWindowDuration");
const matchSpan = __importStar(require("./matchSpan"));
const makeTimeline_1 = require("./testUtility/makeTimeline");
const processSpans_1 = require("./testUtility/processSpans");
const TraceManager_1 = require("./TraceManager");
const GOOGLES_QUIET_WINDOW_DURATION = 2_000;
const GOOGLES_CLUSTER_PADDING = 1_000;
const GOOGLES_HEAVY_CLUSTER_THRESHOLD = 250;
const cpuIdleProcessorOptions = {
getQuietWindowDuration: () => GOOGLES_QUIET_WINDOW_DURATION,
clusterPadding: GOOGLES_CLUSTER_PADDING,
heavyClusterThreshold: GOOGLES_HEAVY_CLUSTER_THRESHOLD,
};
(0, vitest_1.describe)('TraceManager with Capture Interactivity', () => {
let reportFn;
let generateId;
let reportErrorFn;
const DEFAULT_COLDBOOT_TIMEOUT_DURATION = 45_000;
vitest_1.vitest.useFakeTimers({
now: 0,
});
(0, vitest_1.beforeEach)(() => {
reportFn = vitest_1.vitest.fn();
generateId = vitest_1.vitest.fn().mockReturnValue('trace-id');
reportErrorFn = vitest_1.vitest.fn();
});
(0, vitest_1.afterEach)(() => {
vitest_1.vitest.clearAllMocks();
vitest_1.vitest.clearAllTimers();
});
(0, vitest_1.it)('correctly captures trace while waiting the long tasks to settle', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: { ticketId: '1' },
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(50)}------<===5s===>---------${makeTimeline_1.Check}
Time: ${0} ${2_000} ${2_001} ${2_001 + constants_1.DEFAULT_INTERACTIVE_TIMEOUT_DURATION}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +2000 ⋯>-|
time (ms) | 0 2000
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(2_000);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(2_000);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('completes the trace with waiting-for-interactive-timeout', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const interactiveTimeout = 5_000;
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: {
...cpuIdleProcessorOptions,
timeout: interactiveTimeout,
},
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(interactiveTimeout)}
Time: ${0} ${2_000} ${2_050}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +2000 ⋯>-|
time (ms) | 0 2000
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(2_000);
(0, vitest_1.expect)(report.interruptionReason).toBe('waiting-for-interactive-timeout');
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(report.status).toBe('ok');
});
(0, vitest_1.it)('completes the trace when interrupted during waiting for capture interactive to finish', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.interrupt-during-long-task-operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [matchSpan.withName('end')],
interruptOnSpans: [matchSpan.withName('interrupt')],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}---------${(0, makeTimeline_1.Render)('end', 0)}---------${(0, makeTimeline_1.Render)('interrupt', 0)}--${(0, makeTimeline_1.LongTask)(100)}--${makeTimeline_1.Check}
Time: ${0} ${200} ${201} ${300} ${5_000}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 0 200
`);
(0, vitest_1.expect)(report.name).toBe('ticket.interrupt-during-long-task-operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBe('matched-on-interrupt');
});
(0, vitest_1.it)('timeouts the trace while deboucing AND the last span is past the timeout duration', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.debounce-then-interrupted-operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
debounceOnSpans: [{ name: 'debounce' }],
captureInteractive: cpuIdleProcessorOptions,
debounceWindow: 300,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.Render)('debounce', 0)}------${makeTimeline_1.Check}
Time: ${0} ${50} ${100} ${DEFAULT_COLDBOOT_TIMEOUT_DURATION + 100}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end debounce
timeline | |-<⋯ +50 ⋯>-|-<⋯ +50 ⋯>-|
time (ms) | 0 50 100
`);
(0, vitest_1.expect)(report.name).toBe('ticket.debounce-then-interrupted-operation');
(0, vitest_1.expect)(report.status).toBe('interrupted');
(0, vitest_1.expect)(report.duration).toBeNull();
(0, vitest_1.expect)(report.interruptionReason).toBe('timeout');
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
});
(0, vitest_1.it)('completes the trace when debouncing is done AND is waiting for capture interactive to finish', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const CUSTOM_CAPTURE_INTERACTIVE_TIMEOUT = 300;
const tracer = traceManager.createTracer({
name: 'ticket.debounce-then-interrupted-operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
debounceOnSpans: [{ name: 'debounce' }],
captureInteractive: {
...cpuIdleProcessorOptions,
timeout: CUSTOM_CAPTURE_INTERACTIVE_TIMEOUT,
},
debounceWindow: 100,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}---------------------${(0, makeTimeline_1.Render)('debounce', 100)}------------------${makeTimeline_1.Check}
Time: ${0} ${DEFAULT_COLDBOOT_TIMEOUT_DURATION - 500} ${DEFAULT_COLDBOOT_TIMEOUT_DURATION - 499} ${DEFAULT_COLDBOOT_TIMEOUT_DURATION + 1}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +44500 ⋯>-|
time (ms) | 0 44500
`);
(0, vitest_1.expect)(report.name).toBe('ticket.debounce-then-interrupted-operation');
(0, vitest_1.expect)(report.duration).toBe(44_500);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBe('timeout');
});
(0, vitest_1.it)('uses getQuietWindowDuration from capture interactive config', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const CUSTOM_QUIET_WINDOW_DURATION = 2_000;
const TRACE_DURATION = 1_000;
const getQuietWindowDuration = vitest_1.vitest
.fn()
.mockReturnValue(CUSTOM_QUIET_WINDOW_DURATION);
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: {
...cpuIdleProcessorOptions,
timeout: 100,
getQuietWindowDuration,
},
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(5)}------------${(0, makeTimeline_1.LongTask)(5)}-----${makeTimeline_1.Check}
Time: ${0} ${TRACE_DURATION} ${1_001} ${1_050} ${1_200}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +1000 ⋯>-|
time (ms) | 0 1000
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(TRACE_DURATION);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBe('waiting-for-interactive-timeout');
(0, vitest_1.expect)(getQuietWindowDuration).toHaveBeenCalled();
(0, vitest_1.expect)(getQuietWindowDuration).toHaveBeenCalledWith(1_055, TRACE_DURATION);
});
(0, vitest_1.it)('uses createQuietWindowDurationCalculator for getQuietWindowDuration in capture interactive config', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const TRACE_DURATION = 1_000;
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: {
...cpuIdleProcessorOptions,
timeout: 1_000,
getQuietWindowDuration: (0, getDynamicQuietWindowDuration_1.createQuietWindowDurationCalculator)(),
},
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----------${(0, makeTimeline_1.LongTask)(5)}----------------${(0, makeTimeline_1.LongTask)(50)}---${makeTimeline_1.Check}
Time: ${0} ${TRACE_DURATION} ${1_001} ${1_945} ${2_001}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +1000 ⋯>-|
time (ms) | 0 1000
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(TRACE_DURATION);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBe('waiting-for-interactive-timeout');
});
(0, vitest_1.it)('No long tasks after FMP, FirstCPUIdle immediately after FMP + quiet window', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}----------${(0, makeTimeline_1.LongTask)(400)}-----${makeTimeline_1.Check}
Time: ${0} ${200} ${4_600} ${5_000}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 0 200
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(200);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('One light cluster after FMP, FirstCPUIdle at FMP', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}----------${(0, makeTimeline_1.LongTask)(50)}------${(0, makeTimeline_1.LongTask)(50)}-----${(0, makeTimeline_1.LongTask)(50)}---------${makeTimeline_1.Check}
Time: ${0} ${200} ${300} ${400} ${450} ${3_050}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 0 200
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(200);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('One heavy cluster after FMP, FirstCPUIdle after the cluster', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}--${(0, makeTimeline_1.LongTask)(50)}}-${(0, makeTimeline_1.LongTask)(200)}-----${(0, makeTimeline_1.LongTask)(50)}-----------${makeTimeline_1.Check}
Time: ${0} ${200} ${300} ${400} ${650} ${3_200}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end task(50) task(200) task(50)
timeline | |-<⋯ +200 ⋯>-|-----------[++++]------[+++++++++++++++++++++++]------[++++]-
time (ms) | 0 200 300 400 650
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(700);
// TESTING TODO: are we testing enough of first idle time?
(0, vitest_1.expect)(report.additionalDurations.completeTillInteractive).toBe(500);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('Multiple heavy clusters, FirstCPUIdle updated to end of last cluster', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(200)}-----${(0, makeTimeline_1.LongTask)(200)}-----${(0, makeTimeline_1.LongTask)(200)}-----${makeTimeline_1.Check}
Time: ${0} ${200} ${300} ${900} ${1_500} ${3_800}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end task(200) task(200) task(200)
timeline | |------------|------[+++++++++++]-<⋯ +400 ⋯>--[+++++++++++]-<⋯ +400 ⋯>-[+++++++++++]
time (ms) | 0 200 300 900 1500
`);
const lastLongTask = spans.at(-2);
const expectedResult = lastLongTask.startTime.now + lastLongTask.duration;
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(expectedResult);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('Checking before the quiet window has passed - no long tasks processed, FirstCPUIdle not found', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${makeTimeline_1.Check}
Time: ${0} ${200} ${2_400}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 0 200
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(200);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('completes the trace with one heavy cluster followed by two light clusters, value is after 1st heavy cluster', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(200)}-----${(0, makeTimeline_1.LongTask)(100)}-----${(0, makeTimeline_1.LongTask)(200)}-----${(0, makeTimeline_1.LongTask)(200)}-----${makeTimeline_1.Check}
Time: ${0} ${200} ${300} ${600} ${1_700} ${2_900} ${4_650}
}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end task(200) task(100)
timeline | |-<⋯ +200 ⋯>-|-----------[+++++++++++++++++++++++]------------[++++++++++]-
time (ms) | 0 200 300 600
`);
const lastHeavyClusterLongTask = spans.at(3);
const expectedResult = lastHeavyClusterLongTask.startTime.now + lastHeavyClusterLongTask.duration;
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(expectedResult);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('completes the trace with continuous heavy clusters', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${(0, makeTimeline_1.LongTask)(300)}-----${makeTimeline_1.Check}
Time: ${0} ${200} ${550} ${900} ${1_250} ${1_600} ${1_950} ${2_300} ${2_650} ${3_000} ${3_350} ${3_700} ${4_050} ${4_400} ${4_750} ${5_100} ${7_450}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | end task(300) task(300) task(300) task(300) task(300) task(300) task(300)
events | start task(300) task(300) task(300) task(300) task(300) task(300) task(300)
timeline | |-|-----[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-[++]-
time (ms) | 0 200 550 900 1250 1600 1950 2300 2650 3000 3350 3700 4050 4400 4750 5100
`);
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(5_400);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('completes the trace with a light cluster followed by a heavy cluster a second later, FirstCPUIdle updated', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}-----${(0, makeTimeline_1.Render)('end', 0)}-----${(0, makeTimeline_1.LongTask)(50)}----------${(0, makeTimeline_1.LongTask)(50)}----------${(0, makeTimeline_1.LongTask)(50)}--------${(0, makeTimeline_1.LongTask)(50)}---------${(0, makeTimeline_1.LongTask)(200)}-------${(0, makeTimeline_1.LongTask)(200)}--------${makeTimeline_1.Check}
Time: ${0} ${200} ${300} ${350} ${1_450} ${1_550} ${1_650} ${1_900} ${4_150}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | task(50) task(50)
events | start end task(50) task(50) task(200) task(200)
timeline | |------------|------[+]--[+]-<⋯ +1050 ⋯>[+]--[+]---[+++++++++++]---[+++++++++++]-
time (ms) | 0 200 300 350 1450 1550 1650 1900
`);
const lastLongTask = spans.at(-2);
const expectedResult = lastLongTask.startTime.now + lastLongTask.duration;
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(expectedResult);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
(0, vitest_1.it)('completes the trace with a long task overlapping FMP, FirstCPUIdle after the long task', () => {
const traceManager = new TraceManager_1.TraceManager({
relationSchemas: { ticket: { ticketId: String } },
reportFn,
generateId,
reportErrorFn,
});
const tracer = traceManager.createTracer({
name: 'ticket.operation',
type: 'operation',
relationSchemaName: 'ticket',
requiredSpans: [{ name: 'end' }],
captureInteractive: cpuIdleProcessorOptions,
variants: {
cold_boot: {
timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION,
},
},
});
tracer.start({
relatedTo: {
ticketId: '1',
},
variant: 'cold_boot',
});
// prettier-ignore
const { spans } = (0, makeTimeline_1.getSpansFromTimeline) `
Events: ${(0, makeTimeline_1.Render)('start', 0)}----------${(0, makeTimeline_1.LongTask)(110, { start: 150 })}----${(0, makeTimeline_1.Render)('end', 0)}-----${makeTimeline_1.Check}
Time: ${0} ${150} ${200} ${2_500}
`;
(0, processSpans_1.processSpans)(spans, traceManager);
(0, vitest_1.expect)(reportFn).toHaveBeenCalled();
const report = reportFn.mock.calls[0][0];
(0, vitest_1.expect)(report.entries.map((spanAndAnnotation) => spanAndAnnotation.span.performanceEntry)).toMatchInlineSnapshot(`
events | start end
timeline | |-<⋯ +200 ⋯>-|
time (ms) | 0 200
`);
const lastLongTask = spans.at(-2);
const expectedResult = lastLongTask.startTime.now + lastLongTask.duration;
(0, vitest_1.expect)(report.name).toBe('ticket.operation');
(0, vitest_1.expect)(report.duration).toBe(200);
(0, vitest_1.expect)(report.additionalDurations.startTillInteractive).toBe(expectedResult);
(0, vitest_1.expect)(report.status).toBe('ok');
(0, vitest_1.expect)(report.interruptionReason).toBeUndefined();
});
});
//# sourceMappingURL=TraceManagerWithCaptureInteractive.test.js.map