@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
335 lines • 15.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const convertToRum_1 = require("./convertToRum");
const recordingComputeUtils_1 = require("./recordingComputeUtils");
const createMockFactory_1 = require("./testUtility/createMockFactory");
const baseDefinitionFixture = {
name: 'test-trace',
relationSchemaName: 'global',
relationSchema: { global: {} },
requiredSpans: [() => true],
computedSpanDefinitions: {},
computedValueDefinitions: {},
variants: {
origin: { timeout: 45_000 },
},
};
(0, vitest_1.describe)('recordingComputeUtils', () => {
(0, vitest_1.describe)('error status propagation', () => {
(0, vitest_1.it)('should mark trace as error if any non-suppressed span has error status', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: baseDefinitionFixture,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
status: 'error',
name: 'error-span',
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, { status: 'ok', name: 'ok-span' }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, { transitionFromState: 'active' });
(0, vitest_1.expect)(recording.status).toBe('error');
(0, vitest_1.expect)(recording.additionalDurations.startTillInteractive).toBeNull();
(0, vitest_1.expect)(recording.additionalDurations.completeTillInteractive).toBeNull();
(0, vitest_1.expect)(recording.additionalDurations.startTillRequirementsMet).toBeNull();
});
(0, vitest_1.it)('should not mark trace as error if all error spans are suppressed', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: {
...baseDefinitionFixture,
suppressErrorStatusPropagationOnSpans: [
({ span }) => span.name === 'suppressed-error-span',
],
},
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
status: 'error',
name: 'suppressed-error-span',
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, { status: 'ok', name: 'ok-span' }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, { transitionFromState: 'active' });
(0, vitest_1.expect)(recording.status).toBe('ok');
(0, vitest_1.expect)(recording.additionalDurations.startTillInteractive).toBeNull();
});
(0, vitest_1.it)('should mark trace as error if any error span is not suppressed', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: {
...baseDefinitionFixture,
suppressErrorStatusPropagationOnSpans: [
({ span }) => span.name === 'suppressed-error-span',
],
},
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
status: 'error',
name: 'suppressed-error-span',
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, {
status: 'error',
name: 'non-suppressed-error-span',
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(300, { status: 'ok', name: 'ok-span' }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, { transitionFromState: 'active' });
(0, vitest_1.expect)(recording.status).toBe('error');
(0, vitest_1.expect)(recording.additionalDurations.startTillInteractive).toBeNull();
});
(0, vitest_1.it)('should prioritize interrupted status over error status', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: baseDefinitionFixture,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
status: 'error',
name: 'error-span',
}),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, {
transitionFromState: 'active',
interruptionReason: 'timeout',
});
(0, vitest_1.expect)(recording.status).toBe('interrupted');
(0, vitest_1.expect)(recording.additionalDurations.startTillInteractive).toBeNull();
});
});
(0, vitest_1.describe)('getComputedSpans', () => {
const baseDefinition = {
...baseDefinitionFixture,
computedSpanDefinitions: {
'test-computed-span': {
startSpan: ({ span }) => span.name === 'start-span',
endSpan: ({ span }) => span.name === 'end-span',
},
},
};
(0, vitest_1.it)('should compute duration and startOffset correctly', () => {
const result = (0, recordingComputeUtils_1.getComputedSpans)({
definition: baseDefinition,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
name: 'start-span',
duration: 50,
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, {
name: 'end-span',
duration: 50,
}),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
});
(0, vitest_1.expect)(result['test-computed-span']).toEqual({
duration: 150, // (200 + 50) - 100
startOffset: 100,
});
});
(0, vitest_1.it)('should handle operation-start and operation-end special matchers', () => {
const definition = {
...baseDefinition,
computedSpanDefinitions: {
'operation-span': {
startSpan: 'operation-start',
endSpan: 'operation-end',
},
},
};
const markedCompleteSpan = (0, createMockFactory_1.createMockSpanAndAnnotation)(200, {
name: 'end-span',
});
markedCompleteSpan.annotation.markedComplete = true;
const result = (0, recordingComputeUtils_1.getComputedSpans)({
definition,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }),
markedCompleteSpan,
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
});
(0, vitest_1.expect)(result['operation-span']).toBeDefined();
});
});
(0, vitest_1.describe)('getComputedValues', () => {
const baseDefinition = {
...baseDefinitionFixture,
computedValueDefinitions: {
'error-count': {
matches: [({ span }) => span.status === 'error'],
computeValueFromMatches: (matches) => matches.length,
},
},
};
(0, vitest_1.it)('should compute values based on matching spans', () => {
const result = (0, recordingComputeUtils_1.getComputedValues)({
definition: baseDefinition,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, { status: 'error' }),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, { status: 'error' }),
(0, createMockFactory_1.createMockSpanAndAnnotation)(300, { status: 'ok' }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
});
(0, vitest_1.expect)(result['error-count']).toBe(2);
});
(0, vitest_1.it)('should handle multiple matches in computeValueFromMatches', () => {
const definition = {
...baseDefinition,
computedValueDefinitions: {
'status-counts': {
matches: [
({ span }) => span.status === 'error',
({ span }) => span.status === 'ok',
],
computeValueFromMatches: (errors, oks) => errors.length + oks.length,
},
},
};
const result = (0, recordingComputeUtils_1.getComputedValues)({
definition,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, { status: 'error' }),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, { status: 'ok' }),
(0, createMockFactory_1.createMockSpanAndAnnotation)(300, { status: 'error' }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
});
(0, vitest_1.expect)(result['status-counts']).toEqual(3);
});
});
(0, vitest_1.describe)('getSpanSummaryAttributes', () => {
(0, vitest_1.it)('should merge attributes from spans with the same name', () => {
const result = (0, convertToRum_1.getSpanSummaryAttributes)([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
name: 'test-span',
attributes: { first: true },
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, {
name: 'test-span',
attributes: { second: true },
}),
]);
(0, vitest_1.expect)(result['test-span']).toEqual({
first: true,
second: true,
});
});
});
(0, vitest_1.describe)('computedRenderBeaconSpans', () => {
(0, vitest_1.it)('should compute render beacon metrics correctly', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: baseDefinitionFixture,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
name: 'test-component',
type: 'component-render',
relatedTo: {},
duration: 50,
isIdle: true,
renderCount: 1,
renderedOutput: 'loading',
}),
(0, createMockFactory_1.createMockSpanAndAnnotation)(200, {
name: 'test-component',
type: 'component-render',
relatedTo: {},
duration: 50,
isIdle: true,
renderCount: 2,
renderedOutput: 'content',
}, { occurrence: 2 }),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, { transitionFromState: 'active' });
(0, vitest_1.expect)(recording.computedRenderBeaconSpans['test-component']).toEqual({
startOffset: 100,
firstRenderTillContent: 150,
firstRenderTillLoading: 50,
firstRenderTillData: 100,
renderCount: 2,
sumOfRenderDurations: 100,
});
});
});
(0, vitest_1.describe)('variant property', () => {
(0, vitest_1.it)('should include the variant in the recording', () => {
const recording = (0, recordingComputeUtils_1.createTraceRecording)({
definition: baseDefinitionFixture,
recordedItems: new Set([
(0, createMockFactory_1.createMockSpanAndAnnotation)(100, {
status: 'ok',
name: 'test-span',
}),
]),
input: {
id: 'test',
startTime: (0, createMockFactory_1.createTimestamp)(0),
relatedTo: {},
variant: 'origin',
},
recordedItemsByLabel: {},
}, { transitionFromState: 'active' });
// Verify the variant is included in the recording
(0, vitest_1.expect)(recording.variant).toBe('origin');
});
});
});
//# sourceMappingURL=recordingComputeUtils.test.js.map
;