Skip to content

Commit fe8a4a3

Browse files
chargomeclaude
andauthored
test(e2e): Port the nestjs-microservices E2E app to span streaming (#24104)
Removes the `traceLifecycle: 'static'` pin and rewrites the specs against streamed spans. The specs that documented microservice spans arriving as standalone transactions now document them arriving as segment spans of their own traces; the underlying missing trace propagation is unchanged. Ref: #23801 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent e8b8328 commit fe8a4a3

3 files changed

Lines changed: 34 additions & 49 deletions

File tree

‎dev-packages/e2e-tests/test-applications/nestjs-microservices/src/instrument.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as Sentry from '@sentry/nestjs';
22

33
Sentry.init({
4-
traceLifecycle: 'static',
54
environment: 'qa',
65
dsn: process.env.E2E_TEST_DSN,
76
tunnel: `http://localhost:3031/`,

‎dev-packages/e2e-tests/test-applications/nestjs-microservices/tests/errors.test.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from '@playwright/test';
2-
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
2+
import { waitForError, waitForStreamedSpan } from '@sentry-internal/test-utils';
33

44
test('Captures manually reported error in microservice handler', async ({ baseURL }) => {
55
const errorEventPromise = waitForError('nestjs-microservices', event => {
@@ -15,7 +15,7 @@ test('Captures manually reported error in microservice handler', async ({ baseUR
1515
});
1616

1717
// To verify that an exception is NOT automatically captured, we trigger it,
18-
// wait for the transaction from that request to confirm it completed, flush,
18+
// wait for the segment span from that request to confirm it completed, flush,
1919
// and then assert no error event was received.
2020
test('Does not automatically capture exceptions thrown in microservice handler', async ({ baseURL }) => {
2121
let autoCaptureFired = false;
@@ -27,13 +27,13 @@ test('Does not automatically capture exceptions thrown in microservice handler',
2727
return false;
2828
});
2929

30-
const transactionPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
31-
return transactionEvent?.transaction === 'GET /test-microservice-exception/:id';
30+
const segmentSpanPromise = waitForStreamedSpan('nestjs-microservices', span => {
31+
return span.is_segment && span.name === 'GET /test-microservice-exception/:id';
3232
});
3333

3434
await fetch(`${baseURL}/test-microservice-exception/123`);
3535

36-
await transactionPromise;
36+
await segmentSpanPromise;
3737

3838
await fetch(`${baseURL}/flush`);
3939

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,71 @@
11
import { expect, test } from '@playwright/test';
2-
import { waitForTransaction } from '@sentry-internal/test-utils';
3-
4-
test('Sends an HTTP transaction', async ({ baseURL }) => {
5-
const transactionEventPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
6-
return (
7-
transactionEvent?.contexts?.trace?.op === 'http.server' &&
8-
transactionEvent?.transaction === 'GET /test-transaction'
9-
);
2+
import { collectStreamedSpansUntilSegment, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
3+
4+
const APP_NAME = 'nestjs-microservices';
5+
6+
test('Sends an HTTP segment span', async ({ baseURL }) => {
7+
const spanPromise = waitForStreamedSpan(APP_NAME, span => {
8+
return span.is_segment && span.name === 'GET /test-transaction';
109
});
1110

1211
const response = await fetch(`${baseURL}/test-transaction`);
1312
expect(response.status).toBe(200);
1413

15-
const transactionEvent = await transactionEventPromise;
14+
const span = await spanPromise;
1615

17-
expect(transactionEvent.contexts?.trace).toEqual(
18-
expect.objectContaining({
19-
op: 'http.server',
20-
status: 'ok',
21-
}),
22-
);
16+
expect(getSpanOp(span)).toBe('http.server');
17+
expect(span.status).toBe('ok');
2318
});
2419

2520
// Trace context does not propagate over NestJS TCP transport, so RPC spans are disconnected from
26-
// the HTTP transaction. Instead of appearing as child spans of the HTTP transaction, auto-instrumented
27-
// NestJS guard/interceptor/pipe spans become separate standalone transactions.
21+
// the HTTP trace. Instead of appearing as child spans of the HTTP segment span, auto-instrumented
22+
// NestJS guard/interceptor/pipe spans become segment spans of their own traces.
2823
// This documents the current (broken) behavior — ideally these should be connected to the HTTP trace.
2924

30-
test('Microservice spans are not connected to the HTTP transaction', async ({ baseURL }) => {
31-
const httpTransactionPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
32-
return (
33-
transactionEvent?.contexts?.trace?.op === 'http.server' &&
34-
transactionEvent?.transaction === 'GET /test-microservice-sum'
35-
);
36-
});
25+
test('Microservice spans are not connected to the HTTP trace', async ({ baseURL }) => {
26+
const spansPromise = collectStreamedSpansUntilSegment(APP_NAME, 'GET /test-microservice-sum');
3727

3828
const response = await fetch(`${baseURL}/test-microservice-sum`);
3929
expect(response.status).toBe(200);
4030

41-
const httpTransaction = await httpTransactionPromise;
31+
const spans = await spansPromise;
4232

43-
// The microservice span should be part of this transaction but isn't due to missing trace propagation
44-
const microserviceSpan = httpTransaction.spans?.find(span => span.description === 'microservice-sum-operation');
45-
expect(microserviceSpan).toBeUndefined();
33+
// The microservice span should be part of this trace but isn't due to missing trace propagation
34+
expect(spans.find(span => span.name === 'microservice-sum-operation')).toBeUndefined();
4635
});
4736

48-
test('Microservice guard is emitted as a standalone transaction instead of being part of the HTTP trace', async ({
37+
test('Microservice guard is emitted as a segment span of its own trace instead of being part of the HTTP trace', async ({
4938
baseURL,
5039
}) => {
51-
const guardTransactionPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
52-
return transactionEvent?.transaction === 'ExampleGuard';
40+
const guardSpanPromise = waitForStreamedSpan(APP_NAME, span => {
41+
return span.is_segment && span.name === 'ExampleGuard';
5342
});
5443

5544
await fetch(`${baseURL}/test-microservice-guard`);
5645

57-
const guardTransaction = await guardTransactionPromise;
58-
expect(guardTransaction).toBeDefined();
46+
expect(await guardSpanPromise).toBeDefined();
5947
});
6048

61-
test('Microservice interceptor is emitted as a standalone transaction instead of being part of the HTTP trace', async ({
49+
test('Microservice interceptor is emitted as a segment span of its own trace instead of being part of the HTTP trace', async ({
6250
baseURL,
6351
}) => {
64-
const interceptorTransactionPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
65-
return transactionEvent?.transaction === 'ExampleInterceptor';
52+
const interceptorSpanPromise = waitForStreamedSpan(APP_NAME, span => {
53+
return span.is_segment && span.name === 'ExampleInterceptor';
6654
});
6755

6856
await fetch(`${baseURL}/test-microservice-interceptor`);
6957

70-
const interceptorTransaction = await interceptorTransactionPromise;
71-
expect(interceptorTransaction).toBeDefined();
58+
expect(await interceptorSpanPromise).toBeDefined();
7259
});
7360

74-
test('Microservice pipe is emitted as a standalone transaction instead of being part of the HTTP trace', async ({
61+
test('Microservice pipe is emitted as a segment span of its own trace instead of being part of the HTTP trace', async ({
7562
baseURL,
7663
}) => {
77-
const pipeTransactionPromise = waitForTransaction('nestjs-microservices', transactionEvent => {
78-
return transactionEvent?.transaction === 'ExamplePipe';
64+
const pipeSpanPromise = waitForStreamedSpan(APP_NAME, span => {
65+
return span.is_segment && span.name === 'ExamplePipe';
7966
});
8067

8168
await fetch(`${baseURL}/test-microservice-pipe`);
8269

83-
const pipeTransaction = await pipeTransactionPromise;
84-
expect(pipeTransaction).toBeDefined();
70+
expect(await pipeSpanPromise).toBeDefined();
8571
});

0 commit comments

Comments
 (0)