Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 15bb0be

Browse filesBrowse files
santigimenoMyles Borins
authored andcommitted
doc,test: add How to write a Node.js test guide
PR-URL: #6984 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Yorkie Liu <yorkiefixer@gmail.com>
1 parent 644bfe1 commit 15bb0be
Copy full SHA for 15bb0be

File tree

Expand file treeCollapse file tree

2 files changed

+189
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+189
-2
lines changed
Open diff view settings
Collapse file

‎CONTRIBUTING.md‎

Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+3-2Lines changed: 3 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ $ git rebase upstream/master
140140
### Step 5: Test
141141

142142
Bug fixes and features **should come with tests**. Add your tests in the
143-
test/parallel/ directory. Look at other tests to see how they should be
144-
structured (license boilerplate, common includes, etc.).
143+
`test/parallel/` directory. For guidance on how to write a test for the Node.js
144+
project, see this [guide](./doc/guides/writing_tests.md). Looking at other tests
145+
to see how they should be structured can also help.
145146

146147
```text
147148
$ ./configure && make -j8 test
Collapse file

‎doc/guides/writing_tests.md‎

Copy file name to clipboard
+186Lines changed: 186 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# How to write a test for the Node.js project
2+
3+
## What is a test?
4+
5+
A test must be a node script that exercises a specific functionality provided
6+
by node and checks that it behaves as expected. It should return 0 on success,
7+
otherwise it will fail. A test will fail if:
8+
9+
- It exits by calling `process.exit(code)` where `code != 0`
10+
- It exits due to an uncaught exception.
11+
- It never exits. In this case, the test runner will terminate the test because
12+
it sets a maximum time limit.
13+
14+
Tests can be added for multiple reasons:
15+
16+
- When adding new functionality.
17+
- When fixing regressions and bugs.
18+
- When expanding test coverage.
19+
20+
21+
## Test structure
22+
23+
Let's analyze this very basic test from the Node.js test suite:
24+
25+
```javascript
26+
1 'use strict';
27+
2 const common = require('../common');
28+
3 const http = require('http');
29+
4 const assert = require('assert');
30+
5
31+
6 const server = http.createServer(common.mustCall((req, res) => {
32+
7 res.end('ok');
33+
8 }));
34+
9 server.listen(common.PORT, () => {
35+
10 http.get({
36+
11 port: common.PORT,
37+
12 headers: {'Test': 'Düsseldorf'}
38+
13 }, common.mustCall((res) => {
39+
14 assert.equal(res.statusCode, 200);
40+
15 server.close();
41+
16 }));
42+
17 });
43+
```
44+
45+
**Lines 1-2**
46+
47+
```javascript
48+
'use strict';
49+
const common = require('../common');
50+
```
51+
52+
These two lines are mandatory and should be included on every test.
53+
The `common` module is a helper module that provides useful tools for the tests.
54+
If for some reason, no functionality from `common` is used, it should still be
55+
included like this:
56+
57+
```javascript
58+
require('../common');
59+
```
60+
61+
Why? It checks for leaks of globals.
62+
63+
**Lines 3-4**
64+
65+
```javascript
66+
const http = require('http');
67+
const assert = require('assert');
68+
```
69+
70+
These modules are required for the test to run. Except for special cases, these
71+
modules should only include core modules.
72+
The `assert` module is used by most of the tests to check that the assumptions
73+
for the test are met.
74+
75+
**Lines 6-17**
76+
77+
This is the body of the test. This test is quite simple, it just tests that an
78+
HTTP server accepts `non-ASCII` characters in the headers of an incoming
79+
request. Interesting things to notice:
80+
81+
- The use of `common.PORT` as the listening port. Always use `common.PORT`
82+
instead of using an arbitrary value, as it allows to run tests in parallel
83+
safely, as they are not trying to reuse the same port another test is already
84+
using.
85+
- The use of `common.mustCall` to check that some callbacks/listeners are
86+
called.
87+
- The HTTP server is closed once all the checks have run. This way, the test can
88+
exit gracefully. Remember that for a test to succeed, it must exit with a
89+
status code of 0.
90+
91+
## General recommendations
92+
93+
### Timers
94+
95+
The use of timers is discouraged, unless timers are being tested. There are
96+
multiple reasons for this. Mainly, they are a source of flakiness. For a thorough
97+
explanation go [here](https://github.com/nodejs/testing/issues/27).
98+
99+
In the event a timer is needed, it's recommended using the
100+
`common.platformTimeout()` method, that allows setting specific timeouts
101+
depending on the platform. For example:
102+
103+
```javascript
104+
const timer = setTimeout(fail, common.platformTimeout(4000));
105+
```
106+
107+
will create a 4-seconds timeout, except for some platforms where the delay will
108+
be multiplied for some factor.
109+
110+
### The *common* API
111+
112+
Make use of the helpers from the `common` module as much as possible.
113+
114+
One interesting case is `common.mustCall`. The use of `common.mustCall` may
115+
avoid the use of extra variables and the corresponding assertions. Let's explain
116+
this with a real test from the test suite.
117+
118+
```javascript
119+
'use strict';
120+
var common = require('../common');
121+
var assert = require('assert');
122+
var http = require('http');
123+
124+
var request = 0;
125+
var response = 0;
126+
process.on('exit', function() {
127+
assert.equal(request, 1, 'http server "request" callback was not called');
128+
assert.equal(response, 1, 'http request "response" callback was not called');
129+
});
130+
131+
var server = http.createServer(function(req, res) {
132+
request++;
133+
res.end();
134+
}).listen(common.PORT, function() {
135+
var options = {
136+
agent: null,
137+
port: this.address().port
138+
};
139+
http.get(options, function(res) {
140+
response++;
141+
res.resume();
142+
server.close();
143+
});
144+
});
145+
```
146+
147+
This test could be greatly simplified by using `common.mustCall` like this:
148+
149+
```javascript
150+
'use strict';
151+
var common = require('../common');
152+
var assert = require('assert');
153+
var http = require('http');
154+
155+
var server = http.createServer(common.mustCall(function(req, res) {
156+
res.end();
157+
})).listen(common.PORT, function() {
158+
var options = {
159+
agent: null,
160+
port: this.address().port
161+
};
162+
http.get(options, common.mustCall(function(res) {
163+
res.resume();
164+
server.close();
165+
}));
166+
});
167+
168+
```
169+
170+
### Flags
171+
172+
Some tests will require running Node.js with specific command line flags set. To
173+
accomplish this, a `// Flags: ` comment should be added in the preamble of the
174+
test followed by the flags. For example, to allow a test to require some of the
175+
`internal/*` modules, the `--expose-internals` flag should be added.
176+
A test that would require `internal/freelist` could start like this:
177+
178+
```javascript
179+
'use strict';
180+
181+
// Flags: --expose-internals
182+
183+
require('../common');
184+
const assert = require('assert');
185+
const freelist = require('internal/freelist');
186+
```

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.