summaryrefslogtreecommitdiff
path: root/doc/guides/writing-tests.md
diff options
context:
space:
mode:
authorSafia Abdalla <safia@safia.rocks>2016-11-30 22:54:38 -0600
committerMichaël Zasso <targos@protonmail.com>2016-12-03 10:45:27 +0100
commit947baaf5b70d9fa653eecf42d7c9fb27b28427bd (patch)
tree399546ed33ba3390e0608bf8f17b98a9b90fda2b /doc/guides/writing-tests.md
parenta912b791d4dd10d694c8b278fea9345f377adf58 (diff)
downloadandroid-node-v8-947baaf5b70d9fa653eecf42d7c9fb27b28427bd.tar.gz
android-node-v8-947baaf5b70d9fa653eecf42d7c9fb27b28427bd.tar.bz2
android-node-v8-947baaf5b70d9fa653eecf42d7c9fb27b28427bd.zip
doc: rename writing_tests.md to writing-tests.md
The writing_tests.md file did not utilize kebab-case as the other files in the directory did. PR-URL: https://github.com/nodejs/node/pull/9867 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
Diffstat (limited to 'doc/guides/writing-tests.md')
-rw-r--r--doc/guides/writing-tests.md204
1 files changed, 204 insertions, 0 deletions
diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md
new file mode 100644
index 0000000000..d00be9cdbc
--- /dev/null
+++ b/doc/guides/writing-tests.md
@@ -0,0 +1,204 @@
+# How to write a test for the Node.js project
+
+## What is a test?
+
+A test must be a node script that exercises a specific functionality provided
+by node and checks that it behaves as expected. It should exit with code `0` on success,
+otherwise it will fail. A test will fail if:
+
+- It exits by setting `process.exitCode` to a non-zero number.
+ - This is most often done by having an assertion throw an uncaught
+ Error.
+ - Occasionally, using `process.exit(code)` may be appropriate.
+- It never exits. In this case, the test runner will terminate the test because
+ it sets a maximum time limit.
+
+Tests can be added for multiple reasons:
+
+- When adding new functionality.
+- When fixing regressions and bugs.
+- When expanding test coverage.
+
+
+## Test structure
+
+Let's analyze this very basic test from the Node.js test suite:
+
+```javascript
+1 'use strict';
+2 const common = require('../common');
+3
+4 // This test ensures that the http-parser can handle UTF-8 characters
+5 // in the http header.
+6
+7 const http = require('http');
+8 const assert = require('assert');
+9
+10 const server = http.createServer(common.mustCall((req, res) => {
+11 res.end('ok');
+12 }));
+13 server.listen(0, () => {
+14 http.get({
+15 port: server.address().port,
+16 headers: {'Test': 'Düsseldorf'}
+17 }, common.mustCall((res) => {
+18 assert.strictEqual(res.statusCode, 200);
+19 server.close();
+20 }));
+21 });
+```
+
+**Lines 1-2**
+
+```javascript
+'use strict';
+const common = require('../common');
+```
+
+These two lines are mandatory and should be included on every test.
+The `common` module is a helper module that provides useful tools for the tests.
+If for some reason, no functionality from `common` is used, it should still be
+included like this:
+
+```javascript
+require('../common');
+```
+
+Why? It checks for leaks of globals.
+
+**Lines 4-5**
+
+```javascript
+// This test ensures that the http-parser can handle UTF-8 characters
+// in the http header.
+```
+
+A test should start with a comment containing a brief description of what it is
+designed to test.
+
+
+**Lines 7-8**
+
+```javascript
+const http = require('http');
+const assert = require('assert');
+```
+
+These modules are required for the test to run. Except for special cases, these
+modules should only include core modules.
+The `assert` module is used by most of the tests to check that the assumptions
+for the test are met.
+
+**Lines 10-21**
+
+This is the body of the test. This test is quite simple, it just tests that an
+HTTP server accepts `non-ASCII` characters in the headers of an incoming
+request. Interesting things to notice:
+
+- If the test doesn't depend on a specific port number then always use 0 instead
+ of an arbitrary value, as it allows tests to be run in parallel safely, as the
+ operating system will assign a random port. If the test requires a specific
+ port, for example if the test checks that assigning a specific port works as
+ expected, then it is ok to assign a specific port number.
+- The use of `common.mustCall` to check that some callbacks/listeners are
+ called.
+- The HTTP server is closed once all the checks have run. This way, the test can
+ exit gracefully. Remember that for a test to succeed, it must exit with a
+ status code of 0.
+
+## General recommendations
+
+### Timers
+
+The use of timers is discouraged, unless timers are being tested. There are
+multiple reasons for this. Mainly, they are a source of flakiness. For a thorough
+explanation go [here](https://github.com/nodejs/testing/issues/27).
+
+In the event a timer is needed, it's recommended using the
+`common.platformTimeout()` method, that allows setting specific timeouts
+depending on the platform. For example:
+
+```javascript
+const timer = setTimeout(fail, common.platformTimeout(4000));
+```
+
+will create a 4-seconds timeout, except for some platforms where the delay will
+be multiplied for some factor.
+
+### The *common* API
+
+Make use of the helpers from the `common` module as much as possible.
+
+One interesting case is `common.mustCall`. The use of `common.mustCall` may
+avoid the use of extra variables and the corresponding assertions. Let's explain
+this with a real test from the test suite.
+
+```javascript
+'use strict';
+var common = require('../common');
+var assert = require('assert');
+var http = require('http');
+
+var request = 0;
+var response = 0;
+process.on('exit', function() {
+ assert.equal(request, 1, 'http server "request" callback was not called');
+ assert.equal(response, 1, 'http request "response" callback was not called');
+});
+
+var server = http.createServer(function(req, res) {
+ request++;
+ res.end();
+}).listen(0, function() {
+ var options = {
+ agent: null,
+ port: this.address().port
+ };
+ http.get(options, function(res) {
+ response++;
+ res.resume();
+ server.close();
+ });
+});
+```
+
+This test could be greatly simplified by using `common.mustCall` like this:
+
+```javascript
+'use strict';
+var common = require('../common');
+var assert = require('assert');
+var http = require('http');
+
+var server = http.createServer(common.mustCall(function(req, res) {
+ res.end();
+})).listen(0, function() {
+ var options = {
+ agent: null,
+ port: this.address().port
+ };
+ http.get(options, common.mustCall(function(res) {
+ res.resume();
+ server.close();
+ }));
+});
+
+```
+
+### Flags
+
+Some tests will require running Node.js with specific command line flags set. To
+accomplish this, a `// Flags: ` comment should be added in the preamble of the
+test followed by the flags. For example, to allow a test to require some of the
+`internal/*` modules, the `--expose-internals` flag should be added.
+A test that would require `internal/freelist` could start like this:
+
+```javascript
+'use strict';
+
+// Flags: --expose-internals
+
+require('../common');
+const assert = require('assert');
+const freelist = require('internal/freelist');
+```