UNPKG

@zendesk/retrace

Version:

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

585 lines 32.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); const matchSpan_1 = require("./matchSpan"); // Mock data setup const mockRelations = { ticketId: '123', }; const createMockSpan = (overrides = {}) => ({ type: 'measure', id: '123', name: 'testEntry', startTime: { now: Date.now(), epoch: Date.now(), }, relatedTo: mockRelations, attributes: { attr1: 'value1', attr2: 2, }, duration: 100, status: 'ok', getParentSpan: () => undefined, ...overrides, }); const createMockAnnotation = (overrides = {}) => ({ id: '', occurrence: 1, operationRelativeEndTime: 0, operationRelativeStartTime: 0, recordedInState: 'active', labels: [], ...overrides, }); const createMockSpanAndAnnotation = (spanOverrides = {}, annotationOverrides = {}) => ({ span: createMockSpan(spanOverrides), annotation: createMockAnnotation(annotationOverrides), }); const mockContext = { input: { id: '123', relatedTo: mockRelations, startTime: { now: Date.now(), epoch: Date.now(), }, variant: 'origin', }, definition: { name: 'test', type: 'operation', relationSchemaName: 'ticket', relationSchema: { ticketId: String }, requiredSpans: [() => true], computedSpanDefinitions: {}, computedValueDefinitions: {}, variants: { origin: { timeout: 10_000 }, }, }, recordedItemsByLabel: {}, recordedItems: new Map(), }; (0, vitest_1.describe)('findMatchingSpan', () => { (0, vitest_1.describe)('basic functionality', () => { (0, vitest_1.it)('should return undefined for empty array', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const result = (0, matchSpan_1.findMatchingSpan)(matcher, [], mockContext); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should return the first matching span', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'nonMatch' }), createMockSpanAndAnnotation({ name: 'testEntry' }), createMockSpanAndAnnotation({ name: 'testEntry' }), ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result).toBe(spanAndAnnotations[1]); }); (0, vitest_1.it)('should return undefined when no match is found', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'nonExistent' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry1' }), createMockSpanAndAnnotation({ name: 'testEntry2' }), ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should work with complex matchers', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', type: 'element', status: 'ok', }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', type: 'element', status: 'error', }), createMockSpanAndAnnotation({ name: 'testEntry', type: 'mark', status: 'ok', }), createMockSpanAndAnnotation({ name: 'testEntry', type: 'element', status: 'ok', }), ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result).toBe(spanAndAnnotations[2]); }); }); (0, vitest_1.describe)('nthMatch functionality', () => { const createTestData = () => [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span2' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span5' }), ]; (0, vitest_1.it)('should return first match when nthMatch is undefined', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span1'); }); (0, vitest_1.it)('should return first match when nthMatch is 0', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 0 }); (0, vitest_1.expect)(result?.span.id).toBe('span1'); }); (0, vitest_1.it)('should return second match when nthMatch is 1', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 1 }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should return third match when nthMatch is 2', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 2 }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); }); (0, vitest_1.it)('should return undefined when nthMatch exceeds available matches', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 5 }); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should return last match when nthMatch is -1', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -1 }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); }); (0, vitest_1.it)('should return second-to-last match when nthMatch is -2', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -2 }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should return first match when nthMatch is -3', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -3 }); (0, vitest_1.expect)(result?.span.id).toBe('span1'); }); (0, vitest_1.it)('should return undefined when negative nthMatch exceeds available matches', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -5 }); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should override matcher nthMatch with config nthMatch', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); matcher.nthMatch = 0; // Set matcher to return first match const spanAndAnnotations = createTestData(); // Override with config to return second match const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 1 }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); }); (0, vitest_1.describe)('lowestIndexToConsider functionality', () => { const createTestData = () => [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), ]; (0, vitest_1.it)('should start from index 0 by default', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span1'); }); (0, vitest_1.it)('should start from specified lowestIndexToConsider', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 2 }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should return undefined when lowestIndexToConsider is beyond array length', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 10 }); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should work with lowestIndexToConsider and nthMatch together', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); // Start from index 1, get second match (which would be span4) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 1, nthMatch: 1, }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should override matcher lowestIndexToConsider with config lowestIndexToConsider', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); matcher.lowestIndexToConsider = 0; const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 2 }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); }); (0, vitest_1.describe)('highestIndexToConsider functionality', () => { const createTestData = () => [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), ]; (0, vitest_1.it)('should search through entire array by default', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -1 }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); // Last match in entire array }); (0, vitest_1.it)('should limit search to highestIndexToConsider', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); // Only search through first 2 elements (indices 0-1) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { highestIndexToConsider: 1, nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span2'); // Last match in limited range }); (0, vitest_1.it)('should handle highestIndexToConsider beyond array length', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { highestIndexToConsider: 100, nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); // Should not exceed actual array length }); (0, vitest_1.it)('should work with lowestIndexToConsider and highestIndexToConsider together', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); // Search only middle elements (indices 1-2) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 1, highestIndexToConsider: 2, }); (0, vitest_1.expect)(result?.span.id).toBe('span2'); // First match in range }); (0, vitest_1.it)('should return undefined when lowestIndexToConsider > highestIndexToConsider', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 3, highestIndexToConsider: 1, }); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should override matcher highestIndexToConsider with config highestIndexToConsider', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); matcher.highestIndexToConsider = 3; const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { highestIndexToConsider: 1, nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span2'); }); }); (0, vitest_1.describe)('complex scenarios', () => { (0, vitest_1.it)('should handle all config options together with positive nthMatch', () => { const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), // index 0 createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span2' }), // index 1 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), // index 2 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), // index 3 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span5' }), // index 4 createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span6' }), // index 5 ]; const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); // Search from index 2 to 4, get second match (should be span5) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 2, highestIndexToConsider: 4, nthMatch: 1, }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); }); (0, vitest_1.it)('should handle all config options together with negative nthMatch', () => { const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), // index 0 createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span2' }), // index 1 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), // index 2 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), // index 3 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span5' }), // index 4 createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span6' }), // index 5 ]; const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); // Search from index 2 to 4, get last match (should be span5) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 2, highestIndexToConsider: 4, nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span5'); }); (0, vitest_1.it)('should handle single element arrays correctly', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), ]; // Test various nthMatch values (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 0, })?.span.id).toBe('span1'); (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -1, })?.span.id).toBe('span1'); (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 1, })).toBeUndefined(); (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -2, })).toBeUndefined(); }); (0, vitest_1.it)('should handle edge case where lowestIndexToConsider equals highestIndexToConsider', () => { const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span3' }), ]; const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 1, highestIndexToConsider: 1, }); (0, vitest_1.expect)(result?.span.id).toBe('span2'); }); (0, vitest_1.it)('should handle matcher with existing tags', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); matcher.nthMatch = 1; matcher.lowestIndexToConsider = 1; matcher.highestIndexToConsider = 3; const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), // index 0 - excluded by lowestIndexToConsider createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), // index 1 - first match in range createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), // index 2 - second match in range createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), // index 3 - third match in range createMockSpanAndAnnotation({ name: 'testEntry', id: 'span5' }), // index 4 - excluded by highestIndexToConsider ]; // Should use matcher's settings (second match in range 1-3 = span3) const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); }); (0, vitest_1.describe)('edge cases and error conditions', () => { (0, vitest_1.it)('should handle matcher that always returns false', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'nonExistent' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result).toBeUndefined(); }); (0, vitest_1.it)('should handle matcher that always returns true', () => { const matcher = () => true; const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry1', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry2', id: 'span2' }), ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span1'); }); (0, vitest_1.it)('should handle zero-based indices correctly', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), ]; // Test boundary conditions (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 0, })?.span.id).toBe('span1'); (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { highestIndexToConsider: 0, })?.span.id).toBe('span1'); (0, vitest_1.expect)((0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { lowestIndexToConsider: 0, highestIndexToConsider: 0, })?.span.id).toBe('span1'); }); (0, vitest_1.it)('should handle array bounds correctly', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry' }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span2' }), ]; // Test with highestIndexToConsider beyond array length const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { highestIndexToConsider: 100, nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span2'); }); }); (0, vitest_1.describe)('performance and iteration behavior', () => { (0, vitest_1.it)('should iterate from start to end for positive indices', () => { const callOrder = []; const matcher = (spanAndAnnotation) => { callOrder.push(spanAndAnnotation.span.id); return spanAndAnnotation.span.name === 'target'; }; const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'span1', id: 'span1' }), createMockSpanAndAnnotation({ name: 'span2', id: 'span2' }), createMockSpanAndAnnotation({ name: 'target', id: 'span3' }), createMockSpanAndAnnotation({ name: 'span4', id: 'span4' }), ]; (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(callOrder).toEqual(['span1', 'span2', 'span3']); }); (0, vitest_1.it)('should iterate from end to start for negative indices', () => { const callOrder = []; const matcher = (spanAndAnnotation) => { callOrder.push(spanAndAnnotation.span.id); return spanAndAnnotation.span.name === 'target'; }; const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'span1', id: 'span1' }), createMockSpanAndAnnotation({ name: 'target', id: 'span2' }), createMockSpanAndAnnotation({ name: 'span3', id: 'span3' }), createMockSpanAndAnnotation({ name: 'span4', id: 'span4' }), ]; (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -1, }); (0, vitest_1.expect)(callOrder).toEqual(['span4', 'span3', 'span2']); }); (0, vitest_1.it)('should stop early when target nthMatch is found for positive indices', () => { const callOrder = []; const matcher = (spanAndAnnotation) => { callOrder.push(spanAndAnnotation.span.id); return spanAndAnnotation.span.name === 'target'; }; const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'target', id: 'span1' }), createMockSpanAndAnnotation({ name: 'target', id: 'span2' }), createMockSpanAndAnnotation({ name: 'target', id: 'span3' }), createMockSpanAndAnnotation({ name: 'target', id: 'span4' }), ]; // Should stop after finding the second match (index 1) (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 1, }); (0, vitest_1.expect)(callOrder).toEqual(['span1', 'span2']); }); }); (0, vitest_1.describe)('matcher tags from fromDefinition', () => { const createTestData = () => [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span2' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span5' }), ]; (0, vitest_1.it)('should use nthMatch from fromDefinition', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', nthMatch: 1, }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should use negative nthMatch from fromDefinition', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', nthMatch: -1, }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span4'); }); (0, vitest_1.it)('should use lowestIndexToConsider from fromDefinition', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', lowestIndexToConsider: 2, }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span3'); }); (0, vitest_1.it)('should use highestIndexToConsider from fromDefinition and nthMatch from config', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', highestIndexToConsider: 2, }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: -1, }); (0, vitest_1.expect)(result?.span.id).toBe('span3'); // Last match within highestIndexToConsider range (indices 0-2) }); (0, vitest_1.it)('should use multiple tags from fromDefinition together', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', lowestIndexToConsider: 1, highestIndexToConsider: 3, nthMatch: 1, }); const spanAndAnnotations = [ createMockSpanAndAnnotation({ name: 'testEntry', id: 'span1' }), // index 0 - excluded by lowestIndexToConsider createMockSpanAndAnnotation({ name: 'nonMatch', id: 'span2' }), // index 1 createMockSpanAndAnnotation({ name: 'testEntry', id: 'span3' }), // index 2 - first match in range createMockSpanAndAnnotation({ name: 'testEntry', id: 'span4' }), // index 3 - second match in range createMockSpanAndAnnotation({ name: 'testEntry', id: 'span5' }), // index 4 - excluded by highestIndexToConsider ]; const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span4'); // Second match in the range }); (0, vitest_1.it)('should override fromDefinition tags with config parameter', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', nthMatch: 0, lowestIndexToConsider: 0, highestIndexToConsider: 4, }); const spanAndAnnotations = createTestData(); // Override with different config const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext, { nthMatch: 1, lowestIndexToConsider: 2, highestIndexToConsider: 3, }); (0, vitest_1.expect)(result?.span.id).toBe('span4'); // Should use config override, not fromDefinition }); (0, vitest_1.it)('should handle negative nthMatch with range from fromDefinition', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', lowestIndexToConsider: 0, highestIndexToConsider: 2, nthMatch: -1, }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result?.span.id).toBe('span3'); // Last match within range [0, 2] }); (0, vitest_1.it)('should return undefined when fromDefinition nthMatch exceeds matches in range', () => { const matcher = (0, matchSpan_1.fromDefinition)({ name: 'testEntry', lowestIndexToConsider: 2, highestIndexToConsider: 3, nthMatch: 5, // Only 2 matches in range, requesting 6th match }); const spanAndAnnotations = createTestData(); const result = (0, matchSpan_1.findMatchingSpan)(matcher, spanAndAnnotations, mockContext); (0, vitest_1.expect)(result).toBeUndefined(); }); }); }); //# sourceMappingURL=findMatchingSpan.test.js.map