Skip to content

Commit 5af594d

Browse files
committed
fix tests
1 parent fd01aef commit 5af594d

2 files changed

Lines changed: 62 additions & 48 deletions

File tree

dev-packages/node-integration-tests/suites/hono/instrument.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node';
22
import { loggingTransport } from '@sentry-internal/node-integration-tests';
33

44
Sentry.init({
5-
traceLifecycle: 'static',
65
dsn: 'https://public@dsn.ingest.sentry.io/1337',
76
tracesSampleRate: 1.0,
87
transport: loggingTransport,

dev-packages/node-integration-tests/suites/hono/test.ts

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
import { afterAll, describe, expect } from 'vitest';
22
import { cleanupChildProcesses, createEsmAndCjsTests } from '../../utils/runner';
33

4+
// Verifies that Hono is auto-instrumented out of the box by `@sentry/node` (the `honoIntegration`
5+
// default), without importing `@sentry/hono` or registering the `sentry()` middleware manually.
6+
//
7+
// The SDK runs with the default `traceLifecycle` (span streaming), so the transaction is asserted via
8+
// the streamed span container (`container.items`, root = `is_segment`) rather than a `transaction`
9+
// envelope, and `.unordered()` lets the segment/child spans and error events arrive in any order
10+
// while ignoring unrelated envelopes (client reports, etc.).
11+
12+
// oxlint-disable-next-line typescript/no-explicit-any
13+
type StreamedSpan = { name?: string; status?: string; is_segment?: boolean; attributes?: Record<string, any> };
14+
15+
const attr = (span: StreamedSpan, key: string): unknown => span.attributes?.[key]?.value;
16+
const op = (span: StreamedSpan): unknown => attr(span, 'sentry.op');
17+
418
describe('hono auto-instrumentation', () => {
519
afterAll(() => {
620
cleanupChildProcesses();
@@ -9,15 +23,15 @@ describe('hono auto-instrumentation', () => {
923
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => {
1024
test('creates a transaction for a basic GET request', async () => {
1125
const runner = createRunner()
26+
.unordered()
1227
.expect({
13-
transaction: {
14-
transaction: 'GET /',
15-
contexts: {
16-
trace: {
17-
op: 'http.server',
18-
status: 'ok',
19-
},
20-
},
28+
span: container => {
29+
const segment = container.items.find(item => item.is_segment && item.name === 'GET /');
30+
if (!segment) {
31+
throw new Error('segment for `GET /` not in this container');
32+
}
33+
expect(op(segment)).toBe('http.server');
34+
expect(segment.status).toBe('ok');
2135
},
2236
})
2337
.start();
@@ -27,18 +41,15 @@ describe('hono auto-instrumentation', () => {
2741

2842
test('creates a transaction with a parametrized route name', async () => {
2943
const runner = createRunner()
44+
.unordered()
3045
.expect({
31-
transaction: {
32-
transaction: 'GET /hello/:name',
33-
transaction_info: {
34-
source: 'route',
35-
},
36-
contexts: {
37-
trace: {
38-
op: 'http.server',
39-
status: 'ok',
40-
},
41-
},
46+
span: container => {
47+
const segment = container.items.find(item => item.is_segment && item.name === 'GET /hello/:name');
48+
if (!segment) {
49+
throw new Error('segment for `GET /hello/:name` not in this container');
50+
}
51+
expect(op(segment)).toBe('http.server');
52+
expect(attr(segment, 'sentry.segment.name.source')).toBe('route');
4253
},
4354
})
4455
.start();
@@ -48,7 +59,7 @@ describe('hono auto-instrumentation', () => {
4859

4960
test('captures an error with the correct mechanism', async () => {
5061
const runner = createRunner()
51-
.ignore('transaction')
62+
.unordered()
5263
.expect({
5364
event: {
5465
exception: {
@@ -73,19 +84,16 @@ describe('hono auto-instrumentation', () => {
7384

7485
test('creates a transaction with internal_error status when an error occurs', async () => {
7586
const runner = createRunner()
76-
.ignore('event')
87+
.unordered()
7788
.expect({
78-
transaction: {
79-
transaction: 'GET /error/:param',
80-
contexts: {
81-
trace: {
82-
op: 'http.server',
83-
status: 'internal_error',
84-
data: expect.objectContaining({
85-
'http.response.status_code': 500,
86-
}),
87-
},
88-
},
89+
span: container => {
90+
const segment = container.items.find(item => item.is_segment && item.name === 'GET /error/:param');
91+
if (!segment) {
92+
throw new Error('segment for `GET /error/:param` not in this container');
93+
}
94+
expect(op(segment)).toBe('http.server');
95+
expect(segment.status).toBe('error');
96+
expect(attr(segment, 'http.response.status_code')).toBe(500);
8997
},
9098
})
9199
.start();
@@ -95,16 +103,19 @@ describe('hono auto-instrumentation', () => {
95103

96104
test('does not create a middleware span for the Sentry middleware in a mounted sub-app', async () => {
97105
const runner = createRunner()
106+
.unordered()
98107
.expect({
99-
transaction: transaction => {
100-
expect(transaction.transaction).toBe('GET /sub/hello');
101-
const middlewareSpans = (transaction.spans || []).filter(span => span.op === 'middleware');
102-
const names = middlewareSpans.map(span => span.description);
108+
span: container => {
109+
const segment = container.items.find(item => item.is_segment && item.name === 'GET /sub/hello');
110+
if (!segment) {
111+
throw new Error('segment for `GET /sub/hello` not in this container');
112+
}
113+
const middlewareNames = container.items.filter(item => op(item) === 'middleware').map(item => item.name);
103114
// The sub-app's user middleware is traced …
104-
expect(names).toContain('subMiddleware');
115+
expect(middlewareNames).toContain('subMiddleware');
105116
// … but the sub-app's own auto-registered Sentry middleware must not appear as a span
106117
// (it is copied into the parent at mount time and must stay unwrapped).
107-
expect(names).not.toContain('<anonymous>');
118+
expect(middlewareNames).not.toContain('<anonymous>');
108119
},
109120
})
110121
.start();
@@ -114,21 +125,25 @@ describe('hono auto-instrumentation', () => {
114125

115126
test('traces an internal .request() call without the inner app re-instrumenting the request', async () => {
116127
const runner = createRunner()
128+
.unordered()
117129
.expect({
118-
transaction: transaction => {
119-
// The transaction is named after the outer route, not the internal one.
120-
expect(transaction.transaction).toBe('GET /outer/:itemId');
121-
122-
const spans = transaction.spans || [];
130+
span: container => {
131+
// Transaction is named after the outer route, not the internal one.
132+
const segment = container.items.find(item => item.is_segment && item.name === 'GET /outer/:itemId');
133+
if (!segment) {
134+
throw new Error('segment for `GET /outer/:itemId` not in this container');
135+
}
123136

124137
// The internal dispatch is traced with the raw inner path — the inner app's Sentry
125138
// middleware must not re-name it to the parametrized route.
126-
const internalRequestSpans = spans.filter(span => span.origin === 'auto.http.hono.internal_request');
139+
const internalRequestSpans = container.items.filter(
140+
item => attr(item, 'sentry.origin') === 'auto.http.hono.internal_request',
141+
);
127142
expect(internalRequestSpans).toHaveLength(1);
128-
expect(internalRequestSpans[0]?.description).toBe('GET /item/self-watering-plant');
143+
expect(internalRequestSpans[0]?.name).toBe('GET /item/self-watering-plant');
129144

130145
// The inner app's Sentry middleware must not add a middleware span.
131-
const middlewareNames = spans.filter(span => span.op === 'middleware').map(span => span.description);
146+
const middlewareNames = container.items.filter(item => op(item) === 'middleware').map(item => item.name);
132147
expect(middlewareNames).not.toContain('<anonymous>');
133148
},
134149
})
@@ -139,7 +154,7 @@ describe('hono auto-instrumentation', () => {
139154

140155
test('captures an error thrown after an internal .request() with the outer request data', async () => {
141156
const runner = createRunner()
142-
.ignore('transaction')
157+
.unordered()
143158
.expect({
144159
event: event => {
145160
expect(event.exception?.values?.[0]?.value).toBe('Test error from outer Hono app after internal request');

0 commit comments

Comments
 (0)