Skip to content

Commit 335da37

Browse files
authored
test: Make node integration test runner more resilient (#14245)
Noticed while debugging some test problems, that if axios throws an error (e.g. you get a 500 error), jest cannot serialize the error because it contains recursive data, leading to super hard to debug error messages. This makes our node integration test runner more resilient by normalizing errors we get there to ensure circular references are resolved. ## Update While working on this, I found some further, actually more serious problems - some tests were simply not running at all. Especially all the session aggregrate tests were simply not being run and just "passed" accidentally. The core problem there was that the path to the scenario was incorrect, so nothing was even started, plus some things where we seemed to catch errors and still pass (?? I do not think I fixed all of the issues there, but at least some of them...) Now, we assert that the scenario file actually exists. Plus, instead of setting `.expectError()` on the whole runner, you now have to pass this to a specific `makeRequest` call as an optional option, and it will also assert if we expect an error _but do not get one_. This way, the tests can be more explicit and clear in what they do.
1 parent 6d1a251 commit 335da37

File tree

21 files changed

+290
-284
lines changed

21 files changed

+290
-284
lines changed

dev-packages/node-integration-tests/README.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,11 @@ suites/
1414
|---- scenario_2.ts [optional extra test scenario]
1515
|---- server_with_mongo.ts [optional custom server]
1616
|---- server_with_postgres.ts [optional custom server]
17-
utils/
18-
|---- defaults/
19-
|---- server.ts [default Express server configuration]
2017
```
2118

2219
The tests are grouped by their scopes, such as `public-api` or `tracing`. In every group of tests, there are multiple
2320
folders containing test scenarios and assertions.
2421

25-
Tests run on Express servers (a server instance per test). By default, a simple server template inside
26-
`utils/defaults/server.ts` is used. Every server instance runs on a different port.
27-
28-
A custom server configuration can be used, supplying a script that exports a valid express server instance as default.
29-
`runServer` utility function accepts an optional `serverPath` argument for this purpose.
30-
3122
`scenario.ts` contains the initialization logic and the test subject. By default, `{TEST_DIR}/scenario.ts` is used, but
3223
`runServer` also accepts an optional `scenarioPath` argument for non-standard usage.
3324

dev-packages/node-integration-tests/suites/express/handle-error-scope-data-loss/test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ afterAll(() => {
1414
* This test nevertheless covers the behavior so that we're aware.
1515
*/
1616
test('withScope scope is NOT applied to thrown error caught by global handler', done => {
17-
const runner = createRunner(__dirname, 'server.ts')
17+
createRunner(__dirname, 'server.ts')
1818
.expect({
1919
event: {
2020
exception: {
@@ -42,16 +42,15 @@ test('withScope scope is NOT applied to thrown error caught by global handler',
4242
tags: expect.not.objectContaining({ local: expect.anything() }),
4343
},
4444
})
45-
.start(done);
46-
47-
expect(() => runner.makeRequest('get', '/test/withScope')).rejects.toThrow();
45+
.start(done)
46+
.makeRequest('get', '/test/withScope', { expectError: true });
4847
});
4948

5049
/**
5150
* This test shows that the isolation scope set tags are applied correctly to the error.
5251
*/
5352
test('isolation scope is applied to thrown error caught by global handler', done => {
54-
const runner = createRunner(__dirname, 'server.ts')
53+
createRunner(__dirname, 'server.ts')
5554
.expect({
5655
event: {
5756
exception: {
@@ -81,7 +80,6 @@ test('isolation scope is applied to thrown error caught by global handler', done
8180
},
8281
},
8382
})
84-
.start(done);
85-
86-
expect(() => runner.makeRequest('get', '/test/isolationScope')).rejects.toThrow();
83+
.start(done)
84+
.makeRequest('get', '/test/isolationScope', { expectError: true });
8785
});

dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-0/test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ afterAll(() => {
55
});
66

77
test('should capture and send Express controller error with txn name if tracesSampleRate is 0', done => {
8-
const runner = createRunner(__dirname, 'server.ts')
8+
createRunner(__dirname, 'server.ts')
99
.ignore('transaction')
1010
.expect({
1111
event: {
@@ -33,7 +33,6 @@ test('should capture and send Express controller error with txn name if tracesSa
3333
transaction: 'GET /test/express/:id',
3434
},
3535
})
36-
.start(done);
37-
38-
expect(() => runner.makeRequest('get', '/test/express/123')).rejects.toThrow();
36+
.start(done)
37+
.makeRequest('get', '/test/express/123', { expectError: true });
3938
});

dev-packages/node-integration-tests/suites/express/handle-error-tracesSampleRate-unset/test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ afterAll(() => {
55
});
66

77
test('should capture and send Express controller error if tracesSampleRate is not set.', done => {
8-
const runner = createRunner(__dirname, 'server.ts')
8+
createRunner(__dirname, 'server.ts')
99
.ignore('transaction')
1010
.expect({
1111
event: {
@@ -32,7 +32,6 @@ test('should capture and send Express controller error if tracesSampleRate is no
3232
},
3333
},
3434
})
35-
.start(done);
36-
37-
expect(() => runner.makeRequest('get', '/test/express/123')).rejects.toThrow();
35+
.start(done)
36+
.makeRequest('get', '/test/express/123', { expectError: true });
3837
});

dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-assign/test.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ test('Should overwrite baggage if the incoming request already has Sentry baggag
99
const runner = createRunner(__dirname, '..', 'server.ts').start();
1010

1111
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
12-
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv',
12+
headers: {
13+
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv',
14+
},
1315
});
1416

1517
expect(response).toBeDefined();
@@ -25,8 +27,10 @@ test('Should propagate sentry trace baggage data from an incoming to an outgoing
2527
const runner = createRunner(__dirname, '..', 'server.ts').start();
2628

2729
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
28-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
29-
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv,dogs=great',
30+
headers: {
31+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
32+
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv,dogs=great',
33+
},
3034
});
3135

3236
expect(response).toBeDefined();
@@ -42,8 +46,10 @@ test('Should not propagate baggage data from an incoming to an outgoing request
4246
const runner = createRunner(__dirname, '..', 'server.ts').start();
4347

4448
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
45-
'sentry-trace': '',
46-
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv,dogs=great',
49+
headers: {
50+
'sentry-trace': '',
51+
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv,dogs=great',
52+
},
4753
});
4854

4955
expect(response).toBeDefined();
@@ -59,7 +65,9 @@ test('Should not propagate baggage if sentry-trace header is present in incoming
5965
const runner = createRunner(__dirname, '..', 'server.ts').start();
6066

6167
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
62-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
68+
headers: {
69+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
70+
},
6371
});
6472

6573
expect(response).toBeDefined();
@@ -74,8 +82,10 @@ test('Should not propagate baggage and ignore original 3rd party baggage entries
7482
const runner = createRunner(__dirname, '..', 'server.ts').start();
7583

7684
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
77-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
78-
baggage: 'foo=bar',
85+
headers: {
86+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
87+
baggage: 'foo=bar',
88+
},
7989
});
8090

8191
expect(response).toBeDefined();
@@ -107,7 +117,9 @@ test('Should populate Sentry and ignore 3rd party content if sentry-trace header
107117
const runner = createRunner(__dirname, '..', 'server.ts').start();
108118

109119
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
110-
baggage: 'foo=bar,bar=baz',
120+
headers: {
121+
baggage: 'foo=bar,bar=baz',
122+
},
111123
});
112124

113125
expect(response).toBeDefined();

dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-other-vendors-with-sentry-entries/test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ test('should ignore sentry-values in `baggage` header of a third party vendor an
99
const runner = createRunner(__dirname, 'server.ts').start();
1010

1111
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
12-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
13-
baggage: 'sentry-release=2.1.0,sentry-environment=myEnv',
12+
headers: {
13+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
14+
baggage: 'sentry-release=2.1.0,sentry-environment=myEnv',
15+
},
1416
});
1517

1618
expect(response).toBeDefined();

dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-other-vendors/test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ test('should merge `baggage` header of a third party vendor with the Sentry DSC
99
const runner = createRunner(__dirname, 'server.ts').start();
1010

1111
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
12-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
13-
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv',
12+
headers: {
13+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-1',
14+
baggage: 'sentry-release=2.0.0,sentry-environment=myEnv',
15+
},
1416
});
1517

1618
expect(response).toBeDefined();

dev-packages/node-integration-tests/suites/express/sentry-trace/trace-header-assign/test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ test('Should assign `sentry-trace` header which sets parent trace id of an outgo
1010
const runner = createRunner(__dirname, 'server.ts').start();
1111

1212
const response = await runner.makeRequest<TestAPIResponse>('get', '/test/express', {
13-
'sentry-trace': '12312012123120121231201212312012-1121201211212012-0',
13+
headers: {
14+
'sentry-trace': '12312012123120121231201212312012-1121201211212012-0',
15+
},
1416
});
1517

1618
expect(response).toBeDefined();

dev-packages/node-integration-tests/suites/express/setupExpressErrorHandler/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ describe('express setupExpressErrorHandler', () => {
2222
.start(done);
2323

2424
// this error is filtered & ignored
25-
expect(() => runner.makeRequest('get', '/test1')).rejects.toThrow();
25+
runner.makeRequest('get', '/test1', { expectError: true });
2626
// this error is actually captured
27-
expect(() => runner.makeRequest('get', '/test2')).rejects.toThrow();
27+
runner.makeRequest('get', '/test2', { expectError: true });
2828
});
2929
});
3030
});

dev-packages/node-integration-tests/suites/public-api/startSpan/with-nested-spans/test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { SpanJSON } from '@sentry/types';
2-
import { assertSentryTransaction, cleanupChildProcesses, createRunner } from '../../../../utils/runner';
2+
import { assertSentryTransaction } from '../../../../utils/assertions';
3+
import { cleanupChildProcesses, createRunner } from '../../../../utils/runner';
34

45
afterAll(() => {
56
cleanupChildProcesses();

dev-packages/node-integration-tests/suites/sessions/crashed-session-aggregate/test.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ afterEach(() => {
44
cleanupChildProcesses();
55
});
66

7-
test('should aggregate successful and crashed sessions', async () => {
8-
let _done: undefined | (() => void);
9-
const promise = new Promise<void>(resolve => {
10-
_done = resolve;
11-
});
12-
13-
const runner = createRunner(__dirname, 'server.ts')
7+
test('should aggregate successful and crashed sessions', done => {
8+
const runner = createRunner(__dirname, '..', 'server.ts')
149
.ignore('transaction', 'event')
1510
.unignore('sessions')
16-
.expectError()
1711
.expect({
1812
sessions: {
1913
aggregates: [
@@ -25,11 +19,9 @@ test('should aggregate successful and crashed sessions', async () => {
2519
],
2620
},
2721
})
28-
.start(_done);
29-
30-
runner.makeRequest('get', '/success');
31-
runner.makeRequest('get', '/error_unhandled');
32-
runner.makeRequest('get', '/success_next');
22+
.start(done);
3323

34-
await promise;
24+
runner.makeRequest('get', '/test/success');
25+
runner.makeRequest('get', '/test/error_unhandled', { expectError: true });
26+
runner.makeRequest('get', '/test/success_next');
3527
});

dev-packages/node-integration-tests/suites/sessions/errored-session-aggregate/test.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ afterEach(() => {
44
cleanupChildProcesses();
55
});
66

7-
test('should aggregate successful, crashed and erroneous sessions', async () => {
8-
let _done: undefined | (() => void);
9-
const promise = new Promise<void>(resolve => {
10-
_done = resolve;
11-
});
12-
13-
const runner = createRunner(__dirname, 'server.ts')
7+
test('should aggregate successful, crashed and erroneous sessions', done => {
8+
const runner = createRunner(__dirname, '..', 'server.ts')
149
.ignore('transaction', 'event')
1510
.unignore('sessions')
16-
.expectError()
1711
.expect({
1812
sessions: {
1913
aggregates: [
@@ -26,11 +20,9 @@ test('should aggregate successful, crashed and erroneous sessions', async () =>
2620
],
2721
},
2822
})
29-
.start(_done);
30-
31-
runner.makeRequest('get', '/success');
32-
runner.makeRequest('get', '/error_handled');
33-
runner.makeRequest('get', '/error_unhandled');
23+
.start(done);
3424

35-
await promise;
25+
runner.makeRequest('get', '/test/success');
26+
runner.makeRequest('get', '/test/error_handled');
27+
runner.makeRequest('get', '/test/error_unhandled', { expectError: true });
3628
});

dev-packages/node-integration-tests/suites/sessions/exited-session-aggregate/test.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ afterEach(() => {
44
cleanupChildProcesses();
55
});
66

7-
test('should aggregate successful sessions', async () => {
8-
let _done: undefined | (() => void);
9-
const promise = new Promise<void>(resolve => {
10-
_done = resolve;
11-
});
12-
13-
const runner = createRunner(__dirname, 'server.ts')
7+
test('should aggregate successful sessions', done => {
8+
const runner = createRunner(__dirname, '..', 'server.ts')
149
.ignore('transaction', 'event')
1510
.unignore('sessions')
16-
.expectError()
1711
.expect({
1812
sessions: {
1913
aggregates: [
@@ -24,11 +18,9 @@ test('should aggregate successful sessions', async () => {
2418
],
2519
},
2620
})
27-
.start(_done);
28-
29-
runner.makeRequest('get', '/success');
30-
runner.makeRequest('get', '/success_next');
31-
runner.makeRequest('get', '/success_slow');
21+
.start(done);
3222

33-
await promise;
23+
runner.makeRequest('get', '/test/success');
24+
runner.makeRequest('get', '/test/success_next');
25+
runner.makeRequest('get', '/test/success_slow');
3426
});

dev-packages/node-integration-tests/suites/sessions/server.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
1+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
12
import type { SessionFlusher } from '@sentry/core';
23
import * as Sentry from '@sentry/node';
34

45
Sentry.init({
56
dsn: 'https://public@dsn.ingest.sentry.io/1337',
67
release: '1.0',
8+
transport: loggingTransport,
79
});
810

11+
import { startExpressServerAndSendPortToRunner } from '@sentry-internal/node-integration-tests';
912
import express from 'express';
1013

1114
const app = express();
1215

13-
// ### Taken from manual tests ###
14-
// Hack that resets the 60s default flush interval, and replaces it with just a one second interval
1516
const flusher = (Sentry.getClient() as Sentry.NodeClient)['_sessionFlusher'] as SessionFlusher;
1617

17-
let flusherIntervalId = flusher && flusher['_intervalId'];
18-
19-
clearInterval(flusherIntervalId);
20-
21-
flusherIntervalId = flusher['_intervalId'] = setInterval(() => flusher?.flush(), 2000);
22-
23-
setTimeout(() => clearInterval(flusherIntervalId), 4000);
18+
// Flush after 2 seconds (to avoid waiting for the default 60s)
19+
setTimeout(() => {
20+
flusher?.flush();
21+
}, 2000);
2422

2523
app.get('/test/success', (_req, res) => {
2624
res.send('Success!');
@@ -52,4 +50,4 @@ app.get('/test/error_handled', (_req, res) => {
5250

5351
Sentry.setupExpressErrorHandler(app);
5452

55-
export default app;
53+
startExpressServerAndSendPortToRunner(app);

dev-packages/node-integration-tests/suites/tracing/connect/test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ describe('connect auto-instrumentation', () => {
4545
test('CJS - should capture errors in `connect` middleware.', done => {
4646
createRunner(__dirname, 'scenario.js')
4747
.ignore('transaction')
48-
.expectError()
4948
.expect({ event: EXPECTED_EVENT })
5049
.start(done)
5150
.makeRequest('get', '/error');
@@ -55,7 +54,6 @@ describe('connect auto-instrumentation', () => {
5554
createRunner(__dirname, 'scenario.js')
5655
.ignore('event')
5756
.expect({ transaction: { transaction: 'GET /error' } })
58-
.expectError()
5957
.start(done)
6058
.makeRequest('get', '/error');
6159
});

0 commit comments

Comments
 (0)