UNPKG

autotel

Version:
289 lines (287 loc) 8.76 kB
export { assertEventTracked, assertOutcomeTracked, createEventCollector } from './chunk-BZHG5IZ4.js'; import './chunk-55ER2KD5.js'; import { configure } from './chunk-J5QENANM.js'; import './chunk-HA2WBOGQ.js'; import './chunk-DGUM43GV.js'; import { SpanStatusCode, trace, context } from '@opentelemetry/api'; function createTraceCollector() { const spans = []; const createMockSpan = (name, startTime) => { const spanData = { name, startTime, attributes: {}, status: { code: SpanStatusCode.OK } }; const spanContextData = { traceId: "1234567890abcdef1234567890abcdef", // 128-bit trace ID (32 hex chars) spanId: "1234567890abcdef", // 64-bit span ID (16 hex chars) traceFlags: 1, isRemote: false }; const mockSpan = { spanContext: () => spanContextData, setStatus(status) { spanData.status = status; return this; }, setAttributes(attributes) { spanData.attributes = { ...spanData.attributes, ...attributes }; return this; }, setAttribute(key, value) { spanData.attributes = spanData.attributes || {}; spanData.attributes[key] = value; return this; }, addEvent(name2, attributesOrStartTime, startTime2) { return this; }, addLink(link) { return this; }, addLinks(links) { return this; }, updateName(newName) { spanData.name = newName; return this; }, isRecording() { return true; }, recordException(exception, time) { }, end(endTimeArg) { const endTime = performance.now(); spans.push({ name: spanData.name, status: spanData.status, attributes: spanData.attributes || {}, startTime: spanData.startTime, endTime, duration: endTime - spanData.startTime }); } }; return mockSpan; }; const mockTracer = { startSpan(name, options, ctx) { const startTime = performance.now(); return createMockSpan(name, startTime); }, startActiveSpan(name, optionsOrFn, contextOrFn, fn) { const callback = (() => { if (typeof optionsOrFn === "function") { return optionsOrFn; } if (typeof contextOrFn === "function") { return contextOrFn; } if (fn) { return fn; } throw new Error("startActiveSpan requires a callback"); })(); const startTime = performance.now(); const mockSpan = createMockSpan(name, startTime); const ctx = trace.setSpan(context.active(), mockSpan); return context.with(ctx, () => callback(mockSpan)); } }; configure({ tracer: mockTracer }); return { getSpans() { return [...spans]; }, getSpansByName(name) { return spans.filter((span) => span.name === name); }, getSpansByAttributes(attributes) { return spans.filter((span) => { return Object.entries(attributes).every( ([key, value]) => span.attributes[key] === value ); }); }, clear() { spans.length = 0; }, recordSpan(span) { spans.push(span); } }; } function assertTraceCreated(collector, operationName, options) { const spans = collector.getSpansByName(operationName); if (options?.minCount !== void 0 && spans.length < options.minCount) { throw new Error( `Expected at least ${options.minCount} traces for ${operationName}, got ${spans.length}` ); } if (options?.maxCount !== void 0 && spans.length > options.maxCount) { throw new Error( `Expected at most ${options.maxCount} traces for ${operationName}, got ${spans.length}` ); } if (spans.length === 0) { throw new Error(`No traces found for operation: ${operationName}`); } if (options?.status !== void 0) { const matchingSpans = spans.filter( (span) => span.status.code === options.status ); if (matchingSpans.length === 0) { throw new Error( `No traces with status ${options.status} found for ${operationName}` ); } } if (options?.attributes) { const matchingSpans = spans.filter((span) => { return Object.entries(options.attributes).every( ([key, value]) => span.attributes[key] === value ); }); if (matchingSpans.length === 0) { throw new Error( `No traces with attributes ${JSON.stringify(options.attributes)} found for ${operationName}` ); } } } function assertNoErrors(collector) { const errorSpans = collector.getSpans().filter((span) => span.status.code === SpanStatusCode.ERROR); if (errorSpans.length > 0) { const errorSummary = errorSpans.map((span) => `${span.name}: ${span.status.message}`).join("\n"); throw new Error(`Found ${errorSpans.length} error spans: ${errorSummary}`); } } function assertTraceSucceeded(collector, operationName) { assertTraceCreated(collector, operationName, { status: SpanStatusCode.OK }); } function assertTraceFailed(collector, operationName, errorMessage) { const spans = collector.getSpansByName(operationName); if (spans.length === 0) { throw new Error(`No traces found for operation: ${operationName}`); } const errorSpans = spans.filter( (span) => span.status.code === SpanStatusCode.ERROR ); if (errorSpans.length === 0) { throw new Error(`No error traces found for operation: ${operationName}`); } if (errorMessage) { const matchingSpans = errorSpans.filter( (span) => span.status.message === errorMessage ); if (matchingSpans.length === 0) { throw new Error( `No error traces with message "${errorMessage}" found for ${operationName}` ); } } } function createMockLogger() { const logs = []; const createLogMethod = (level) => { return (objOrMsg, msg) => { if (typeof objOrMsg === "string") { logs.push({ level, message: objOrMsg, extra: void 0 }); } else { logs.push({ level, message: msg || "", extra: objOrMsg }); } }; }; return { info: createLogMethod("info"), warn: createLogMethod("warn"), debug: createLogMethod("debug"), error(objOrMsg, msg) { if (typeof objOrMsg === "string") { logs.push({ level: "error", message: objOrMsg, extra: void 0, error: void 0 }); return; } const { err, ...rest } = objOrMsg; logs.push({ level: "error", message: msg || "", error: err instanceof Error ? err : void 0, extra: err !== void 0 && !(err instanceof Error) ? { err, ...rest } : rest }); }, getLogs() { return [...logs]; }, getLogsByLevel(level) { return logs.filter((log) => log.level === level); }, getLogsByMessage(message) { return logs.filter((log) => log.message.includes(message)); }, clear() { logs.length = 0; } }; } function assertNoErrorsLogged(logger) { const errorLogs = logger.getLogsByLevel("error"); if (errorLogs.length > 0) { const errorSummary = errorLogs.map( (log) => `${log.message}${log.error ? ": " + log.error.message : ""}` ).join("\n"); throw new Error(`Found ${errorLogs.length} error logs: ${errorSummary}`); } } async function waitForTrace(collector, operationName, timeoutMs = 5e3) { const startTime = Date.now(); while (Date.now() - startTime < timeoutMs) { const spans = collector.getSpansByName(operationName); if (spans.length > 0) { return; } await new Promise((resolve) => setTimeout(resolve, 10)); } throw new Error( `Timeout waiting for trace ${operationName} after ${timeoutMs}ms` ); } function getTraceDuration(collector, operationName) { const spans = collector.getSpansByName(operationName); if (spans.length === 0) { return void 0; } return spans[0]?.duration; } function assertTraceDuration(collector, operationName, maxDurationMs) { const duration = getTraceDuration(collector, operationName); if (duration === void 0) { throw new Error(`No trace found for operation: ${operationName}`); } if (duration > maxDurationMs) { throw new Error( `Operation ${operationName} took ${duration.toFixed(2)}ms, exceeding ${maxDurationMs}ms threshold` ); } } export { assertNoErrors, assertNoErrorsLogged, assertTraceCreated, assertTraceDuration, assertTraceFailed, assertTraceSucceeded, createMockLogger, createTraceCollector, getTraceDuration, waitForTrace }; //# sourceMappingURL=testing.js.map //# sourceMappingURL=testing.js.map