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