11cb0ef41Sopenharmony_ci# How to write a test for the Node.js project
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci## What is a test?
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciMost tests in Node.js core are JavaScript programs that exercise a functionality
61cb0ef41Sopenharmony_ciprovided by Node.js and check that it behaves as expected. Tests should exit
71cb0ef41Sopenharmony_ciwith code `0` on success. A test will fail if:
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci* It exits by setting `process.exitCode` to a non-zero number.
101cb0ef41Sopenharmony_ci  * This is usually done by having an assertion throw an uncaught Error.
111cb0ef41Sopenharmony_ci  * Occasionally, using `process.exit(code)` may be appropriate.
121cb0ef41Sopenharmony_ci* It never exits. In this case, the test runner will terminate the test because
131cb0ef41Sopenharmony_ci  it sets a maximum time limit.
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciAdd tests when:
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci* Adding new functionality.
181cb0ef41Sopenharmony_ci* Fixing regressions and bugs.
191cb0ef41Sopenharmony_ci* Expanding test coverage.
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci## Test directory structure
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciSee [directory structure overview][] for outline of existing test and locations.
241cb0ef41Sopenharmony_ciWhen deciding on whether to expand an existing test file or create a new one,
251cb0ef41Sopenharmony_ciconsider going through the files related to the subsystem.
261cb0ef41Sopenharmony_ciFor example, look for `test-streams` when writing a test for `lib/streams.js`.
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci## Test structure
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciLet's analyze this basic test from the Node.js test suite:
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci```js
331cb0ef41Sopenharmony_ci'use strict';                                                          // 1
341cb0ef41Sopenharmony_ciconst common = require('../common');                                   // 2
351cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');                        // 3
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci// This test ensures that the http-parser can handle UTF-8 characters  // 5
381cb0ef41Sopenharmony_ci// in the http header.                                                 // 6
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ciconst assert = require('node:assert');                                 // 8
411cb0ef41Sopenharmony_ciconst http = require('node:http');                                     // 9
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => {       // 11
441cb0ef41Sopenharmony_ci  res.end('ok');                                                       // 12
451cb0ef41Sopenharmony_ci}));                                                                   // 13
461cb0ef41Sopenharmony_ciserver.listen(0, () => {                                               // 14
471cb0ef41Sopenharmony_ci  http.get({                                                           // 15
481cb0ef41Sopenharmony_ci    port: server.address().port,                                       // 16
491cb0ef41Sopenharmony_ci    headers: { 'Test': 'Düsseldorf' },                                 // 17
501cb0ef41Sopenharmony_ci  }, common.mustCall((res) => {                                        // 18
511cb0ef41Sopenharmony_ci    assert.strictEqual(res.statusCode, 200);                           // 19
521cb0ef41Sopenharmony_ci    server.close();                                                    // 20
531cb0ef41Sopenharmony_ci  }));                                                                 // 21
541cb0ef41Sopenharmony_ci});                                                                    // 22
551cb0ef41Sopenharmony_ci// ...                                                                 // 23
561cb0ef41Sopenharmony_ci```
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci### **Lines 1-3**
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci```js
611cb0ef41Sopenharmony_ci'use strict';
621cb0ef41Sopenharmony_ciconst common = require('../common');
631cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
641cb0ef41Sopenharmony_ci```
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciThe first line enables strict mode. All tests should be in strict mode unless
671cb0ef41Sopenharmony_cithe nature of the test requires that the test run without it.
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ciThe second line loads the `common` module. The [`common` module][] is a helper
701cb0ef41Sopenharmony_cimodule that provides useful tools for the tests. Some common functionality has
711cb0ef41Sopenharmony_cibeen extracted into submodules, which are required separately like the fixtures
721cb0ef41Sopenharmony_cimodule here.
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciEven if a test uses no functions or other properties exported by `common`,
751cb0ef41Sopenharmony_cithe test should still include the `common` module before any other modules. This
761cb0ef41Sopenharmony_ciis because the `common` module includes code that will cause a test to fail if
771cb0ef41Sopenharmony_cithe test leaks variables into the global space. In situations where a test uses
781cb0ef41Sopenharmony_cino functions or other properties exported by `common`, include it without
791cb0ef41Sopenharmony_ciassigning it to an identifier:
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci```js
821cb0ef41Sopenharmony_cirequire('../common');
831cb0ef41Sopenharmony_ci```
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci### **Lines 5-6**
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci```js
881cb0ef41Sopenharmony_ci// This test ensures that the http-parser can handle UTF-8 characters
891cb0ef41Sopenharmony_ci// in the http header.
901cb0ef41Sopenharmony_ci```
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ciA test should start with a comment containing a brief description of what it is
931cb0ef41Sopenharmony_cidesigned to test.
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci### **Lines 8-9**
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci```js
981cb0ef41Sopenharmony_ciconst assert = require('node:assert');
991cb0ef41Sopenharmony_ciconst http = require('node:http');
1001cb0ef41Sopenharmony_ci```
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ciThe test checks functionality in the `node:http` module.
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ciMost tests use the `node:assert` module to confirm expectations of the test.
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ciThe require statements are sorted in
1071cb0ef41Sopenharmony_ci[ASCII][] order (digits, upper
1081cb0ef41Sopenharmony_cicase, `_`, lower case).
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci### **Lines 11-22**
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci```js
1131cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => {
1141cb0ef41Sopenharmony_ci  res.end('ok');
1151cb0ef41Sopenharmony_ci}));
1161cb0ef41Sopenharmony_ciserver.listen(0, () => {
1171cb0ef41Sopenharmony_ci  http.get({
1181cb0ef41Sopenharmony_ci    port: server.address().port,
1191cb0ef41Sopenharmony_ci    headers: { 'Test': 'Düsseldorf' },
1201cb0ef41Sopenharmony_ci  }, common.mustCall((res) => {
1211cb0ef41Sopenharmony_ci    assert.strictEqual(res.statusCode, 200);
1221cb0ef41Sopenharmony_ci    server.close();
1231cb0ef41Sopenharmony_ci  }));
1241cb0ef41Sopenharmony_ci});
1251cb0ef41Sopenharmony_ci```
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ciThis is the body of the test. This test is simple, it just tests that an
1281cb0ef41Sopenharmony_ciHTTP server accepts `non-ASCII` characters in the headers of an incoming
1291cb0ef41Sopenharmony_cirequest. Interesting things to notice:
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci* If the test doesn't depend on a specific port number, then always use 0
1321cb0ef41Sopenharmony_ci  instead of an arbitrary value, as it allows tests to run in parallel safely,
1331cb0ef41Sopenharmony_ci  as the operating system will assign a random port. If the test requires a
1341cb0ef41Sopenharmony_ci  specific port, for example if the test checks that assigning a specific port
1351cb0ef41Sopenharmony_ci  works as expected, then it is ok to assign a specific port number.
1361cb0ef41Sopenharmony_ci* The use of `common.mustCall` to check that some callbacks/listeners are
1371cb0ef41Sopenharmony_ci  called.
1381cb0ef41Sopenharmony_ci* The HTTP server closes once all the checks have run. This way, the test can
1391cb0ef41Sopenharmony_ci  exit gracefully. Remember that for a test to succeed, it must exit with a
1401cb0ef41Sopenharmony_ci  status code of 0.
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci## General recommendations
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci### Timers
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ciAvoid timers unless the test is specifically testing timers. There are multiple
1471cb0ef41Sopenharmony_cireasons for this. Mainly, they are a source of flakiness. For a thorough
1481cb0ef41Sopenharmony_ciexplanation go [here](https://github.com/nodejs/testing/issues/27).
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ciIn the event a test needs a timer, consider using the
1511cb0ef41Sopenharmony_ci`common.platformTimeout()` method. It allows setting specific timeouts
1521cb0ef41Sopenharmony_cidepending on the platform:
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci```js
1551cb0ef41Sopenharmony_ciconst timer = setTimeout(fail, common.platformTimeout(4000));
1561cb0ef41Sopenharmony_ci```
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ciwill create a 4-second timeout on most platforms but a longer timeout on slower
1591cb0ef41Sopenharmony_ciplatforms.
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci### The _common_ API
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ciMake use of the helpers from the `common` module as much as possible. Please
1641cb0ef41Sopenharmony_cirefer to the [common file documentation](https://github.com/nodejs/node/tree/HEAD/test/common)
1651cb0ef41Sopenharmony_cifor the full details of the helpers.
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci#### common.mustCall
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ciOne interesting case is `common.mustCall`. The use of `common.mustCall` may
1701cb0ef41Sopenharmony_ciavoid the use of extra variables and the corresponding assertions. Let's
1711cb0ef41Sopenharmony_ciexplain this with a real test from the test suite.
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci```js
1741cb0ef41Sopenharmony_ci'use strict';
1751cb0ef41Sopenharmony_cirequire('../common');
1761cb0ef41Sopenharmony_ciconst assert = require('node:assert');
1771cb0ef41Sopenharmony_ciconst http = require('node:http');
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_cilet request = 0;
1801cb0ef41Sopenharmony_cilet listening = 0;
1811cb0ef41Sopenharmony_cilet response = 0;
1821cb0ef41Sopenharmony_ciprocess.on('exit', () => {
1831cb0ef41Sopenharmony_ci  assert.equal(request, 1, 'http server "request" callback was not called');
1841cb0ef41Sopenharmony_ci  assert.equal(listening, 1, 'http server "listening" callback was not called');
1851cb0ef41Sopenharmony_ci  assert.equal(response, 1, 'http request "response" callback was not called');
1861cb0ef41Sopenharmony_ci});
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ciconst server = http.createServer((req, res) => {
1891cb0ef41Sopenharmony_ci  request++;
1901cb0ef41Sopenharmony_ci  res.end();
1911cb0ef41Sopenharmony_ci}).listen(0, () => {
1921cb0ef41Sopenharmony_ci  listening++;
1931cb0ef41Sopenharmony_ci  const options = {
1941cb0ef41Sopenharmony_ci    agent: null,
1951cb0ef41Sopenharmony_ci    port: server.address().port,
1961cb0ef41Sopenharmony_ci  };
1971cb0ef41Sopenharmony_ci  http.get(options, (res) => {
1981cb0ef41Sopenharmony_ci    response++;
1991cb0ef41Sopenharmony_ci    res.resume();
2001cb0ef41Sopenharmony_ci    server.close();
2011cb0ef41Sopenharmony_ci  });
2021cb0ef41Sopenharmony_ci});
2031cb0ef41Sopenharmony_ci```
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ciThis test could be greatly simplified by using `common.mustCall` like this:
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci```js
2081cb0ef41Sopenharmony_ci'use strict';
2091cb0ef41Sopenharmony_ciconst common = require('../common');
2101cb0ef41Sopenharmony_ciconst http = require('node:http');
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => {
2131cb0ef41Sopenharmony_ci  res.end();
2141cb0ef41Sopenharmony_ci})).listen(0, common.mustCall(() => {
2151cb0ef41Sopenharmony_ci  const options = {
2161cb0ef41Sopenharmony_ci    agent: null,
2171cb0ef41Sopenharmony_ci    port: server.address().port,
2181cb0ef41Sopenharmony_ci  };
2191cb0ef41Sopenharmony_ci  http.get(options, common.mustCall((res) => {
2201cb0ef41Sopenharmony_ci    res.resume();
2211cb0ef41Sopenharmony_ci    server.close();
2221cb0ef41Sopenharmony_ci  }));
2231cb0ef41Sopenharmony_ci}));
2241cb0ef41Sopenharmony_ci```
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci**Note:** Many functions invoke their callback with an `err` value as the first
2271cb0ef41Sopenharmony_ciargument. It is not a good idea to simply pass `common.mustCall()` to those
2281cb0ef41Sopenharmony_cibecause `common.mustCall()` will ignore the error. Use `common.mustSucceed()`
2291cb0ef41Sopenharmony_ciinstead.
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci#### Countdown module
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ciThe common [Countdown module](https://github.com/nodejs/node/tree/HEAD/test/common#countdown-module)
2341cb0ef41Sopenharmony_ciprovides a simple countdown mechanism for tests that require a particular
2351cb0ef41Sopenharmony_ciaction to be taken after a given number of completed tasks (for instance,
2361cb0ef41Sopenharmony_cishutting down an HTTP server after a specific number of requests).
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci```js
2391cb0ef41Sopenharmony_ciconst Countdown = require('../common/countdown');
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ciconst countdown = new Countdown(2, () => {
2421cb0ef41Sopenharmony_ci  console.log('.');
2431cb0ef41Sopenharmony_ci});
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_cicountdown.dec();
2461cb0ef41Sopenharmony_cicountdown.dec(); // The countdown callback will be invoked now.
2471cb0ef41Sopenharmony_ci```
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci#### Testing promises
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ciWhen writing tests involving promises, it is generally good to wrap the
2521cb0ef41Sopenharmony_ci`onFulfilled` handler, otherwise the test could successfully finish if the
2531cb0ef41Sopenharmony_cipromise never resolves (pending promises do not keep the event loop alive).
2541cb0ef41Sopenharmony_ciNode.js automatically crashes - and hence, the test fails - in the case of an
2551cb0ef41Sopenharmony_ci`unhandledRejection` event.
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci```js
2581cb0ef41Sopenharmony_ciconst common = require('../common');
2591cb0ef41Sopenharmony_ciconst assert = require('node:assert');
2601cb0ef41Sopenharmony_ciconst fs = require('node:fs').promises;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci// Wrap the `onFulfilled` handler in `common.mustCall()`.
2631cb0ef41Sopenharmony_cifs.readFile('test-file').then(
2641cb0ef41Sopenharmony_ci  common.mustCall(
2651cb0ef41Sopenharmony_ci    (content) => assert.strictEqual(content.toString(), 'test2'),
2661cb0ef41Sopenharmony_ci  ));
2671cb0ef41Sopenharmony_ci```
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci### Flags
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ciSome tests will require running Node.js with specific command line flags set. To
2721cb0ef41Sopenharmony_ciaccomplish this, add a `// Flags:` comment in the preamble of the
2731cb0ef41Sopenharmony_citest followed by the flags. For example, to allow a test to require some of the
2741cb0ef41Sopenharmony_ci`internal/*` modules, add the `--expose-internals` flag.
2751cb0ef41Sopenharmony_ciA test that would require `internal/freelist` could start like this:
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci```js
2781cb0ef41Sopenharmony_ci'use strict';
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci// Flags: --expose-internals
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_cirequire('../common');
2831cb0ef41Sopenharmony_ciconst assert = require('node:assert');
2841cb0ef41Sopenharmony_ciconst freelist = require('node:internal/freelist');
2851cb0ef41Sopenharmony_ci```
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ciIn specific scenarios it may be useful to get a hold of `primordials` or
2881cb0ef41Sopenharmony_ci`internalBinding()`. You can do so using
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci```console
2911cb0ef41Sopenharmony_cinode --expose-internals -r internal/test/binding lib/fs.js
2921cb0ef41Sopenharmony_ci```
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ciThis only works if you preload `node:internal/test/binding` by command line
2951cb0ef41Sopenharmony_ciflag.
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci### Assertions
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ciWhen writing assertions, prefer the strict versions:
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci* `assert.strictEqual()` over `assert.equal()`
3021cb0ef41Sopenharmony_ci* `assert.deepStrictEqual()` over `assert.deepEqual()`
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ciWhen using `assert.throws()`, if possible, provide the full error message:
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci```js
3071cb0ef41Sopenharmony_ciassert.throws(
3081cb0ef41Sopenharmony_ci  () => {
3091cb0ef41Sopenharmony_ci    throw new Error('Wrong value');
3101cb0ef41Sopenharmony_ci  },
3111cb0ef41Sopenharmony_ci  /^Error: Wrong value$/, // Instead of something like /Wrong value/
3121cb0ef41Sopenharmony_ci);
3131cb0ef41Sopenharmony_ci```
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ciIn the case of internal errors, prefer checking only the `code` property:
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci```js
3181cb0ef41Sopenharmony_ciassert.throws(
3191cb0ef41Sopenharmony_ci  () => {
3201cb0ef41Sopenharmony_ci    throw new ERR_FS_FILE_TOO_LARGE(`${sizeKiB} Kb`);
3211cb0ef41Sopenharmony_ci  },
3221cb0ef41Sopenharmony_ci  { code: 'ERR_FS_FILE_TOO_LARGE' },
3231cb0ef41Sopenharmony_ci  // Do not include message: /^File size ([0-9]+ Kb) is greater than 2 GiB$/
3241cb0ef41Sopenharmony_ci);
3251cb0ef41Sopenharmony_ci```
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci### Console output
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ciOutput written by tests to stdout or stderr, such as with `console.log()` or
3301cb0ef41Sopenharmony_ci`console.error()`, can be useful when writing tests, as well as for debugging
3311cb0ef41Sopenharmony_cithem during later maintenance. The output will be suppressed by the test runner
3321cb0ef41Sopenharmony_ci(`./tools/test.py`) unless the test fails, but will always be displayed when
3331cb0ef41Sopenharmony_cirunning tests directly with `node`. For failing tests, the test runner will
3341cb0ef41Sopenharmony_ciinclude the output along with the failed test assertion in the test report.
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ciSome output can help debugging by giving context to test failures. For example,
3371cb0ef41Sopenharmony_ciwhen troubleshooting tests that timeout in CI. With no log statements, we have
3381cb0ef41Sopenharmony_cino idea where the test got hung up.
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ciThere have been cases where tests fail without `console.log()`, and then pass
3411cb0ef41Sopenharmony_ciwhen its added, so be cautious about its use, particularly in tests of the I/O
3421cb0ef41Sopenharmony_ciand streaming APIs.
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ciExcessive use of console output is discouraged as it can overwhelm the display,
3451cb0ef41Sopenharmony_ciincluding the Jenkins console and test report displays. Be particularly
3461cb0ef41Sopenharmony_cicautious of output in loops, or other contexts where output may be repeated many
3471cb0ef41Sopenharmony_citimes in the case of failure.
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ciIn some tests, it can be unclear whether a `console.log()` statement is required
3501cb0ef41Sopenharmony_cias part of the test (message tests, tests that check output from child
3511cb0ef41Sopenharmony_ciprocesses, etc.), or is there as a debug aide. If there is any chance of
3521cb0ef41Sopenharmony_ciconfusion, use comments to make the purpose clear.
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci### ES.Next features
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ciFor performance considerations, we only use a selected subset of ES.Next
3571cb0ef41Sopenharmony_cifeatures in JavaScript code in the `lib` directory. However, when writing
3581cb0ef41Sopenharmony_citests, for the ease of backporting, it is encouraged to use those ES.Next
3591cb0ef41Sopenharmony_cifeatures that can be used directly without a flag in
3601cb0ef41Sopenharmony_ci[all maintained branches][]. [node.green][] lists available features
3611cb0ef41Sopenharmony_ciin each release, such as:
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci* `let` and `const` over `var`
3641cb0ef41Sopenharmony_ci* Template literals over string concatenation
3651cb0ef41Sopenharmony_ci* Arrow functions when appropriate
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci## Naming test files
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ciTest files are named using kebab casing. The first component of the name is
3701cb0ef41Sopenharmony_ci`test`. The second is the module or subsystem being tested. The third is usually
3711cb0ef41Sopenharmony_cithe method or event name being tested. Subsequent components of the name add
3721cb0ef41Sopenharmony_cimore information about what is being tested.
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ciFor example, a test for the `beforeExit` event on the `process` object might be
3751cb0ef41Sopenharmony_cinamed `test-process-before-exit.js`. If the test specifically checked that arrow
3761cb0ef41Sopenharmony_cifunctions worked correctly with the `beforeExit` event, then it might be named
3771cb0ef41Sopenharmony_ci`test-process-before-exit-arrow-functions.js`.
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci## Imported tests
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci### Web platform tests
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ciSee [`test/wpt`](../../test/wpt/README.md) for more information.
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci## C++ unit test
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ciC++ code can be tested using [Google Test][]. Most features in Node.js can be
3881cb0ef41Sopenharmony_citested using the methods described previously in this document. But there are
3891cb0ef41Sopenharmony_cicases where these might not be enough, for example writing code for Node.js
3901cb0ef41Sopenharmony_cithat will only be called when Node.js is embedded.
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci### Adding a new test
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ciThe unit test should be placed in `test/cctest` and be named with the prefix
3951cb0ef41Sopenharmony_ci`test` followed by the name of unit being tested. For example, the code below
3961cb0ef41Sopenharmony_ciwould be placed in `test/cctest/test_env.cc`:
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci```cpp
3991cb0ef41Sopenharmony_ci#include "gtest/gtest.h"
4001cb0ef41Sopenharmony_ci#include "node_test_fixture.h"
4011cb0ef41Sopenharmony_ci#include "env.h"
4021cb0ef41Sopenharmony_ci#include "node.h"
4031cb0ef41Sopenharmony_ci#include "v8.h"
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_cistatic bool called_cb = false;
4061cb0ef41Sopenharmony_cistatic void at_exit_callback(void* arg);
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ciclass EnvTest : public NodeTestFixture { };
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ciTEST_F(EnvTest, RunAtExit) {
4111cb0ef41Sopenharmony_ci  v8::HandleScope handle_scope(isolate_);
4121cb0ef41Sopenharmony_ci  v8::Local<v8::Context> context = v8::Context::New(isolate_);
4131cb0ef41Sopenharmony_ci  node::IsolateData* isolateData = node::CreateIsolateData(isolate_, uv_default_loop());
4141cb0ef41Sopenharmony_ci  Argv argv{"node", "-e", ";"};
4151cb0ef41Sopenharmony_ci  auto env = node::CreateEnvironment(isolateData, context, 1, *argv, 2, *argv);
4161cb0ef41Sopenharmony_ci  node::AtExit(env, at_exit_callback);
4171cb0ef41Sopenharmony_ci  node::RunAtExit(env);
4181cb0ef41Sopenharmony_ci  EXPECT_TRUE(called_cb);
4191cb0ef41Sopenharmony_ci}
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_cistatic void at_exit_callback(void* arg) {
4221cb0ef41Sopenharmony_ci  called_cb = true;
4231cb0ef41Sopenharmony_ci}
4241cb0ef41Sopenharmony_ci```
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ciNext add the test to the `sources` in the `cctest` target in node.gyp:
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci```console
4291cb0ef41Sopenharmony_ci'sources': [
4301cb0ef41Sopenharmony_ci  'test/cctest/test_env.cc',
4311cb0ef41Sopenharmony_ci  ...
4321cb0ef41Sopenharmony_ci],
4331cb0ef41Sopenharmony_ci```
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_ciThe only sources that should be included in the cctest target are
4361cb0ef41Sopenharmony_ciactual test or helper source files. There might be a need to include specific
4371cb0ef41Sopenharmony_ciobject files that are compiled by the `node` target and this can be done by
4381cb0ef41Sopenharmony_ciadding them to the `libraries` section in the cctest target.
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ciThe test can be executed by running the `cctest` target:
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci```console
4431cb0ef41Sopenharmony_ci$ make cctest
4441cb0ef41Sopenharmony_ci```
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ciA filter can be applied to run single/multiple test cases:
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci```console
4491cb0ef41Sopenharmony_ci$ make cctest GTEST_FILTER=EnvironmentTest.AtExitWithArgument
4501cb0ef41Sopenharmony_ci```
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_ci`cctest` can also be run directly which can be useful when debugging:
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci```console
4551cb0ef41Sopenharmony_ci$ out/Release/cctest --gtest_filter=EnvironmentTest.AtExit\*
4561cb0ef41Sopenharmony_ci```
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci### Node.js test fixture
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ciThere is a [test fixture][] named `node_test_fixture.h` which can be included by
4611cb0ef41Sopenharmony_ciunit tests. The fixture takes care of setting up the Node.js environment
4621cb0ef41Sopenharmony_ciand tearing it down after the tests have finished.
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ciIt also contains a helper to create arguments to be passed into Node.js. It
4651cb0ef41Sopenharmony_ciwill depend on what is being tested if this is required or not.
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_ci### Test coverage
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ciTo generate a test coverage report, see the
4701cb0ef41Sopenharmony_ci[Test Coverage section of the Building guide][].
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ciNightly coverage reports for the Node.js `main` branch are available at
4731cb0ef41Sopenharmony_ci<https://coverage.nodejs.org/>.
4741cb0ef41Sopenharmony_ci
4751cb0ef41Sopenharmony_ci[ASCII]: https://man7.org/linux/man-pages/man7/ascii.7.html
4761cb0ef41Sopenharmony_ci[Google Test]: https://github.com/google/googletest
4771cb0ef41Sopenharmony_ci[Test Coverage section of the Building guide]: https://github.com/nodejs/node/blob/HEAD/BUILDING.md#running-coverage
4781cb0ef41Sopenharmony_ci[`common` module]: https://github.com/nodejs/node/blob/HEAD/test/common/README.md
4791cb0ef41Sopenharmony_ci[all maintained branches]: https://github.com/nodejs/lts
4801cb0ef41Sopenharmony_ci[directory structure overview]: https://github.com/nodejs/node/blob/HEAD/test/README.md#test-directories
4811cb0ef41Sopenharmony_ci[node.green]: https://node.green/
4821cb0ef41Sopenharmony_ci[test fixture]: https://github.com/google/googletest/blob/HEAD/docs/primer.md#test-fixtures-using-the-same-data-configuration-for-multiple-tests-same-data-multiple-tests
483