Skip to content

Commit 41a6b67

Browse files
committed
test(node): New ee2e test runner
1 parent d41e39e commit 41a6b67

File tree

12 files changed

+441
-310
lines changed

12 files changed

+441
-310
lines changed

dev-packages/node-integration-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"type-check": "tsc",
1616
"pretest": "run-s --silent prisma:init prisma:init:new",
1717
"test": "ts-node ./utils/run-tests.ts",
18+
"jest": "jest --config ./jest.config.js",
1819
"test:watch": "yarn test --watch"
1920
},
2021
"dependencies": {
Lines changed: 172 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,188 +1,176 @@
1-
import * as childProcess from 'child_process';
2-
import * as path from 'path';
3-
import type { Event } from '@sentry/node';
4-
import type { SerializedSession } from '@sentry/types';
51
import { conditionalTest } from '../../utils';
6-
7-
/** The output will contain logging so we need to find the line that parses as JSON */
8-
function parseJsonLines<T extends unknown[]>(input: string, expected: number): T {
9-
const results = input
10-
.split('\n')
11-
.map(line => {
12-
const trimmed = line.startsWith('[ANR Worker] ') ? line.slice(13) : line;
13-
try {
14-
return JSON.parse(trimmed) as T;
15-
} catch {
16-
return undefined;
17-
}
18-
})
19-
.filter(a => a) as T;
20-
21-
expect(results.length).toEqual(expected);
22-
23-
return results;
24-
}
2+
import { assertSentryEvent, assertSentrySession, createRunner } from '../../utils/runner';
3+
4+
const ANR_TEST_TIMEOUT = 10_000;
5+
6+
const EXPECTED_ANR_EVENT = {
7+
// Ensure we have context
8+
contexts: {
9+
trace: {
10+
span_id: expect.any(String),
11+
trace_id: expect.any(String),
12+
},
13+
device: {
14+
arch: expect.any(String),
15+
},
16+
app: {
17+
app_start_time: expect.any(String),
18+
},
19+
os: {
20+
name: expect.any(String),
21+
},
22+
culture: {
23+
timezone: expect.any(String),
24+
},
25+
},
26+
// and an exception that is our ANR
27+
exception: {
28+
values: [
29+
{
30+
type: 'ApplicationNotResponding',
31+
value: 'Application Not Responding for at least 200 ms',
32+
mechanism: { type: 'ANR' },
33+
stacktrace: {
34+
frames: expect.arrayContaining([
35+
{
36+
colno: expect.any(Number),
37+
lineno: expect.any(Number),
38+
filename: expect.any(String),
39+
function: '?',
40+
in_app: true,
41+
},
42+
{
43+
colno: expect.any(Number),
44+
lineno: expect.any(Number),
45+
filename: expect.any(String),
46+
function: 'longWork',
47+
in_app: true,
48+
},
49+
]),
50+
},
51+
},
52+
],
53+
},
54+
};
2555

2656
conditionalTest({ min: 16 })('should report ANR when event loop blocked', () => {
27-
test('CJS', done => {
28-
expect.assertions(13);
29-
30-
const testScriptPath = path.resolve(__dirname, 'basic.js');
31-
32-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
33-
const [event] = parseJsonLines<[Event]>(stdout, 1);
34-
35-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
36-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
37-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
38-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThan(4);
39-
40-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
41-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
42-
43-
expect(event.contexts?.trace?.trace_id).toBeDefined();
44-
expect(event.contexts?.trace?.span_id).toBeDefined();
45-
46-
expect(event.contexts?.device?.arch).toBeDefined();
47-
expect(event.contexts?.app?.app_start_time).toBeDefined();
48-
expect(event.contexts?.os?.name).toBeDefined();
49-
expect(event.contexts?.culture?.timezone).toBeDefined();
50-
51-
done();
52-
});
53-
});
54-
55-
test('Legacy API', done => {
56-
// TODO (v8): Remove this old API and this test
57-
expect.assertions(9);
58-
59-
const testScriptPath = path.resolve(__dirname, 'legacy.js');
60-
61-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
62-
const [event] = parseJsonLines<[Event]>(stdout, 1);
63-
64-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
65-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
66-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
67-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThan(4);
68-
69-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
70-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
71-
72-
expect(event.contexts?.trace?.trace_id).toBeDefined();
73-
expect(event.contexts?.trace?.span_id).toBeDefined();
74-
75-
done();
76-
});
77-
});
78-
79-
test('ESM', done => {
80-
expect.assertions(7);
81-
82-
const testScriptPath = path.resolve(__dirname, 'basic.mjs');
83-
84-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
85-
const [event] = parseJsonLines<[Event]>(stdout, 1);
86-
87-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
88-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
89-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
90-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThanOrEqual(4);
91-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
92-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
93-
94-
done();
95-
});
96-
});
97-
98-
test('With --inspect', done => {
99-
expect.assertions(7);
100-
101-
const testScriptPath = path.resolve(__dirname, 'basic.js');
102-
103-
childProcess.exec(`node --inspect ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
104-
const [event] = parseJsonLines<[Event]>(stdout, 1);
105-
106-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
107-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
108-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
109-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThan(4);
110-
111-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
112-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
113-
114-
done();
115-
});
116-
});
117-
118-
test('should exit', done => {
119-
const testScriptPath = path.resolve(__dirname, 'should-exit.js');
120-
let hasClosed = false;
121-
122-
setTimeout(() => {
123-
expect(hasClosed).toBe(true);
124-
done();
125-
}, 5_000);
126-
127-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, () => {
128-
hasClosed = true;
129-
});
130-
});
131-
132-
test('should exit forced', done => {
133-
const testScriptPath = path.resolve(__dirname, 'should-exit-forced.js');
134-
let hasClosed = false;
135-
136-
setTimeout(() => {
137-
expect(hasClosed).toBe(true);
138-
done();
139-
}, 5_000);
140-
141-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, () => {
142-
hasClosed = true;
143-
});
144-
});
145-
146-
test('With session', done => {
147-
expect.assertions(9);
148-
149-
const testScriptPath = path.resolve(__dirname, 'basic-session.js');
150-
151-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
152-
const [session, event] = parseJsonLines<[SerializedSession, Event]>(stdout, 2);
153-
154-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
155-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
156-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
157-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThan(4);
158-
159-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
160-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
161-
162-
expect(session.status).toEqual('abnormal');
163-
expect(session.abnormal_mechanism).toEqual('anr_foreground');
164-
165-
done();
166-
});
167-
});
168-
169-
test('from forked process', done => {
170-
expect.assertions(7);
171-
172-
const testScriptPath = path.resolve(__dirname, 'forker.js');
173-
174-
childProcess.exec(`node ${testScriptPath}`, { encoding: 'utf8' }, (_, stdout) => {
175-
const [event] = parseJsonLines<[Event]>(stdout, 1);
176-
177-
expect(event.exception?.values?.[0].mechanism).toEqual({ type: 'ANR' });
178-
expect(event.exception?.values?.[0].type).toEqual('ApplicationNotResponding');
179-
expect(event.exception?.values?.[0].value).toEqual('Application Not Responding for at least 200 ms');
180-
expect(event.exception?.values?.[0].stacktrace?.frames?.length).toBeGreaterThan(4);
181-
182-
expect(event.exception?.values?.[0].stacktrace?.frames?.[2].function).toEqual('?');
183-
expect(event.exception?.values?.[0].stacktrace?.frames?.[3].function).toEqual('longWork');
184-
185-
done();
186-
});
187-
});
57+
test(
58+
'CJS',
59+
done => {
60+
createRunner(__dirname, 'basic.js')
61+
.expect({
62+
event: event => {
63+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
64+
},
65+
})
66+
.start(done);
67+
},
68+
ANR_TEST_TIMEOUT,
69+
);
70+
71+
// TODO (v8): Remove this old API and this test
72+
test(
73+
'Legacy API',
74+
done => {
75+
createRunner(__dirname, 'legacy.js')
76+
.expect({
77+
event: event => {
78+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
79+
},
80+
})
81+
.start(done);
82+
},
83+
ANR_TEST_TIMEOUT,
84+
);
85+
86+
test(
87+
'ESM',
88+
done => {
89+
createRunner(__dirname, 'basic.mjs')
90+
.expect({
91+
event: event => {
92+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
93+
},
94+
})
95+
.start(done);
96+
},
97+
ANR_TEST_TIMEOUT,
98+
);
99+
100+
test(
101+
'With --inspect',
102+
done => {
103+
createRunner(__dirname, 'basic.mjs')
104+
.withFlags('--inspect')
105+
.expect({
106+
event: event => {
107+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
108+
},
109+
})
110+
.start(done);
111+
},
112+
ANR_TEST_TIMEOUT,
113+
);
114+
115+
test(
116+
'should exit',
117+
done => {
118+
const runner = createRunner(__dirname, 'should-exit.js').start();
119+
120+
setTimeout(() => {
121+
expect(runner.childHasExited()).toBe(true);
122+
done();
123+
}, 5_000);
124+
},
125+
ANR_TEST_TIMEOUT,
126+
);
127+
128+
test(
129+
'should exit forced',
130+
done => {
131+
const runner = createRunner(__dirname, 'should-exit-forced.js').start();
132+
133+
setTimeout(() => {
134+
expect(runner.childHasExited()).toBe(true);
135+
done();
136+
}, 5_000);
137+
},
138+
ANR_TEST_TIMEOUT,
139+
);
140+
141+
test(
142+
'With session',
143+
done => {
144+
createRunner(__dirname, 'basic-session.js')
145+
.expect({
146+
session: session => {
147+
assertSentrySession(session, {
148+
status: 'abnormal',
149+
abnormal_mechanism: 'anr_foreground',
150+
});
151+
},
152+
})
153+
.expect({
154+
event: event => {
155+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
156+
},
157+
})
158+
.start(done);
159+
},
160+
ANR_TEST_TIMEOUT,
161+
);
162+
163+
test(
164+
'from forked process',
165+
done => {
166+
createRunner(__dirname, 'forker.js')
167+
.expect({
168+
event: event => {
169+
assertSentryEvent(event, EXPECTED_ANR_EVENT);
170+
},
171+
})
172+
.start(done);
173+
},
174+
ANR_TEST_TIMEOUT,
175+
);
188176
});

dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-caught.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
/* eslint-disable no-unused-vars */
22
const Sentry = require('@sentry/node');
3+
const { loggingTransport } = require('@sentry/utils');
34

45
Sentry.init({
56
dsn: 'https://[email protected]/1337',
67
includeLocalVariables: true,
7-
beforeSend: event => {
8-
// eslint-disable-next-line no-console
9-
console.log(JSON.stringify(event));
10-
},
8+
transport: loggingTransport,
119
});
1210

1311
class Some {

0 commit comments

Comments
 (0)