UNPKG

@zendesk/retrace

Version:

define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API

842 lines 39.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); const convertToRum_1 = require("./convertToRum"); const matchSpan_1 = require("./matchSpan"); 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', lastRelevantSpanAndAnnotation: undefined, transitionToState: 'complete', completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (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', lastRelevantSpanAndAnnotation: undefined, transitionToState: 'complete', completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (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', lastRelevantSpanAndAnnotation: undefined, transitionToState: 'complete', completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (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', transitionToState: 'interrupted', lastRelevantSpanAndAnnotation: undefined, }); (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: {}, }, { completeSpanAndAnnotation: markedCompleteSpan }); (0, vitest_1.expect)(result['operation-span']).toBeDefined(); }); (0, vitest_1.describe)('matchingIndex', () => { (0, vitest_1.it)('should select the correct start span using a positive matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span', matchingIndex: 1, // starts at 0th index }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span' }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(300, { name: 'start-span' }), // matching start span (0, createMockFactory_1.createMockSpanAndAnnotation)(400, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(500, { 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: 250, // (500 + 50) - 300 startOffset: 300, // should use the second start-span }); }); (0, vitest_1.it)('should select the correct start span using a negative matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span', matchingIndex: -3, }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span' }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), // starting span (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(300, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(500, { 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: 450, // (500 + 50) - 100 startOffset: 100, }); }); (0, vitest_1.it)('should select the correct end span using a positive matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span' }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span', matchingIndex: 2, }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(150, { name: 'span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(400, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(600, { // matching span name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(700, { 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: 550, // (600 + 50) - 100 startOffset: 100, }); }); (0, vitest_1.it)('should select the correct end span using a negative matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span' }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span', matchingIndex: -1, }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(400, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(600, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(700, { // matching span 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: 650, // (700 + 50) - 100 startOffset: 100, }); }); (0, vitest_1.it)('should not return any computed spans using a invalid matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span' }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span', matchingIndex: -100, }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(400, { // matching span name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(600, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(700, { name: 'end-span', duration: 50, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', }, recordedItemsByLabel: {}, }); (0, vitest_1.expect)(result).toEqual({}); }); (0, vitest_1.it)('should work with span definition objects containing matchingIndex', () => { const definition = { ...baseDefinitionFixture, computedSpanDefinitions: { 'test-computed-span': { startSpan: (0, matchSpan_1.fromDefinition)({ name: 'start-span', matchingIndex: 1, }), endSpan: (0, matchSpan_1.fromDefinition)({ name: 'end-span', matchingIndex: -1 }), }, }, }; const result = (0, recordingComputeUtils_1.getComputedSpans)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(300, { name: 'start-span' }), (0, createMockFactory_1.createMockSpanAndAnnotation)(400, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(500, { name: 'end-span', duration: 50, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(600, { 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: 450, // (600 + 50) - 200 startOffset: 200, // should use second start-span }); }); }); }); (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', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (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', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); // Verify the variant is included in the recording (0, vitest_1.expect)(recording.variant).toBe('origin'); }); }); (0, vitest_1.describe)('promoteSpanAttributesForTrace and attribute promotion', () => { const promotedAttributesTraceDefinition = { ...baseDefinitionFixture, promoteSpanAttributes: [ { span: { name: 'foo-span' }, attributes: ['foo', 'bar'], }, { span: { name: 'baz-span' }, attributes: ['baz'], }, ], }; (0, vitest_1.it)('should promote specified attributes from last matching spans to trace', () => { const recording = (0, recordingComputeUtils_1.createTraceRecording)({ definition: promotedAttributesTraceDefinition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'foo-span', attributes: { foo: 1, bar: 2, unused: 42 }, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'foo-span', attributes: { foo: 7, bar: 8 }, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(300, { name: 'baz-span', attributes: { baz: 'hello' }, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', }, recordedItemsByLabel: {}, }, { transitionFromState: 'active', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); // Should select last foo-span (timestamp 200) for foo/bar, and baz-span for baz (0, vitest_1.expect)(recording.attributes.foo).toBe(7); (0, vitest_1.expect)(recording.attributes.bar).toBe(8); (0, vitest_1.expect)(recording.attributes.baz).toBe('hello'); (0, vitest_1.expect)('unused' in recording.attributes).toBe(false); }); (0, vitest_1.it)('should promote specified attributes from last matching spans when there is an attribute name collision to trace', () => { const promotedAttributesTraceDefinitionWithOverrideAttributeNames = { ...baseDefinitionFixture, promoteSpanAttributes: [ { span: { name: 'foo-span' }, attributes: ['foo', 'bar'], }, { span: { name: 'baz-span' }, attributes: ['foo', 'bar'], }, ], }; const recording = (0, recordingComputeUtils_1.createTraceRecording)({ definition: promotedAttributesTraceDefinitionWithOverrideAttributeNames, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'foo-span', attributes: { foo: 7, bar: 8 }, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(300, { name: 'baz-span', // should replace the trace attributes from 'foo-span' attributes: { foo: 'hello', bar: 'world' }, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', }, recordedItemsByLabel: {}, }, { transitionFromState: 'active', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); // Should select attributes from baz-span (timestamp 300) (0, vitest_1.expect)(recording.attributes.foo).toBe('hello'); (0, vitest_1.expect)(recording.attributes.bar).toBe('world'); (0, vitest_1.expect)('unused' in recording.attributes).toBe(false); }); (0, vitest_1.it)('should not set unset promoted attributes if not found', () => { const partialAttrDefinition = { ...baseDefinitionFixture, promoteSpanAttributes: [ { span: { name: 'foo-span' }, attributes: ['foo', 'bar'], }, { span: { name: 'no-match' }, attributes: ['baz', 'shouldNotBeSet'], }, ], }; const recording = (0, recordingComputeUtils_1.createTraceRecording)({ definition: partialAttrDefinition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(111, { name: 'foo-span', attributes: { foo: 99 }, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', }, recordedItemsByLabel: {}, }, { transitionFromState: 'active', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (0, vitest_1.expect)(recording.attributes.foo).toBe(99); (0, vitest_1.expect)('bar' in recording.attributes).toBe(false); (0, vitest_1.expect)('baz' in recording.attributes).toBe(false); (0, vitest_1.expect)('shouldNotBeSet' in recording.attributes).toBe(false); }); (0, vitest_1.it)('should allow attribute promotion on interruption', () => { const recording = (0, recordingComputeUtils_1.createTraceRecording)({ definition: promotedAttributesTraceDefinition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'foo-span', attributes: { foo: 'z' }, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'baz-span', attributes: { baz: 10 }, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', }, recordedItemsByLabel: {}, }, { transitionFromState: 'active', transitionToState: 'interrupted', interruptionReason: 'timeout', lastRelevantSpanAndAnnotation: undefined, }); (0, vitest_1.expect)(recording.attributes.foo).toBe('z'); (0, vitest_1.expect)(recording.attributes.baz).toBe(10); }); (0, vitest_1.it)('should allow original trace attributes to take precedence over promoted', () => { const definition = { ...promotedAttributesTraceDefinition, }; const recording = (0, recordingComputeUtils_1.createTraceRecording)({ definition, recordedItems: new Set([ (0, createMockFactory_1.createMockSpanAndAnnotation)(100, { name: 'foo-span', attributes: { foo: 'notUsed' }, }), (0, createMockFactory_1.createMockSpanAndAnnotation)(200, { name: 'baz-span', attributes: { baz: 111 }, }), ]), input: { id: 'test', startTime: (0, createMockFactory_1.createTimestamp)(0), relatedTo: {}, variant: 'origin', attributes: { foo: 'owned', baz: 'shouldWin' }, }, recordedItemsByLabel: {}, }, { transitionFromState: 'active', transitionToState: 'complete', lastRelevantSpanAndAnnotation: undefined, completeSpanAndAnnotation: undefined, cpuIdleSpanAndAnnotation: undefined, lastRequiredSpanAndAnnotation: undefined, }); (0, vitest_1.expect)(recording.attributes.foo).toBe('owned'); (0, vitest_1.expect)(recording.attributes.baz).toBe('shouldWin'); }); }); }); //# sourceMappingURL=recordingComputeUtils.test.js.map