autotel-tanstack 1.13.5 → 1.13.7
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/dist/browser/index.js +1 -1
- package/dist/browser/testing.js +1 -1
- package/dist/{chunk-ZJTHTWHJ.js → chunk-YQYYPJCK.js} +8 -5
- package/dist/chunk-YQYYPJCK.js.map +1 -0
- package/dist/testing.d.ts +39 -5
- package/dist/testing.js +11 -3
- package/dist/testing.js.map +1 -1
- package/package.json +13 -13
- package/src/browser/testing.ts +32 -10
- package/src/testing.test.ts +20 -2
- package/src/testing.ts +52 -6
- package/dist/chunk-ZJTHTWHJ.js.map +0 -1
package/dist/browser/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { createTracedServerFnFactory, traceServerFn } from '../chunk-CSFIPJC2.js
|
|
|
6
6
|
export { createTracedRoute, traceBeforeLoad, traceLoader } from '../chunk-MNP65ZX7.js';
|
|
7
7
|
export { createTracedHeaders, extractContextFromRequest, getActiveContext, getCurrentSpanId, getCurrentTraceId, getTraceParent, getTraceState, injectContextToHeaders, runInContext } from '../chunk-DTZCOB4W.js';
|
|
8
8
|
export { wrapStartHandler } from '../chunk-V3RO5N2M.js';
|
|
9
|
-
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector } from '../chunk-
|
|
9
|
+
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector } from '../chunk-YQYYPJCK.js';
|
|
10
10
|
export { debugHeadersMiddleware } from '../chunk-JXO7H6KO.js';
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
package/dist/browser/testing.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector, createTestSpansHandlers } from '../chunk-
|
|
1
|
+
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector, createTestSpansHandlers, createTestSpansRoute } from '../chunk-YQYYPJCK.js';
|
|
2
2
|
//# sourceMappingURL=testing.js.map
|
|
3
3
|
//# sourceMappingURL=testing.js.map
|
|
@@ -12,15 +12,18 @@ function assertSpanCreated(collector, name) {
|
|
|
12
12
|
}
|
|
13
13
|
function assertSpanHasAttribute(collector, name, key, value) {
|
|
14
14
|
}
|
|
15
|
+
function createTestSpansRoute(createFileRoute, path) {
|
|
16
|
+
throw new Error("createTestSpansRoute is server-only");
|
|
17
|
+
}
|
|
15
18
|
function createTestSpansHandlers() {
|
|
16
19
|
return {
|
|
17
|
-
GET(
|
|
20
|
+
GET(input) {
|
|
18
21
|
return Response.json(
|
|
19
22
|
{ error: "createTestSpansHandlers is server-only" },
|
|
20
23
|
{ status: 404 }
|
|
21
24
|
);
|
|
22
25
|
},
|
|
23
|
-
DELETE(
|
|
26
|
+
DELETE(input) {
|
|
24
27
|
return Response.json(
|
|
25
28
|
{ error: "createTestSpansHandlers is server-only" },
|
|
26
29
|
{ status: 404 }
|
|
@@ -29,6 +32,6 @@ function createTestSpansHandlers() {
|
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector, createTestSpansHandlers };
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
34
|
-
//# sourceMappingURL=chunk-
|
|
35
|
+
export { assertSpanCreated, assertSpanHasAttribute, createTestCollector, createTestSpansHandlers, createTestSpansRoute };
|
|
36
|
+
//# sourceMappingURL=chunk-YQYYPJCK.js.map
|
|
37
|
+
//# sourceMappingURL=chunk-YQYYPJCK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browser/testing.ts"],"names":[],"mappings":";AA+BO,SAAS,mBAAA,GAAqC;AACnD,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,MAAM,EAAC;AAAA,IACjB,cAAA,EAAgB,MAAM,EAAC;AAAA,IACvB,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,IACd,YAAA,EAAc,YAAY;AAAC,GAC7B;AACF;AAKO,SAAS,iBAAA,CACd,WACA,IAAA,EACM;AAIR;AAKO,SAAS,sBAAA,CACd,SAAA,EACA,IAAA,EACA,GAAA,EACA,KAAA,EACM;AAMR;AA8BO,SAAS,oBAAA,CACd,iBACA,IAAA,EACS;AAGT,EAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AACvD;AAMO,SAAS,uBAAA,GAGd;AACA,EAAA,OAAO;AAAA,IACL,IAAI,KAAA,EAA+B;AAEjC,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,OAAO,wCAAA,EAAyC;AAAA,QAClD,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF,CAAA;AAAA,IACA,OAAO,KAAA,EAA+B;AAEpC,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,OAAO,wCAAA,EAAyC;AAAA,QAClD,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-YQYYPJCK.js","sourcesContent":["/**\n * Browser stub for testing module\n *\n * Testing utilities are server-side only.\n * In browser, these return no-op implementations.\n */\n\n/**\n * Test span structure (stub)\n */\nexport interface TestSpan {\n name: string;\n attributes: Record<string, unknown>;\n status: { code: number; message?: string };\n events: Array<{ name: string; attributes?: Record<string, unknown> }>;\n duration: number;\n}\n\n/**\n * Test collector structure (stub)\n */\nexport interface TestCollector {\n getSpans(): TestSpan[];\n getSpansByName(name: string): TestSpan[];\n clear(): void;\n waitForSpans(count: number, timeout?: number): Promise<TestSpan[]>;\n}\n\n/**\n * Browser stub: Returns empty collector\n */\nexport function createTestCollector(): TestCollector {\n return {\n getSpans: () => [],\n getSpansByName: () => [],\n clear: () => {},\n waitForSpans: async () => [],\n };\n}\n\n/**\n * Browser stub: No-op\n */\nexport function assertSpanCreated(\n collector: TestCollector,\n name: string,\n): void {\n void collector;\n void name;\n // No-op in browser\n}\n\n/**\n * Browser stub: No-op\n */\nexport function assertSpanHasAttribute(\n collector: TestCollector,\n name: string,\n key: string,\n value?: unknown,\n): void {\n void collector;\n void name;\n void key;\n void value;\n // No-op in browser\n}\n\n/**\n * Serialized span type (browser stub - mirrors server SerializedSpan).\n *\n * Defined as a `type` (not `interface`) so it is assignable to\n * `Record<string, unknown>` in TypeScript 6+ strict mode.\n */\nexport type SerializedSpan = {\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId?: string;\n attributes?: Record<string, unknown>;\n status: { code: number; message?: string };\n durationMs: number;\n};\n\n/**\n * Accepts either a raw `Request` (legacy) or a TanStack Router context\n * object containing `{ request: Request }` (Router 1.168+).\n */\ntype HandlerInput = Request | { request: Request };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype CreateFileRoute = (path: string) => (options: any) => any;\n\n/**\n * Browser stub: createTestSpansRoute is server-only.\n */\nexport function createTestSpansRoute(\n createFileRoute: CreateFileRoute,\n path?: string,\n): unknown {\n void createFileRoute;\n void path;\n throw new Error('createTestSpansRoute is server-only');\n}\n\n/**\n * Browser stub: test-spans handlers are server-only.\n * Returns no-op handlers that always return 404.\n */\nexport function createTestSpansHandlers(): {\n GET: (input: HandlerInput) => Response;\n DELETE: (input: HandlerInput) => Response;\n} {\n return {\n GET(input: HandlerInput): Response {\n void input;\n return Response.json(\n { error: 'createTestSpansHandlers is server-only' },\n { status: 404 },\n );\n },\n DELETE(input: HandlerInput): Response {\n void input;\n return Response.json(\n { error: 'createTestSpansHandlers is server-only' },\n { status: 404 },\n );\n },\n };\n}\n"]}
|
package/dist/testing.d.ts
CHANGED
|
@@ -127,8 +127,11 @@ declare function generateTraceparent(traceId?: string, spanId?: string): string;
|
|
|
127
127
|
/**
|
|
128
128
|
* Serialized span shape returned by the test-spans HTTP endpoint.
|
|
129
129
|
* Mirrors the fields the Playwright side needs for assertions.
|
|
130
|
+
*
|
|
131
|
+
* Defined as a `type` (not `interface`) so it is assignable to
|
|
132
|
+
* `Record<string, unknown>` in TypeScript 6+ strict mode.
|
|
130
133
|
*/
|
|
131
|
-
|
|
134
|
+
type SerializedSpan = {
|
|
132
135
|
name: string;
|
|
133
136
|
spanId: string;
|
|
134
137
|
traceId: string;
|
|
@@ -139,13 +142,25 @@ interface SerializedSpan {
|
|
|
139
142
|
message?: string;
|
|
140
143
|
};
|
|
141
144
|
durationMs: number;
|
|
142
|
-
}
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Accepts either a raw `Request` (legacy) or a TanStack Router context
|
|
148
|
+
* object containing `{ request: Request }` (Router 1.168+).
|
|
149
|
+
*/
|
|
150
|
+
type HandlerInput = Request | {
|
|
151
|
+
request: Request;
|
|
152
|
+
};
|
|
153
|
+
type CreateFileRoute = (path: string) => (options: any) => any;
|
|
143
154
|
/**
|
|
144
155
|
* Creates GET and DELETE handlers for a test-spans HTTP endpoint.
|
|
145
156
|
*
|
|
146
157
|
* Use in a TanStack Start route to expose in-memory spans for Playwright assertions.
|
|
147
158
|
* Only works when E2E=1 (set in webServer command).
|
|
148
159
|
*
|
|
160
|
+
* Handlers accept either a raw `Request` or a TanStack Router context
|
|
161
|
+
* object `{ request: Request }`, so they work with both Router < 1.168
|
|
162
|
+
* and Router >= 1.168.
|
|
163
|
+
*
|
|
149
164
|
* @example
|
|
150
165
|
* ```typescript
|
|
151
166
|
* // src/routes/api/test-spans.ts
|
|
@@ -157,9 +172,28 @@ interface SerializedSpan {
|
|
|
157
172
|
* });
|
|
158
173
|
* ```
|
|
159
174
|
*/
|
|
175
|
+
/**
|
|
176
|
+
* Creates a pre-built TanStack Start route for the test-spans endpoint.
|
|
177
|
+
*
|
|
178
|
+
* Reduces E2E boilerplate to three lines. The handlers accept both
|
|
179
|
+
* `Request` and `{ request: Request }` so they work with any Router version.
|
|
180
|
+
*
|
|
181
|
+
* @param createFileRoute - Pass `createFileRoute` from `@tanstack/react-router`
|
|
182
|
+
* @param path - Route path (default: `/api/test-spans`)
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* // src/routes/api/test-spans.ts
|
|
187
|
+
* import { createFileRoute } from "@tanstack/react-router";
|
|
188
|
+
* import { createTestSpansRoute } from "autotel-tanstack/testing";
|
|
189
|
+
*
|
|
190
|
+
* export const Route = createTestSpansRoute(createFileRoute);
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
declare function createTestSpansRoute(createFileRoute: CreateFileRoute, path?: string): any;
|
|
160
194
|
declare function createTestSpansHandlers(): {
|
|
161
|
-
GET: (
|
|
162
|
-
DELETE: (
|
|
195
|
+
GET: (input: HandlerInput) => Response;
|
|
196
|
+
DELETE: (input: HandlerInput) => Response;
|
|
163
197
|
};
|
|
164
198
|
|
|
165
|
-
export { type SerializedSpan, type TestHarness, createMockRequest, createTestHarness, createTestSpansHandlers, generateTraceparent };
|
|
199
|
+
export { type SerializedSpan, type TestHarness, createMockRequest, createTestHarness, createTestSpansHandlers, createTestSpansRoute, generateTraceparent };
|
package/dist/testing.js
CHANGED
|
@@ -125,9 +125,17 @@ function exporterGuard() {
|
|
|
125
125
|
}
|
|
126
126
|
return null;
|
|
127
127
|
}
|
|
128
|
+
function createTestSpansRoute(createFileRoute, path = "/api/test-spans") {
|
|
129
|
+
const { GET, DELETE } = createTestSpansHandlers();
|
|
130
|
+
return createFileRoute(path)({
|
|
131
|
+
server: {
|
|
132
|
+
handlers: { GET, DELETE }
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
128
136
|
function createTestSpansHandlers() {
|
|
129
137
|
return {
|
|
130
|
-
GET(
|
|
138
|
+
GET(_input) {
|
|
131
139
|
const guard = e2eGuard() ?? exporterGuard();
|
|
132
140
|
if (guard) return guard;
|
|
133
141
|
const spans = getExporter().getFinishedSpans().map((span) => {
|
|
@@ -147,7 +155,7 @@ function createTestSpansHandlers() {
|
|
|
147
155
|
});
|
|
148
156
|
return Response.json({ spans });
|
|
149
157
|
},
|
|
150
|
-
DELETE(
|
|
158
|
+
DELETE(_input) {
|
|
151
159
|
const guard = e2eGuard() ?? exporterGuard();
|
|
152
160
|
if (guard) return guard;
|
|
153
161
|
getExporter().reset();
|
|
@@ -156,6 +164,6 @@ function createTestSpansHandlers() {
|
|
|
156
164
|
};
|
|
157
165
|
}
|
|
158
166
|
|
|
159
|
-
export { createMockRequest, createTestHarness, createTestSpansHandlers, generateTraceparent };
|
|
167
|
+
export { createMockRequest, createTestHarness, createTestSpansHandlers, createTestSpansRoute, generateTraceparent };
|
|
160
168
|
//# sourceMappingURL=testing.js.map
|
|
161
169
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/testing.ts"],"names":[],"mappings":"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","file":"testing.js","sourcesContent":["import { type ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { InMemorySpanExporter } from 'autotel/exporters';\nimport { SimpleSpanProcessor } from 'autotel/processors';\nimport { init } from 'autotel';\n\n/**\n * Test harness for TanStack instrumentation testing\n *\n * Provides utilities for testing TanStack Start applications\n * with autotel-tanstack instrumentation.\n */\nexport interface TestHarness {\n /**\n * The in-memory span exporter\n */\n exporter: {\n getFinishedSpans(): ReadableSpan[];\n reset(): void;\n };\n\n /**\n * Get all finished spans\n */\n getSpans(): ReadableSpan[];\n\n /**\n * Get spans by name (exact match or regex)\n */\n getSpansByName(name: string | RegExp): ReadableSpan[];\n\n /**\n * Get spans by TanStack type\n */\n getSpansByType(\n type: 'request' | 'serverFn' | 'loader' | 'beforeLoad',\n ): ReadableSpan[];\n\n /**\n * Reset collected spans\n */\n reset(): void;\n\n /**\n * Assert a span exists\n */\n assertSpanExists(name: string | RegExp): void;\n\n /**\n * Assert a span has a specific attribute\n */\n assertSpanHasAttribute(\n name: string | RegExp,\n attr: string,\n value?: unknown,\n ): void;\n\n /**\n * Assert a server function was traced\n */\n assertServerFnTraced(name: string): void;\n\n /**\n * Assert a loader was traced\n */\n assertLoaderTraced(routeId: string): void;\n\n /**\n * Assert a beforeLoad was traced\n */\n assertBeforeLoadTraced(routeId: string): void;\n\n /**\n * Assert an HTTP request was traced\n */\n assertRequestTraced(method: string, path: string): void;\n}\n\n/**\n * Create a test harness for TanStack instrumentation testing\n *\n * This sets up autotel with an in-memory exporter for testing.\n * Call this in your test setup to capture and assert on spans.\n *\n * @returns Test harness with assertion helpers\n *\n * @example\n * ```typescript\n * import { describe, it, beforeEach } from 'vitest';\n * import { createTestHarness } from 'autotel-tanstack/testing';\n *\n * describe('MyServerFunction', () => {\n * let harness: ReturnType<typeof createTestHarness>;\n *\n * beforeEach(() => {\n * harness = createTestHarness();\n * });\n *\n * afterEach(() => {\n * harness.reset();\n * });\n *\n * it('should trace the server function', async () => {\n * await myServerFunction({ id: '123' });\n *\n * harness.assertServerFnTraced('myServerFunction');\n * harness.assertSpanHasAttribute(\n * /tanstack\\.serverFn/,\n * 'tanstack.server_function.name',\n * 'myServerFunction'\n * );\n * });\n * });\n * ```\n */\nexport function createTestHarness(): TestHarness {\n const exporter = new InMemorySpanExporter();\n\n init({\n service: 'test',\n spanProcessors: [new SimpleSpanProcessor(exporter)],\n });\n\n function getSpans(): ReadableSpan[] {\n return exporter.getFinishedSpans() as ReadableSpan[];\n }\n\n function getSpansByName(name: string | RegExp): ReadableSpan[] {\n const spans = getSpans();\n if (typeof name === 'string') {\n return spans.filter((s) => s.name === name);\n }\n return spans.filter((s) => name.test(s.name));\n }\n\n function getSpansByType(\n type: 'request' | 'serverFn' | 'loader' | 'beforeLoad',\n ): ReadableSpan[] {\n return getSpans().filter((s) => s.attributes['tanstack.type'] === type);\n }\n\n function reset(): void {\n exporter.reset();\n }\n\n function assertSpanExists(name: string | RegExp): void {\n const spans = getSpansByName(name);\n if (spans.length === 0) {\n const allSpanNames = getSpans().map((s) => s.name);\n throw new Error(\n `Expected span \"${name}\" to exist. Found spans: ${JSON.stringify(allSpanNames)}`,\n );\n }\n }\n\n function assertSpanHasAttribute(\n name: string | RegExp,\n attr: string,\n value?: unknown,\n ): void {\n const spans = getSpansByName(name);\n if (spans.length === 0) {\n throw new Error(`Span \"${name}\" not found`);\n }\n\n const span = spans[0];\n const attrValue = span.attributes[attr];\n\n if (attrValue === undefined) {\n throw new Error(\n `Attribute \"${attr}\" not found on span \"${span.name}\". ` +\n `Available attributes: ${JSON.stringify(Object.keys(span.attributes))}`,\n );\n }\n\n if (value !== undefined && attrValue !== value) {\n throw new Error(\n `Expected attribute \"${attr}\" to be \"${value}\", got \"${attrValue}\"`,\n );\n }\n }\n\n function assertServerFnTraced(name: string): void {\n assertSpanExists(`tanstack.serverFn.${name}`);\n }\n\n function assertLoaderTraced(routeId: string): void {\n assertSpanExists(`tanstack.loader.${routeId}`);\n }\n\n function assertBeforeLoadTraced(routeId: string): void {\n assertSpanExists(`tanstack.beforeLoad.${routeId}`);\n }\n\n function assertRequestTraced(method: string, path: string): void {\n assertSpanExists(`${method} ${path}`);\n }\n\n return {\n exporter,\n getSpans,\n getSpansByName,\n getSpansByType,\n reset,\n assertSpanExists,\n assertSpanHasAttribute,\n assertServerFnTraced,\n assertLoaderTraced,\n assertBeforeLoadTraced,\n assertRequestTraced,\n };\n}\n\n/**\n * Mock request factory for testing\n *\n * Creates mock Request objects for testing middleware and handlers.\n *\n * @example\n * ```typescript\n * const request = createMockRequest('GET', '/api/users', {\n * headers: { 'x-request-id': 'test-123' },\n * });\n * ```\n */\nexport function createMockRequest(\n method: string,\n path: string,\n options: {\n headers?: Record<string, string>;\n body?: string;\n traceparent?: string;\n } = {},\n): Request {\n const headers = new Headers(options.headers);\n\n if (options.traceparent) {\n headers.set('traceparent', options.traceparent);\n }\n\n return new Request(`http://localhost${path}`, {\n method,\n headers,\n body: options.body,\n });\n}\n\n/**\n * Generate a valid W3C traceparent header for testing\n *\n * @param traceId - Optional 32-char hex trace ID\n * @param spanId - Optional 16-char hex span ID\n * @returns Valid traceparent header string\n *\n * @example\n * ```typescript\n * const traceparent = generateTraceparent();\n * const request = createMockRequest('GET', '/api/users', { traceparent });\n * ```\n */\nexport function generateTraceparent(traceId?: string, spanId?: string): string {\n const version = '00';\n const trace = traceId || generateHex(32);\n const span = spanId || generateHex(16);\n const flags = '01'; // Sampled\n\n return `${version}-${trace}-${span}-${flags}`;\n}\n\nfunction generateHex(length: number): string {\n const chars = '0123456789abcdef';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * 16)];\n }\n return result;\n}\n\n/**\n * Serialized span shape returned by the test-spans HTTP endpoint.\n * Mirrors the fields the Playwright side needs for assertions.\n */\nexport interface SerializedSpan {\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId?: string;\n attributes?: Record<string, unknown>;\n status: { code: number; message?: string };\n durationMs: number;\n}\n\ninterface TestSpanExporter {\n getFinishedSpans(): Array<{\n name: string;\n spanContext(): { spanId: string; traceId: string };\n parentSpanContext?: { spanId: string };\n attributes: Record<string, unknown>;\n status: { code: number; message?: string };\n duration: [number, number];\n }>;\n reset(): void;\n}\n\nfunction getExporter(): TestSpanExporter | undefined {\n return (globalThis as Record<string, unknown>).__testSpanExporter as\n | TestSpanExporter\n | undefined;\n}\n\nfunction e2eGuard(): Response | null {\n if (process.env.E2E !== '1') {\n return Response.json(\n { error: 'test-spans endpoint only available in E2E mode' },\n { status: 404 },\n );\n }\n return null;\n}\n\nfunction exporterGuard(): Response | null {\n if (!getExporter()) {\n return Response.json(\n { error: 'in-memory span exporter not initialized' },\n { status: 500 },\n );\n }\n return null;\n}\n\n/**\n * Creates GET and DELETE handlers for a test-spans HTTP endpoint.\n *\n * Use in a TanStack Start route to expose in-memory spans for Playwright assertions.\n * Only works when E2E=1 (set in webServer command).\n *\n * @example\n * ```typescript\n * // src/routes/api/test-spans.ts\n * import { createFileRoute } from \"@tanstack/react-router\";\n * import { createTestSpansHandlers } from 'autotel-tanstack/testing';\n * const { GET, DELETE } = createTestSpansHandlers();\n * export const Route = createFileRoute('/api/test-spans')({\n * server: { handlers: { GET, DELETE } },\n * });\n * ```\n */\nexport function createTestSpansHandlers(): {\n GET: (request: Request) => Response;\n DELETE: (request: Request) => Response;\n} {\n return {\n GET(_request: Request): Response {\n const guard = e2eGuard() ?? exporterGuard();\n if (guard) return guard;\n\n const spans: SerializedSpan[] = getExporter()!\n .getFinishedSpans()\n .map((span) => {\n const { spanId, traceId } = span.spanContext();\n const serialized: SerializedSpan = {\n name: span.name,\n spanId,\n traceId,\n attributes: span.attributes,\n status: span.status,\n durationMs: span.duration[0] * 1000 + span.duration[1] / 1_000_000,\n };\n if (span.parentSpanContext?.spanId) {\n serialized.parentSpanId = span.parentSpanContext.spanId;\n }\n return serialized;\n });\n\n return Response.json({ spans });\n },\n\n DELETE(_request: Request): Response {\n const guard = e2eGuard() ?? exporterGuard();\n if (guard) return guard;\n getExporter()!.reset();\n return Response.json({ ok: true });\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"names":[],"mappings":";;;;;AAkHO,SAAS,iBAAA,GAAiC;AAC/C,EAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,EAAqB;AAE1C,EAAA,IAAA,CAAK;AAAA,IACH,OAAA,EAAS,MAAA;AAAA,IACT,cAAA,EAAgB,CAAC,IAAI,mBAAA,CAAoB,QAAQ,CAAC;AAAA,GACnD,CAAA;AAED,EAAA,SAAS,QAAA,GAA2B;AAClC,IAAA,OAAO,SAAS,gBAAA,EAAiB;AAAA,EACnC;AAEA,EAAA,SAAS,eAAe,IAAA,EAAuC;AAC7D,IAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,MAAA,OAAO,MAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAAA,IAC5C;AACA,IAAA,OAAO,KAAA,CAAM,OAAO,CAAC,CAAA,KAAM,KAAK,IAAA,CAAK,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EAC9C;AAEA,EAAA,SAAS,eACP,IAAA,EACgB;AAChB,IAAA,OAAO,QAAA,GAAW,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,UAAA,CAAW,eAAe,CAAA,KAAM,IAAI,CAAA;AAAA,EACxE;AAEA,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,QAAA,CAAS,KAAA,EAAM;AAAA,EACjB;AAEA,EAAA,SAAS,iBAAiB,IAAA,EAA6B;AACrD,IAAA,MAAM,KAAA,GAAQ,eAAe,IAAI,CAAA;AACjC,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,MAAA,MAAM,eAAe,QAAA,EAAS,CAAE,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AACjD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,kBAAkB,IAAI,CAAA,yBAAA,EAA4B,IAAA,CAAK,SAAA,CAAU,YAAY,CAAC,CAAA;AAAA,OAChF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAAS,sBAAA,CACP,IAAA,EACA,IAAA,EACA,KAAA,EACM;AACN,IAAA,MAAM,KAAA,GAAQ,eAAe,IAAI,CAAA;AACjC,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,IAAI,CAAA,WAAA,CAAa,CAAA;AAAA,IAC5C;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAEtC,IAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,WAAA,EAAc,IAAI,CAAA,qBAAA,EAAwB,IAAA,CAAK,IAAI,CAAA,yBAAA,EACxB,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,UAAU,CAAC,CAAC,CAAA;AAAA,OACzE;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,SAAA,KAAc,KAAA,EAAO;AAC9C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,oBAAA,EAAuB,IAAI,CAAA,SAAA,EAAY,KAAK,WAAW,SAAS,CAAA,CAAA;AAAA,OAClE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAAS,qBAAqB,IAAA,EAAoB;AAChD,IAAA,gBAAA,CAAiB,CAAA,kBAAA,EAAqB,IAAI,CAAA,CAAE,CAAA;AAAA,EAC9C;AAEA,EAAA,SAAS,mBAAmB,OAAA,EAAuB;AACjD,IAAA,gBAAA,CAAiB,CAAA,gBAAA,EAAmB,OAAO,CAAA,CAAE,CAAA;AAAA,EAC/C;AAEA,EAAA,SAAS,uBAAuB,OAAA,EAAuB;AACrD,IAAA,gBAAA,CAAiB,CAAA,oBAAA,EAAuB,OAAO,CAAA,CAAE,CAAA;AAAA,EACnD;AAEA,EAAA,SAAS,mBAAA,CAAoB,QAAgB,IAAA,EAAoB;AAC/D,IAAA,gBAAA,CAAiB,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAAA,EACtC;AAEA,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,QAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAA;AAAA,IACA,KAAA;AAAA,IACA,gBAAA;AAAA,IACA,sBAAA;AAAA,IACA,oBAAA;AAAA,IACA,kBAAA;AAAA,IACA,sBAAA;AAAA,IACA;AAAA,GACF;AACF;AAcO,SAAS,iBAAA,CACd,MAAA,EACA,IAAA,EACA,OAAA,GAII,EAAC,EACI;AACT,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,OAAA,CAAQ,OAAO,CAAA;AAE3C,EAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,IAAA,OAAA,CAAQ,GAAA,CAAI,aAAA,EAAe,OAAA,CAAQ,WAAW,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAA,EAAI;AAAA,IAC5C,MAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAM,OAAA,CAAQ;AAAA,GACf,CAAA;AACH;AAeO,SAAS,mBAAA,CAAoB,SAAkB,MAAA,EAAyB;AAC7E,EAAA,MAAM,OAAA,GAAU,IAAA;AAChB,EAAA,MAAM,KAAA,GAAQ,OAAA,IAAW,WAAA,CAAY,EAAE,CAAA;AACvC,EAAA,MAAM,IAAA,GAAO,MAAA,IAAU,WAAA,CAAY,EAAE,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,IAAA;AAEd,EAAA,OAAO,GAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,IAAI,IAAI,KAAK,CAAA,CAAA;AAC7C;AAEA,SAAS,YAAY,MAAA,EAAwB;AAC3C,EAAA,MAAM,KAAA,GAAQ,kBAAA;AACd,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,IAAA,MAAA,IAAU,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,GAAI,EAAE,CAAC,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT;AA+BA,SAAS,WAAA,GAA4C;AACnD,EAAA,OAAQ,UAAA,CAAuC,kBAAA;AAGjD;AAEA,SAAS,QAAA,GAA4B;AACnC,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,KAAQ,GAAA,EAAK;AAC3B,IAAA,OAAO,QAAA,CAAS,IAAA;AAAA,MACd,EAAE,OAAO,gDAAA,EAAiD;AAAA,MAC1D,EAAE,QAAQ,GAAA;AAAI,KAChB;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,aAAA,GAAiC;AACxC,EAAA,IAAI,CAAC,aAAY,EAAG;AAClB,IAAA,OAAO,QAAA,CAAS,IAAA;AAAA,MACd,EAAE,OAAO,yCAAA,EAA0C;AAAA,MACnD,EAAE,QAAQ,GAAA;AAAI,KAChB;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAkDO,SAAS,oBAAA,CACd,eAAA,EACA,IAAA,GAAO,iBAAA,EACP;AACA,EAAA,MAAM,EAAE,GAAA,EAAK,MAAA,EAAO,GAAI,uBAAA,EAAwB;AAChD,EAAA,OAAO,eAAA,CAAgB,IAAI,CAAA,CAAE;AAAA,IAC3B,MAAA,EAAQ;AAAA,MACN,QAAA,EAAU,EAAE,GAAA,EAAK,MAAA;AAAO;AAC1B,GACD,CAAA;AACH;AAEO,SAAS,uBAAA,GAGd;AACA,EAAA,OAAO;AAAA,IACL,IAAI,MAAA,EAAgC;AAClC,MAAA,MAAM,KAAA,GAAQ,QAAA,EAAS,IAAK,aAAA,EAAc;AAC1C,MAAA,IAAI,OAAO,OAAO,KAAA;AAElB,MAAA,MAAM,QAA0B,WAAA,EAAY,CACzC,kBAAiB,CACjB,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,QAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAQ,GAAI,KAAK,WAAA,EAAY;AAC7C,QAAA,MAAM,UAAA,GAA6B;AAAA,UACjC,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,MAAA;AAAA,UACA,OAAA;AAAA,UACA,YAAY,IAAA,CAAK,UAAA;AAAA,UACjB,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,UAAA,EAAY,KAAK,QAAA,CAAS,CAAC,IAAI,GAAA,GAAO,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,GAAI;AAAA,SAC3D;AACA,QAAA,IAAI,IAAA,CAAK,mBAAmB,MAAA,EAAQ;AAClC,UAAA,UAAA,CAAW,YAAA,GAAe,KAAK,iBAAA,CAAkB,MAAA;AAAA,QACnD;AACA,QAAA,OAAO,UAAA;AAAA,MACT,CAAC,CAAA;AAEH,MAAA,OAAO,QAAA,CAAS,IAAA,CAAK,EAAE,KAAA,EAAO,CAAA;AAAA,IAChC,CAAA;AAAA,IAEA,OAAO,MAAA,EAAgC;AACrC,MAAA,MAAM,KAAA,GAAQ,QAAA,EAAS,IAAK,aAAA,EAAc;AAC1C,MAAA,IAAI,OAAO,OAAO,KAAA;AAClB,MAAA,WAAA,GAAe,KAAA,EAAM;AACrB,MAAA,OAAO,QAAA,CAAS,IAAA,CAAK,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,IACnC;AAAA,GACF;AACF","file":"testing.js","sourcesContent":["import { type ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { InMemorySpanExporter } from 'autotel/exporters';\nimport { SimpleSpanProcessor } from 'autotel/processors';\nimport { init } from 'autotel';\n\n/**\n * Test harness for TanStack instrumentation testing\n *\n * Provides utilities for testing TanStack Start applications\n * with autotel-tanstack instrumentation.\n */\nexport interface TestHarness {\n /**\n * The in-memory span exporter\n */\n exporter: {\n getFinishedSpans(): ReadableSpan[];\n reset(): void;\n };\n\n /**\n * Get all finished spans\n */\n getSpans(): ReadableSpan[];\n\n /**\n * Get spans by name (exact match or regex)\n */\n getSpansByName(name: string | RegExp): ReadableSpan[];\n\n /**\n * Get spans by TanStack type\n */\n getSpansByType(\n type: 'request' | 'serverFn' | 'loader' | 'beforeLoad',\n ): ReadableSpan[];\n\n /**\n * Reset collected spans\n */\n reset(): void;\n\n /**\n * Assert a span exists\n */\n assertSpanExists(name: string | RegExp): void;\n\n /**\n * Assert a span has a specific attribute\n */\n assertSpanHasAttribute(\n name: string | RegExp,\n attr: string,\n value?: unknown,\n ): void;\n\n /**\n * Assert a server function was traced\n */\n assertServerFnTraced(name: string): void;\n\n /**\n * Assert a loader was traced\n */\n assertLoaderTraced(routeId: string): void;\n\n /**\n * Assert a beforeLoad was traced\n */\n assertBeforeLoadTraced(routeId: string): void;\n\n /**\n * Assert an HTTP request was traced\n */\n assertRequestTraced(method: string, path: string): void;\n}\n\n/**\n * Create a test harness for TanStack instrumentation testing\n *\n * This sets up autotel with an in-memory exporter for testing.\n * Call this in your test setup to capture and assert on spans.\n *\n * @returns Test harness with assertion helpers\n *\n * @example\n * ```typescript\n * import { describe, it, beforeEach } from 'vitest';\n * import { createTestHarness } from 'autotel-tanstack/testing';\n *\n * describe('MyServerFunction', () => {\n * let harness: ReturnType<typeof createTestHarness>;\n *\n * beforeEach(() => {\n * harness = createTestHarness();\n * });\n *\n * afterEach(() => {\n * harness.reset();\n * });\n *\n * it('should trace the server function', async () => {\n * await myServerFunction({ id: '123' });\n *\n * harness.assertServerFnTraced('myServerFunction');\n * harness.assertSpanHasAttribute(\n * /tanstack\\.serverFn/,\n * 'tanstack.server_function.name',\n * 'myServerFunction'\n * );\n * });\n * });\n * ```\n */\nexport function createTestHarness(): TestHarness {\n const exporter = new InMemorySpanExporter();\n\n init({\n service: 'test',\n spanProcessors: [new SimpleSpanProcessor(exporter)],\n });\n\n function getSpans(): ReadableSpan[] {\n return exporter.getFinishedSpans() as ReadableSpan[];\n }\n\n function getSpansByName(name: string | RegExp): ReadableSpan[] {\n const spans = getSpans();\n if (typeof name === 'string') {\n return spans.filter((s) => s.name === name);\n }\n return spans.filter((s) => name.test(s.name));\n }\n\n function getSpansByType(\n type: 'request' | 'serverFn' | 'loader' | 'beforeLoad',\n ): ReadableSpan[] {\n return getSpans().filter((s) => s.attributes['tanstack.type'] === type);\n }\n\n function reset(): void {\n exporter.reset();\n }\n\n function assertSpanExists(name: string | RegExp): void {\n const spans = getSpansByName(name);\n if (spans.length === 0) {\n const allSpanNames = getSpans().map((s) => s.name);\n throw new Error(\n `Expected span \"${name}\" to exist. Found spans: ${JSON.stringify(allSpanNames)}`,\n );\n }\n }\n\n function assertSpanHasAttribute(\n name: string | RegExp,\n attr: string,\n value?: unknown,\n ): void {\n const spans = getSpansByName(name);\n if (spans.length === 0) {\n throw new Error(`Span \"${name}\" not found`);\n }\n\n const span = spans[0];\n const attrValue = span.attributes[attr];\n\n if (attrValue === undefined) {\n throw new Error(\n `Attribute \"${attr}\" not found on span \"${span.name}\". ` +\n `Available attributes: ${JSON.stringify(Object.keys(span.attributes))}`,\n );\n }\n\n if (value !== undefined && attrValue !== value) {\n throw new Error(\n `Expected attribute \"${attr}\" to be \"${value}\", got \"${attrValue}\"`,\n );\n }\n }\n\n function assertServerFnTraced(name: string): void {\n assertSpanExists(`tanstack.serverFn.${name}`);\n }\n\n function assertLoaderTraced(routeId: string): void {\n assertSpanExists(`tanstack.loader.${routeId}`);\n }\n\n function assertBeforeLoadTraced(routeId: string): void {\n assertSpanExists(`tanstack.beforeLoad.${routeId}`);\n }\n\n function assertRequestTraced(method: string, path: string): void {\n assertSpanExists(`${method} ${path}`);\n }\n\n return {\n exporter,\n getSpans,\n getSpansByName,\n getSpansByType,\n reset,\n assertSpanExists,\n assertSpanHasAttribute,\n assertServerFnTraced,\n assertLoaderTraced,\n assertBeforeLoadTraced,\n assertRequestTraced,\n };\n}\n\n/**\n * Mock request factory for testing\n *\n * Creates mock Request objects for testing middleware and handlers.\n *\n * @example\n * ```typescript\n * const request = createMockRequest('GET', '/api/users', {\n * headers: { 'x-request-id': 'test-123' },\n * });\n * ```\n */\nexport function createMockRequest(\n method: string,\n path: string,\n options: {\n headers?: Record<string, string>;\n body?: string;\n traceparent?: string;\n } = {},\n): Request {\n const headers = new Headers(options.headers);\n\n if (options.traceparent) {\n headers.set('traceparent', options.traceparent);\n }\n\n return new Request(`http://localhost${path}`, {\n method,\n headers,\n body: options.body,\n });\n}\n\n/**\n * Generate a valid W3C traceparent header for testing\n *\n * @param traceId - Optional 32-char hex trace ID\n * @param spanId - Optional 16-char hex span ID\n * @returns Valid traceparent header string\n *\n * @example\n * ```typescript\n * const traceparent = generateTraceparent();\n * const request = createMockRequest('GET', '/api/users', { traceparent });\n * ```\n */\nexport function generateTraceparent(traceId?: string, spanId?: string): string {\n const version = '00';\n const trace = traceId || generateHex(32);\n const span = spanId || generateHex(16);\n const flags = '01'; // Sampled\n\n return `${version}-${trace}-${span}-${flags}`;\n}\n\nfunction generateHex(length: number): string {\n const chars = '0123456789abcdef';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * 16)];\n }\n return result;\n}\n\n/**\n * Serialized span shape returned by the test-spans HTTP endpoint.\n * Mirrors the fields the Playwright side needs for assertions.\n *\n * Defined as a `type` (not `interface`) so it is assignable to\n * `Record<string, unknown>` in TypeScript 6+ strict mode.\n */\nexport type SerializedSpan = {\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId?: string;\n attributes?: Record<string, unknown>;\n status: { code: number; message?: string };\n durationMs: number;\n};\n\ninterface TestSpanExporter {\n getFinishedSpans(): Array<{\n name: string;\n spanContext(): { spanId: string; traceId: string };\n parentSpanContext?: { spanId: string };\n attributes: Record<string, unknown>;\n status: { code: number; message?: string };\n duration: [number, number];\n }>;\n reset(): void;\n}\n\nfunction getExporter(): TestSpanExporter | undefined {\n return (globalThis as Record<string, unknown>).__testSpanExporter as\n | TestSpanExporter\n | undefined;\n}\n\nfunction e2eGuard(): Response | null {\n if (process.env.E2E !== '1') {\n return Response.json(\n { error: 'test-spans endpoint only available in E2E mode' },\n { status: 404 },\n );\n }\n return null;\n}\n\nfunction exporterGuard(): Response | null {\n if (!getExporter()) {\n return Response.json(\n { error: 'in-memory span exporter not initialized' },\n { status: 500 },\n );\n }\n return null;\n}\n\n/**\n * Accepts either a raw `Request` (legacy) or a TanStack Router context\n * object containing `{ request: Request }` (Router 1.168+).\n */\ntype HandlerInput = Request | { request: Request };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype CreateFileRoute = (path: string) => (options: any) => any;\n\n/**\n * Creates GET and DELETE handlers for a test-spans HTTP endpoint.\n *\n * Use in a TanStack Start route to expose in-memory spans for Playwright assertions.\n * Only works when E2E=1 (set in webServer command).\n *\n * Handlers accept either a raw `Request` or a TanStack Router context\n * object `{ request: Request }`, so they work with both Router < 1.168\n * and Router >= 1.168.\n *\n * @example\n * ```typescript\n * // src/routes/api/test-spans.ts\n * import { createFileRoute } from \"@tanstack/react-router\";\n * import { createTestSpansHandlers } from 'autotel-tanstack/testing';\n * const { GET, DELETE } = createTestSpansHandlers();\n * export const Route = createFileRoute('/api/test-spans')({\n * server: { handlers: { GET, DELETE } },\n * });\n * ```\n */\n/**\n * Creates a pre-built TanStack Start route for the test-spans endpoint.\n *\n * Reduces E2E boilerplate to three lines. The handlers accept both\n * `Request` and `{ request: Request }` so they work with any Router version.\n *\n * @param createFileRoute - Pass `createFileRoute` from `@tanstack/react-router`\n * @param path - Route path (default: `/api/test-spans`)\n *\n * @example\n * ```typescript\n * // src/routes/api/test-spans.ts\n * import { createFileRoute } from \"@tanstack/react-router\";\n * import { createTestSpansRoute } from \"autotel-tanstack/testing\";\n *\n * export const Route = createTestSpansRoute(createFileRoute);\n * ```\n */\nexport function createTestSpansRoute(\n createFileRoute: CreateFileRoute,\n path = '/api/test-spans',\n) {\n const { GET, DELETE } = createTestSpansHandlers();\n return createFileRoute(path)({\n server: {\n handlers: { GET, DELETE },\n },\n });\n}\n\nexport function createTestSpansHandlers(): {\n GET: (input: HandlerInput) => Response;\n DELETE: (input: HandlerInput) => Response;\n} {\n return {\n GET(_input: HandlerInput): Response {\n const guard = e2eGuard() ?? exporterGuard();\n if (guard) return guard;\n\n const spans: SerializedSpan[] = getExporter()!\n .getFinishedSpans()\n .map((span) => {\n const { spanId, traceId } = span.spanContext();\n const serialized: SerializedSpan = {\n name: span.name,\n spanId,\n traceId,\n attributes: span.attributes,\n status: span.status,\n durationMs: span.duration[0] * 1000 + span.duration[1] / 1_000_000,\n };\n if (span.parentSpanContext?.spanId) {\n serialized.parentSpanId = span.parentSpanContext.spanId;\n }\n return serialized;\n });\n\n return Response.json({ spans });\n },\n\n DELETE(_input: HandlerInput): Response {\n const guard = e2eGuard() ?? exporterGuard();\n if (guard) return guard;\n getExporter()!.reset();\n return Response.json({ ok: true });\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-tanstack",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.7",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for TanStack Start - automatic tracing for server functions, middleware, and route loaders",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -121,14 +121,14 @@
|
|
|
121
121
|
"author": "Jag Reehal <jag@jagreehal.com> (https://jagreehal.com)",
|
|
122
122
|
"license": "MIT",
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"@opentelemetry/api": "^1.9.
|
|
125
|
-
"@tanstack/intent": "^0.0.
|
|
126
|
-
"autotel": "2.
|
|
127
|
-
"autotel-adapters": "0.2.
|
|
124
|
+
"@opentelemetry/api": "^1.9.1",
|
|
125
|
+
"@tanstack/intent": "^0.0.29",
|
|
126
|
+
"autotel": "2.26.0",
|
|
127
|
+
"autotel-adapters": "0.2.6"
|
|
128
128
|
},
|
|
129
129
|
"peerDependencies": {
|
|
130
|
-
"@tanstack/react-start": "^1.167.
|
|
131
|
-
"@tanstack/solid-start": "^1.167.
|
|
130
|
+
"@tanstack/react-start": "^1.167.16",
|
|
131
|
+
"@tanstack/solid-start": "^1.167.15"
|
|
132
132
|
},
|
|
133
133
|
"peerDependenciesMeta": {
|
|
134
134
|
"@tanstack/react-start": {
|
|
@@ -139,14 +139,14 @@
|
|
|
139
139
|
}
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|
|
142
|
-
"@opentelemetry/sdk-trace-base": "^2.6.
|
|
143
|
-
"@tanstack/react-router": "^1.168.
|
|
144
|
-
"@types/node": "^25.5.
|
|
142
|
+
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
|
143
|
+
"@tanstack/react-router": "^1.168.10",
|
|
144
|
+
"@types/node": "^25.5.2",
|
|
145
145
|
"rimraf": "^6.1.3",
|
|
146
146
|
"tsup": "^8.5.1",
|
|
147
|
-
"typescript": "^
|
|
148
|
-
"vitest": "^4.1.
|
|
149
|
-
"vitest-mock-extended": "^
|
|
147
|
+
"typescript": "^6.0.2",
|
|
148
|
+
"vitest": "^4.1.3",
|
|
149
|
+
"vitest-mock-extended": "^4.0.0"
|
|
150
150
|
},
|
|
151
151
|
"repository": {
|
|
152
152
|
"type": "git",
|
package/src/browser/testing.ts
CHANGED
|
@@ -67,9 +67,12 @@ export function assertSpanHasAttribute(
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
|
-
* Serialized span
|
|
70
|
+
* Serialized span type (browser stub - mirrors server SerializedSpan).
|
|
71
|
+
*
|
|
72
|
+
* Defined as a `type` (not `interface`) so it is assignable to
|
|
73
|
+
* `Record<string, unknown>` in TypeScript 6+ strict mode.
|
|
71
74
|
*/
|
|
72
|
-
export
|
|
75
|
+
export type SerializedSpan = {
|
|
73
76
|
name: string;
|
|
74
77
|
spanId: string;
|
|
75
78
|
traceId: string;
|
|
@@ -77,6 +80,27 @@ export interface SerializedSpan {
|
|
|
77
80
|
attributes?: Record<string, unknown>;
|
|
78
81
|
status: { code: number; message?: string };
|
|
79
82
|
durationMs: number;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Accepts either a raw `Request` (legacy) or a TanStack Router context
|
|
87
|
+
* object containing `{ request: Request }` (Router 1.168+).
|
|
88
|
+
*/
|
|
89
|
+
type HandlerInput = Request | { request: Request };
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
type CreateFileRoute = (path: string) => (options: any) => any;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Browser stub: createTestSpansRoute is server-only.
|
|
96
|
+
*/
|
|
97
|
+
export function createTestSpansRoute(
|
|
98
|
+
createFileRoute: CreateFileRoute,
|
|
99
|
+
path?: string,
|
|
100
|
+
): unknown {
|
|
101
|
+
void createFileRoute;
|
|
102
|
+
void path;
|
|
103
|
+
throw new Error('createTestSpansRoute is server-only');
|
|
80
104
|
}
|
|
81
105
|
|
|
82
106
|
/**
|
|
@@ -84,21 +108,19 @@ export interface SerializedSpan {
|
|
|
84
108
|
* Returns no-op handlers that always return 404.
|
|
85
109
|
*/
|
|
86
110
|
export function createTestSpansHandlers(): {
|
|
87
|
-
GET: (
|
|
88
|
-
DELETE: (
|
|
111
|
+
GET: (input: HandlerInput) => Response;
|
|
112
|
+
DELETE: (input: HandlerInput) => Response;
|
|
89
113
|
} {
|
|
90
114
|
return {
|
|
91
|
-
GET(
|
|
92
|
-
|
|
93
|
-
void _request;
|
|
115
|
+
GET(input: HandlerInput): Response {
|
|
116
|
+
void input;
|
|
94
117
|
return Response.json(
|
|
95
118
|
{ error: 'createTestSpansHandlers is server-only' },
|
|
96
119
|
{ status: 404 },
|
|
97
120
|
);
|
|
98
121
|
},
|
|
99
|
-
DELETE(
|
|
100
|
-
|
|
101
|
-
void _request;
|
|
122
|
+
DELETE(input: HandlerInput): Response {
|
|
123
|
+
void input;
|
|
102
124
|
return Response.json(
|
|
103
125
|
{ error: 'createTestSpansHandlers is server-only' },
|
|
104
126
|
{ status: 404 },
|
package/src/testing.test.ts
CHANGED
|
@@ -87,12 +87,20 @@ describe('createTestSpansHandlers', () => {
|
|
|
87
87
|
delete process.env.E2E;
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
it('GET returns 404 when not in E2E mode', async () => {
|
|
90
|
+
it('GET returns 404 when not in E2E mode (raw Request)', async () => {
|
|
91
91
|
const { GET } = createTestSpansHandlers();
|
|
92
92
|
const res = GET(new Request('http://localhost/api/test-spans'));
|
|
93
93
|
expect(res.status).toBe(404);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
it('GET returns 404 when not in E2E mode (context object)', async () => {
|
|
97
|
+
const { GET } = createTestSpansHandlers();
|
|
98
|
+
const res = GET({
|
|
99
|
+
request: new Request('http://localhost/api/test-spans'),
|
|
100
|
+
});
|
|
101
|
+
expect(res.status).toBe(404);
|
|
102
|
+
});
|
|
103
|
+
|
|
96
104
|
it('GET returns 500 when exporter not initialized', async () => {
|
|
97
105
|
process.env.E2E = '1';
|
|
98
106
|
const { GET } = createTestSpansHandlers();
|
|
@@ -150,7 +158,7 @@ describe('createTestSpansHandlers', () => {
|
|
|
150
158
|
expect(body.spans[0].parentSpanId).toBeUndefined();
|
|
151
159
|
});
|
|
152
160
|
|
|
153
|
-
it('DELETE returns 404 when not in E2E mode', async () => {
|
|
161
|
+
it('DELETE returns 404 when not in E2E mode (raw Request)', async () => {
|
|
154
162
|
const { DELETE } = createTestSpansHandlers();
|
|
155
163
|
const res = DELETE(
|
|
156
164
|
new Request('http://localhost/api/test-spans', { method: 'DELETE' }),
|
|
@@ -158,6 +166,16 @@ describe('createTestSpansHandlers', () => {
|
|
|
158
166
|
expect(res.status).toBe(404);
|
|
159
167
|
});
|
|
160
168
|
|
|
169
|
+
it('DELETE returns 404 when not in E2E mode (context object)', async () => {
|
|
170
|
+
const { DELETE } = createTestSpansHandlers();
|
|
171
|
+
const res = DELETE({
|
|
172
|
+
request: new Request('http://localhost/api/test-spans', {
|
|
173
|
+
method: 'DELETE',
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
expect(res.status).toBe(404);
|
|
177
|
+
});
|
|
178
|
+
|
|
161
179
|
it('DELETE returns 500 when exporter not initialized', async () => {
|
|
162
180
|
process.env.E2E = '1';
|
|
163
181
|
const { DELETE } = createTestSpansHandlers();
|
package/src/testing.ts
CHANGED
|
@@ -278,8 +278,11 @@ function generateHex(length: number): string {
|
|
|
278
278
|
/**
|
|
279
279
|
* Serialized span shape returned by the test-spans HTTP endpoint.
|
|
280
280
|
* Mirrors the fields the Playwright side needs for assertions.
|
|
281
|
+
*
|
|
282
|
+
* Defined as a `type` (not `interface`) so it is assignable to
|
|
283
|
+
* `Record<string, unknown>` in TypeScript 6+ strict mode.
|
|
281
284
|
*/
|
|
282
|
-
export
|
|
285
|
+
export type SerializedSpan = {
|
|
283
286
|
name: string;
|
|
284
287
|
spanId: string;
|
|
285
288
|
traceId: string;
|
|
@@ -287,7 +290,7 @@ export interface SerializedSpan {
|
|
|
287
290
|
attributes?: Record<string, unknown>;
|
|
288
291
|
status: { code: number; message?: string };
|
|
289
292
|
durationMs: number;
|
|
290
|
-
}
|
|
293
|
+
};
|
|
291
294
|
|
|
292
295
|
interface TestSpanExporter {
|
|
293
296
|
getFinishedSpans(): Array<{
|
|
@@ -327,12 +330,25 @@ function exporterGuard(): Response | null {
|
|
|
327
330
|
return null;
|
|
328
331
|
}
|
|
329
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Accepts either a raw `Request` (legacy) or a TanStack Router context
|
|
335
|
+
* object containing `{ request: Request }` (Router 1.168+).
|
|
336
|
+
*/
|
|
337
|
+
type HandlerInput = Request | { request: Request };
|
|
338
|
+
|
|
339
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
340
|
+
type CreateFileRoute = (path: string) => (options: any) => any;
|
|
341
|
+
|
|
330
342
|
/**
|
|
331
343
|
* Creates GET and DELETE handlers for a test-spans HTTP endpoint.
|
|
332
344
|
*
|
|
333
345
|
* Use in a TanStack Start route to expose in-memory spans for Playwright assertions.
|
|
334
346
|
* Only works when E2E=1 (set in webServer command).
|
|
335
347
|
*
|
|
348
|
+
* Handlers accept either a raw `Request` or a TanStack Router context
|
|
349
|
+
* object `{ request: Request }`, so they work with both Router < 1.168
|
|
350
|
+
* and Router >= 1.168.
|
|
351
|
+
*
|
|
336
352
|
* @example
|
|
337
353
|
* ```typescript
|
|
338
354
|
* // src/routes/api/test-spans.ts
|
|
@@ -344,12 +360,42 @@ function exporterGuard(): Response | null {
|
|
|
344
360
|
* });
|
|
345
361
|
* ```
|
|
346
362
|
*/
|
|
363
|
+
/**
|
|
364
|
+
* Creates a pre-built TanStack Start route for the test-spans endpoint.
|
|
365
|
+
*
|
|
366
|
+
* Reduces E2E boilerplate to three lines. The handlers accept both
|
|
367
|
+
* `Request` and `{ request: Request }` so they work with any Router version.
|
|
368
|
+
*
|
|
369
|
+
* @param createFileRoute - Pass `createFileRoute` from `@tanstack/react-router`
|
|
370
|
+
* @param path - Route path (default: `/api/test-spans`)
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* // src/routes/api/test-spans.ts
|
|
375
|
+
* import { createFileRoute } from "@tanstack/react-router";
|
|
376
|
+
* import { createTestSpansRoute } from "autotel-tanstack/testing";
|
|
377
|
+
*
|
|
378
|
+
* export const Route = createTestSpansRoute(createFileRoute);
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
export function createTestSpansRoute(
|
|
382
|
+
createFileRoute: CreateFileRoute,
|
|
383
|
+
path = '/api/test-spans',
|
|
384
|
+
) {
|
|
385
|
+
const { GET, DELETE } = createTestSpansHandlers();
|
|
386
|
+
return createFileRoute(path)({
|
|
387
|
+
server: {
|
|
388
|
+
handlers: { GET, DELETE },
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
347
393
|
export function createTestSpansHandlers(): {
|
|
348
|
-
GET: (
|
|
349
|
-
DELETE: (
|
|
394
|
+
GET: (input: HandlerInput) => Response;
|
|
395
|
+
DELETE: (input: HandlerInput) => Response;
|
|
350
396
|
} {
|
|
351
397
|
return {
|
|
352
|
-
GET(
|
|
398
|
+
GET(_input: HandlerInput): Response {
|
|
353
399
|
const guard = e2eGuard() ?? exporterGuard();
|
|
354
400
|
if (guard) return guard;
|
|
355
401
|
|
|
@@ -374,7 +420,7 @@ export function createTestSpansHandlers(): {
|
|
|
374
420
|
return Response.json({ spans });
|
|
375
421
|
},
|
|
376
422
|
|
|
377
|
-
DELETE(
|
|
423
|
+
DELETE(_input: HandlerInput): Response {
|
|
378
424
|
const guard = e2eGuard() ?? exporterGuard();
|
|
379
425
|
if (guard) return guard;
|
|
380
426
|
getExporter()!.reset();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser/testing.ts"],"names":[],"mappings":";AA+BO,SAAS,mBAAA,GAAqC;AACnD,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,MAAM,EAAC;AAAA,IACjB,cAAA,EAAgB,MAAM,EAAC;AAAA,IACvB,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,IACd,YAAA,EAAc,YAAY;AAAC,GAC7B;AACF;AAKO,SAAS,iBAAA,CACd,WACA,IAAA,EACM;AAIR;AAKO,SAAS,sBAAA,CACd,SAAA,EACA,IAAA,EACA,GAAA,EACA,KAAA,EACM;AAMR;AAmBO,SAAS,uBAAA,GAGd;AACA,EAAA,OAAO;AAAA,IACL,IAAI,QAAA,EAA6B;AAG/B,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,OAAO,wCAAA,EAAyC;AAAA,QAClD,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF,CAAA;AAAA,IACA,OAAO,QAAA,EAA6B;AAGlC,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,OAAO,wCAAA,EAAyC;AAAA,QAClD,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-ZJTHTWHJ.js","sourcesContent":["/**\n * Browser stub for testing module\n *\n * Testing utilities are server-side only.\n * In browser, these return no-op implementations.\n */\n\n/**\n * Test span structure (stub)\n */\nexport interface TestSpan {\n name: string;\n attributes: Record<string, unknown>;\n status: { code: number; message?: string };\n events: Array<{ name: string; attributes?: Record<string, unknown> }>;\n duration: number;\n}\n\n/**\n * Test collector structure (stub)\n */\nexport interface TestCollector {\n getSpans(): TestSpan[];\n getSpansByName(name: string): TestSpan[];\n clear(): void;\n waitForSpans(count: number, timeout?: number): Promise<TestSpan[]>;\n}\n\n/**\n * Browser stub: Returns empty collector\n */\nexport function createTestCollector(): TestCollector {\n return {\n getSpans: () => [],\n getSpansByName: () => [],\n clear: () => {},\n waitForSpans: async () => [],\n };\n}\n\n/**\n * Browser stub: No-op\n */\nexport function assertSpanCreated(\n collector: TestCollector,\n name: string,\n): void {\n void collector;\n void name;\n // No-op in browser\n}\n\n/**\n * Browser stub: No-op\n */\nexport function assertSpanHasAttribute(\n collector: TestCollector,\n name: string,\n key: string,\n value?: unknown,\n): void {\n void collector;\n void name;\n void key;\n void value;\n // No-op in browser\n}\n\n/**\n * Serialized span interface (browser stub - mirrors server SerializedSpan).\n */\nexport interface SerializedSpan {\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId?: string;\n attributes?: Record<string, unknown>;\n status: { code: number; message?: string };\n durationMs: number;\n}\n\n/**\n * Browser stub: test-spans handlers are server-only.\n * Returns no-op handlers that always return 404.\n */\nexport function createTestSpansHandlers(): {\n GET: (request: Request) => Response;\n DELETE: (request: Request) => Response;\n} {\n return {\n GET(_request: Request): Response {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n void _request;\n return Response.json(\n { error: 'createTestSpansHandlers is server-only' },\n { status: 404 },\n );\n },\n DELETE(_request: Request): Response {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n void _request;\n return Response.json(\n { error: 'createTestSpansHandlers is server-only' },\n { status: 404 },\n );\n },\n };\n}\n"]}
|