Skip to content

Commit d405a64

Browse files
mydeaclaude
andcommitted
test(deno): Add orchestrion-fastify integration test
Mirror the other orchestrion Deno suites: assert the Fastify integration is in the defaults and that the native `tracing:fastify.request.handler:error` channel captures the error (with mechanism `auto.function.fastify`). Adds a shared `errorSink` helper alongside `transactionSink`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ab767ef commit d405a64

2 files changed

Lines changed: 82 additions & 1 deletion

File tree

  • dev-packages/deno-integration-tests

dev-packages/deno-integration-tests/src/index.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { TransactionEvent } from '@sentry/core';
1+
import type { Event, TransactionEvent } from '@sentry/core';
22
import { getAsyncContextStrategy, getMainCarrier, setAsyncContextStrategy } from '@sentry/core';
33

44
/**
@@ -51,6 +51,40 @@ export function transactionSink(): TransactionSink {
5151
};
5252
}
5353

54+
export interface ErrorSink {
55+
beforeSend: (event: Event) => null;
56+
waitFor: (predicate: (event: Event) => boolean) => Promise<Event>;
57+
}
58+
59+
/**
60+
* A `beforeSend` hook that records every error event and lets a test `await` the
61+
* first one matching a predicate. Mirrors {@link transactionSink} for error events.
62+
*/
63+
export function errorSink(): ErrorSink {
64+
const events: Event[] = [];
65+
const waiters: { predicate: (e: Event) => boolean; resolve: (e: Event) => void }[] = [];
66+
return {
67+
beforeSend(event) {
68+
events.push(event);
69+
for (let i = waiters.length - 1; i >= 0; i--) {
70+
const w = waiters[i]!;
71+
if (w.predicate(event)) {
72+
waiters.splice(i, 1);
73+
w.resolve(event);
74+
}
75+
}
76+
return null;
77+
},
78+
waitFor(predicate) {
79+
const already = events.find(predicate);
80+
if (already) return Promise.resolve(already);
81+
return new Promise<Event>(resolve => {
82+
waiters.push({ predicate, resolve });
83+
});
84+
},
85+
};
86+
}
87+
5488
/** Reject with a descriptive message if `p` does not settle within `ms`. */
5589
export function withTimeout<T>(p: Promise<T>, ms: number, what: string): Promise<T> {
5690
let timer: ReturnType<typeof setTimeout> | undefined;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// <reference lib="deno.ns" />
2+
3+
import { channel } from 'node:diagnostics_channel';
4+
import type { DenoClient } from '@sentry/deno';
5+
import { init } from '@sentry/deno';
6+
import { assert } from 'https://deno.land/std@0.212.0/assert/assert.ts';
7+
import { assertEquals } from 'https://deno.land/std@0.212.0/assert/assert_equals.ts';
8+
import { assertExists } from 'https://deno.land/std@0.212.0/assert/assert_exists.ts';
9+
import { errorSink, resetGlobals, withTimeout } from '../../src/index.ts';
10+
11+
Deno.test('fastify instrumentation: included in default integrations (Deno 2.8.0+)', () => {
12+
resetGlobals();
13+
const client = init({ traceLifecycle: 'static', dsn: 'https://username@domain/123' }) as DenoClient;
14+
const names = client.getOptions().integrations.map(i => i.name);
15+
assert(names.includes('Fastify'), `Fastify should be in defaults, got ${names.join(', ')}`);
16+
});
17+
18+
Deno.test('fastify instrumentation: tracing:fastify.request.handler:error channel captures the error', async () => {
19+
resetGlobals();
20+
const sink = errorSink();
21+
init({
22+
traceLifecycle: 'static',
23+
dsn: 'https://username@domain/123',
24+
beforeSend: sink.beforeSend,
25+
});
26+
27+
const error = new Error('fastify boom');
28+
29+
// Fastify v5 publishes this native diagnostics channel when a request handler errors; the
30+
// integration subscribes to it directly (no orchestrion injection needed). A 5xx reply passes the
31+
// default `shouldHandleError`, so the error is captured.
32+
channel('tracing:fastify.request.handler:error').publish({
33+
error,
34+
request: { method: 'GET', routeOptions: { url: '/boom' } },
35+
reply: { statusCode: 500 },
36+
});
37+
38+
const event = await withTimeout(
39+
sink.waitFor(e => e.exception?.values?.[0]?.value === 'fastify boom'),
40+
5000,
41+
"the captured 'fastify boom' error",
42+
);
43+
44+
assertExists(event.exception?.values?.[0]);
45+
assertEquals(event.exception?.values?.[0]?.mechanism?.type, 'auto.function.fastify');
46+
assertEquals(event.exception?.values?.[0]?.mechanism?.handled, false);
47+
});

0 commit comments

Comments
 (0)