autotel-vitest 0.4.59 → 0.4.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -95,6 +95,7 @@ The fixture is `auto: true`, so every test gets a parent span automatically.
95
95
  - Span attributes: `test.name`, `test.file`, `test.suite`
96
96
  - If a test throws, the span is marked as error and records the exception
97
97
  - Any `trace()` / `span()` calls in the test flow become children of the active test span
98
+ - An `otel-trace` annotation on every test, holding the trace URL (from `OTEL_TRACE_URL_TEMPLATE`) or the raw trace id, so reporters — including the browser trace view's step list — link back to the trace
98
99
  - The test's spans on `task.meta.otelSpans`, which
99
100
  [executable-stories](https://github.com/jagreehal/executable-stories) renders
100
101
  as a trace waterfall in its report with no extra wiring
@@ -120,6 +121,10 @@ Reporter spans:
120
121
  - test span: `test:${name}`
121
122
  - suite span: `suite:${name}`
122
123
 
124
+ In browser mode, Vitest exposes a recorded Playwright trace to reporters as an
125
+ annotation attachment; the reporter copies its path onto the test span as
126
+ `test.trace.path`, so a failed span leads straight to the replay.
127
+
123
128
  ## Testing Utilities
124
129
 
125
130
  `autotel-vitest` re-exports helpers from `autotel/testing`:
package/dist/index.cjs CHANGED
@@ -74,7 +74,7 @@ function ensureCollector() {
74
74
  * // All trace()/span() calls become children of the test span
75
75
  * });
76
76
  */
77
- const test = vitest.test.extend({ _otelTestSpan: [async ({ task }, use) => {
77
+ const test = vitest.test.extend({ _otelTestSpan: [async ({ task, annotate }, use) => {
78
78
  ensureCollector();
79
79
  const span = (0, autotel.getTracer)(TRACER_NAME, TRACER_VERSION).startSpan(`test:${task.name}`, { attributes: {
80
80
  "test.name": task.name,
@@ -82,8 +82,13 @@ const test = vitest.test.extend({ _otelTestSpan: [async ({ task }, use) => {
82
82
  "test.suite": task.suite?.name ?? ""
83
83
  } });
84
84
  const ctx = autotel.otelTrace.setSpan(autotel.context.active(), span);
85
+ const entered = enterContext(ctx);
86
+ if (annotate) {
87
+ const traceId = span.spanContext().traceId;
88
+ await annotate((0, autotel.resolveTraceUrl)(void 0, traceId) ?? traceId, "otel-trace").catch(() => {});
89
+ }
85
90
  try {
86
- await (enterContext(ctx) ? use(span) : autotel.context.with(ctx, () => use(span)));
91
+ await (entered ? use(span) : autotel.context.with(ctx, () => use(span)));
87
92
  } catch (error) {
88
93
  span.setStatus({ code: autotel.SpanStatusCode.ERROR });
89
94
  span.recordException(error instanceof Error ? error : new Error(String(error)));
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test as test$1 } from "vitest";
2
- import { SpanStatusCode, context, enrichWithTraceContext, flush, getAutotelTracerProvider, getTraceContext, getTracer, isTracing, otelTrace, resolveTraceUrl } from "autotel";
2
+ import { SpanStatusCode, context, enrichWithTraceContext, flush, getAutotelTracerProvider, getTraceContext, getTracer, isTracing, otelTrace, resolveTraceUrl, resolveTraceUrl as resolveTraceUrl$1 } from "autotel";
3
3
  import { TestSpanCollector } from "autotel/test-span-collector";
4
4
  import { SimpleSpanProcessor } from "autotel/processors";
5
5
  import { assertNoErrors, assertTraceCreated, assertTraceDuration, assertTraceFailed, assertTraceSucceeded, createMockLogger, createTraceCollector, getTraceDuration, waitForTrace } from "autotel/testing";
@@ -73,7 +73,7 @@ function ensureCollector() {
73
73
  * // All trace()/span() calls become children of the test span
74
74
  * });
75
75
  */
76
- const test = test$1.extend({ _otelTestSpan: [async ({ task }, use) => {
76
+ const test = test$1.extend({ _otelTestSpan: [async ({ task, annotate }, use) => {
77
77
  ensureCollector();
78
78
  const span = getTracer(TRACER_NAME, TRACER_VERSION).startSpan(`test:${task.name}`, { attributes: {
79
79
  "test.name": task.name,
@@ -81,8 +81,13 @@ const test = test$1.extend({ _otelTestSpan: [async ({ task }, use) => {
81
81
  "test.suite": task.suite?.name ?? ""
82
82
  } });
83
83
  const ctx = otelTrace.setSpan(context.active(), span);
84
+ const entered = enterContext(ctx);
85
+ if (annotate) {
86
+ const traceId = span.spanContext().traceId;
87
+ await annotate(resolveTraceUrl$1(void 0, traceId) ?? traceId, "otel-trace").catch(() => {});
88
+ }
84
89
  try {
85
- await (enterContext(ctx) ? use(span) : context.with(ctx, () => use(span)));
90
+ await (entered ? use(span) : context.with(ctx, () => use(span)));
86
91
  } catch (error) {
87
92
  span.setStatus({ code: SpanStatusCode.ERROR });
88
93
  span.recordException(error instanceof Error ? error : new Error(String(error)));
package/dist/reporter.cjs CHANGED
@@ -35,6 +35,8 @@ var OtelReporter = class {
35
35
  onTestCaseResult(testCase) {
36
36
  const entry = this.testSpans.get(testCase.id);
37
37
  if (!entry) return;
38
+ const tracePath = testCase.annotations().find((annotation) => annotation.attachment?.path?.endsWith(".trace.zip"))?.attachment?.path;
39
+ if (tracePath) entry.span.setAttribute("test.trace.path", tracePath);
38
40
  const result = testCase.result();
39
41
  if (result.state === "failed") {
40
42
  entry.span.setStatus({ code: autotel.SpanStatusCode.ERROR });
package/dist/reporter.js CHANGED
@@ -31,6 +31,8 @@ var OtelReporter = class {
31
31
  onTestCaseResult(testCase) {
32
32
  const entry = this.testSpans.get(testCase.id);
33
33
  if (!entry) return;
34
+ const tracePath = testCase.annotations().find((annotation) => annotation.attachment?.path?.endsWith(".trace.zip"))?.attachment?.path;
35
+ if (tracePath) entry.span.setAttribute("test.trace.path", tracePath);
34
36
  const result = testCase.result();
35
37
  if (result.state === "failed") {
36
38
  entry.span.setStatus({ code: SpanStatusCode.ERROR });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-vitest",
3
- "version": "0.4.59",
3
+ "version": "0.4.60",
4
4
  "description": "Vitest fixture for OpenTelemetry: one span per test so all instrumented code is filterable by test run",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",