Skip to content

Commit eddad36

Browse files
test(node): Document Node integration tests. (#4791)
Co-authored-by: Abhijeet Prasad <aprasad@sentry.io>
1 parent 99aa705 commit eddad36

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Integration Tests for Sentry Node.JS SDK
2+
3+
## Structure
4+
5+
```
6+
suites/
7+
|---- public-api/
8+
|---- captureMessage/
9+
|---- test.ts [assertions]
10+
|---- scenario.ts [Sentry initialization and test subject]
11+
|---- customTest/
12+
|---- test.ts [assertions]
13+
|---- scenario_1.ts [optional extra test scenario]
14+
|---- scenario_2.ts [optional extra test scenario]
15+
|---- server_with_mongo.ts [optional custom server]
16+
|---- server_with_postgres.ts [optional custom server]
17+
utils/
18+
|---- defaults/
19+
|---- server.ts [default Express server configuration]
20+
```
21+
22+
The tests are grouped by their scopes, such as `public-api` or `tracing`. In every group of tests, there are multiple folders containing test scenarios and assertions.
23+
24+
Tests run on Express servers (a server instance per test). By default, a simple server template inside `utils/defaults/server.ts` is used. Every server instance runs on a different port.
25+
26+
A custom server configuration can be used, supplying a script that exports a valid express server instance as default. `runServer` utility function accepts an optional `serverPath` argument for this purpose.
27+
28+
`scenario.ts` contains the initialization logic and the test subject. By default, `{TEST_DIR}/scenario.ts` is used, but `runServer` also accepts an optional `scenarioPath` argument for non-standard usage.
29+
30+
`test.ts` is required for each test case, and contains the server runner logic, request interceptors for Sentry requests, and assertions. Test server, interceptors and assertions are all run on the same Jest thread.
31+
32+
### Utilities
33+
34+
`utils/` contains helpers and Sentry-specific assertions that can be used in (`test.ts`).
35+
36+
## Running Tests Locally
37+
38+
Tests can be run locally with:
39+
40+
`yarn test`
41+
42+
To run tests with Jest's watch mode:
43+
44+
`yarn test:jest`
45+
46+
To filter tests by their title:
47+
48+
`yarn test -t "set different properties of a scope"`
49+
50+
You can refer to [Jest documentation](https://jestjs.io/docs/cli) for other CLI options.

packages/node-integration-tests/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"lint:eslint": "eslint . --cache --cache-location '../../eslintcache/' --format stylish",
1212
"lint:prettier": "prettier --check \"{suites,utils}/**/*.ts\"",
1313
"type-check": "tsc",
14-
"test": "jest --detectOpenHandles --runInBand --forceExit"
14+
"test": "jest --detectOpenHandles --runInBand --forceExit",
15+
"test:watch": "yarn test --watch"
1516
},
1617
"dependencies": {
1718
"express": "^4.17.3",

packages/node-integration-tests/utils/index.ts

+45
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import nock from 'nock';
55
import * as path from 'path';
66
import { getPortPromise } from 'portfinder';
77

8+
/**
9+
* Asserts against a Sentry Event ignoring non-deterministic properties
10+
*
11+
* @param {Record<string, unknown>} actual
12+
* @param {Record<string, unknown>} expected
13+
*/
814
export const assertSentryEvent = (actual: Record<string, unknown>, expected: Record<string, unknown>): void => {
915
expect(actual).toMatchObject({
1016
event_id: expect.any(String),
@@ -13,6 +19,12 @@ export const assertSentryEvent = (actual: Record<string, unknown>, expected: Rec
1319
});
1420
};
1521

22+
/**
23+
* Asserts against a Sentry Transaction ignoring non-deterministic properties
24+
*
25+
* @param {Record<string, unknown>} actual
26+
* @param {Record<string, unknown>} expected
27+
*/
1628
export const assertSentryTransaction = (actual: Record<string, unknown>, expected: Record<string, unknown>): void => {
1729
expect(actual).toMatchObject({
1830
event_id: expect.any(String),
@@ -24,10 +36,23 @@ export const assertSentryTransaction = (actual: Record<string, unknown>, expecte
2436
});
2537
};
2638

39+
/**
40+
* Parses response body containing an Envelope
41+
*
42+
* @param {string} body
43+
* @return {*} {Array<Record<string, unknown>>}
44+
*/
2745
export const parseEnvelope = (body: string): Array<Record<string, unknown>> => {
2846
return body.split('\n').map(e => JSON.parse(e));
2947
};
3048

49+
/**
50+
* Intercepts and extracts multiple requests containing a Sentry Event
51+
*
52+
* @param {string} url
53+
* @param {number} count
54+
* @return {*} {Promise<Array<Record<string, unknown>>>}
55+
*/
3156
export const getMultipleEventRequests = async (url: string, count: number): Promise<Array<Record<string, unknown>>> => {
3257
const events: Record<string, unknown>[] = [];
3358

@@ -47,10 +72,22 @@ export const getMultipleEventRequests = async (url: string, count: number): Prom
4772
});
4873
};
4974

75+
/**
76+
* Intercepts and extracts a single request containing a Sentry Event
77+
*
78+
* @param {string} url
79+
* @return {*} {Promise<Record<string, unknown>>}
80+
*/
5081
export const getEventRequest = async (url: string): Promise<Record<string, unknown>> => {
5182
return (await getMultipleEventRequests(url, 1))[0];
5283
};
5384

85+
/**
86+
* Intercepts and extracts a request containing a Sentry Envelope
87+
*
88+
* @param {string} url
89+
* @return {*} {Promise<Array<Record<string, unknown>>>}
90+
*/
5491
export const getEnvelopeRequest = async (url: string): Promise<Array<Record<string, unknown>>> => {
5592
return new Promise(resolve => {
5693
nock('https://dsn.ingest.sentry.io')
@@ -65,6 +102,14 @@ export const getEnvelopeRequest = async (url: string): Promise<Array<Record<stri
65102
});
66103
};
67104

105+
/**
106+
* Runs a test server
107+
*
108+
* @param {string} testDir
109+
* @param {string} [serverPath]
110+
* @param {string} [scenarioPath]
111+
* @return {*} {Promise<string>}
112+
*/
68113
export async function runServer(testDir: string, serverPath?: string, scenarioPath?: string): Promise<string> {
69114
const port = await getPortPromise();
70115
const url = `http://localhost:${port}/test`;

0 commit comments

Comments
 (0)