test() - uhop/tape-six GitHub Wiki
test is the entry point to the test suite:
import test from 'tape-six';
// import {test} from 'tape-six';
// CommonJS (named import is recommended):
// const {test} = require('tape-six');To help port tests from other frameworks, test() is aliased as suite(), describe() and it(). The aliases are exported from the package.
When called inside a test body, test() and its aliases automatically delegate to the current tester's t.test() method. The same applies to test.skip(), test.todo(), and test.asPromise(). Using t.test() directly is still preferred because it makes the delegation explicit.
This function registers a test suite. Available options:
-
async test(name, options, testFn)— registers a test suite to be executed asynchronously. The returned promise is resolved when the test suite is finished.- In most cases no need to wait for the returned promise.
- The test function has the following signature:
async testFn(tester)- The test function can be async or sync. No need to return a promise.
-
test.skip(name, options, testFn)— registers a test suite to be skipped.- It is used to mark a test suite to be skipped. It will not be executed.
-
test.todo(name, options, testFn)— registers a test suite that is marked as work in progress.- Tests in this suite will be executed, errors will be reported but not counted as failures.
- It is used to mark tests for incomplete features under development.
-
test.asPromise(name, options, testPromiseFn)— registers a test suite to be executed asynchronously using the callback-style API to notify that the test suite is finished.- The test function has a different signature:
testPromiseFn(tester, resolve, reject).- The whole
resolve/rejectpair is modeled after thePromiseAPI. - The
resolvefunction is used to notify that the test suite is finished successfully.- The value passed to
resolve()will be ignored.
- The value passed to
- The
rejectfunction is used to notify that the test suite is finished with an error.- The error passed to
reject()will be reported as a failure.
- The error passed to
- The whole
- The test function has a different signature:
All three arguments (name, options, testFn or testPromiseFn) are optional and can be used in any order (they are recognized by their types).
The arguments mentioned above are:
-
name— the optional name of the test suite. If not provided, it will be set to the name of the test function or'(anonymous)'. -
options— the optional options object. Available options:-
name— the optional name of the test suite. If not provided, it will be set to the name of the test function or'(anonymous)'.- Can be overridden by the
nameargument.
- Can be overridden by the
-
testFn— the optional test function to be executed (see below).- Can be overridden by the
testFnargument.
- Can be overridden by the
-
skip— iftrue, the test suite will be skipped. -
todo— iftrue, the test suite will be marked as work in progress. -
timeout— the optional timeout in milliseconds. It is used for asynchronous tests.- If the timeout is exceeded, the test suite will be marked as failed.
-
Important: JavaScript does not provide a generic way to cancel asynchronous operations.
When the timeout is exceeded,
tape6will usesignalproperty of the tester object to indicate that the test should be cancelled. See Tester for more details. - The default: no timeout.
- Hooks (see below for details):
-
beforeAll— a function to be executed before all tests in the suite. -
afterAll— a function to be executed after all tests in the suite. -
beforeEach— a function to be executed before each test in the suite. -
afterEach— a function to be executed after each test in the suite. -
before— an alias forbeforeAll.- If both are set,
beforeAllwill be executed beforebefore.
- If both are set,
-
after— an alias forafterAll.- If both are set,
afterAllwill be executed afterafter.
- If both are set,
-
-
-
testFn— a test function to be executed. It will be called with thetesterobject. The result will be ignored.- This function can be synchronous or asynchronous.
-
testPromiseFn— a callback-based test function to be executed (see below). It will be called with thetesterobject and two callbacks:resolveandrejectmodeled on the Promise API.- Value supplied to
resolve()will be ignored. - Value supplied to
reject()will be used as the error message.
- Value supplied to
All hooks are functions with no arguments returning void or a Promise<void>:
() => void | Promise<void>;Read more on hooks and their use in before and after hooks.
Given all that test and its helpers can be called like this:
test(name, options, testFn);
test(name, testFn);
test(testFn);
test(name, options);
test(options, testFn);
test(options);
// examples:
test('foo', t => {
t.pass();
});
test('bar', async t => {
t.fail();
});
test(function baz(t) {
t.ok(1 < 2);
});
test({
name: 'qux',
todo: true,
testFn: t => {
t.ok(1 < 2);
}
});
test.skip('foo1', t => {
t.pass();
t.fail();
});
test.todo('foo2', t => {
t.pass();
t.fail();
});
test.asPromise('foo3', (t, resolve, reject) => {
const stream = fs.readStream('foo.txt');
let buffer = '';
stream.on('data', chunk => {
buffer += chunk;
});
stream.on('end', () => {
t.equal(buffer, 'foo');
resolve();
});
stream.on('error', error => reject(error));
});The preferred way to embed tests is to use the test method of the tester object:
test('top', async t => {
t.pass();
await t.test('nested #1', async t => {
t.pass();
});
await t.test('nested #2', async t => {
t.pass();
await t.test('even more nested', async t => {
t.pass();
});
});
});Since top-level test() (and its aliases describe(), it(), suite()) automatically delegate to the current tester when called inside a test body, the following is equivalent:
test('top', async t => {
t.pass();
await test('nested #1', async t => {
t.pass();
});
await test('nested #2', async t => {
t.pass();
await test('even more nested', async t => {
t.pass();
});
});
});Using t.test() is preferred because it makes the delegation explicit. The top-level form is convenient when porting tests from frameworks like Mocha or Jest that use describe()/it() without a tester object.
The same delegation applies to test.skip(), test.todo(), and test.asPromise().
test() registers a test that will be executed asynchronously later.
It returns a promise that resolves when the test is completed.
Generally tests will be executed in the order of their registration in the file.
In most cases there is no need to wait for the test to complete unless
you want to analyze the results of the test.
The situation is totally different for embedded tests because it may affect the order of execution.
Let's start with a simple synchronous test:
test('foo', t => {
t.pass();
});As you can see we don't mark our test as asynchronous and everything works as expected.
Now let's add an asynchronous embedded test:
test('bar', t => {
t.pass('pass #1');
t.test('nested', t => {
t.pass('nested pass');
});
t.pass('pass #2');
});Now if we run the test the result will be not exactly what we expected:
○ bar
✓ pass #1 - 0.856ms
✓ pass #2 - 0.041ms
○ nested
✓ nested pass - 0.05ms
✓ nested 1 0 - 0.157ms
✓ bar 3 0 - 1.877ms
You can see that the order of execution is not what we expected:
nested should be executed before pass #2 yet we can clearly see
that it is executed after pass #2.
If we make this test more elaborate:
test('bar', t => {
t.pass('pass #1');
t.test('nested #1', t => {
t.pass('nested #1 pass');
});
t.pass('pass #2');
t.test('nested #2', t => {
t.pass('nested #2 pass');
});
t.pass('pass #3');
});The result will be:
○ bar
✓ pass #1 - 0.894ms
✓ pass #2 - 0.051ms
✓ pass #3 - 0.011ms
○ nested #1
✓ nested #1 pass - 0.059ms
✓ nested #1 1 0 - 0.169ms
○ nested #2
✓ nested #2 pass - 0.048ms
✓ nested #2 1 0 - 0.116ms
✓ bar 5 0 - 2.217ms
As you can see all "synchronous" checks are executed before any asynchronous tests.
All asynchronous tests are executed at the end of an outer test in the order of their declaration.
The outer test (bar) didn't finish until all embedded tests were executed.
Every embedded test has waited for the previous test, if any, to finish.
Most probably it is not what you expected. How to fix it? Use async and await properly:
test('bar', async t => {
t.pass('pass #1');
await t.test('nested #1', t => {
t.pass('nested #1 pass');
});
t.pass('pass #2');
await t.test('nested #2', t => {
t.pass('nested #2 pass');
});
t.pass('pass #3');
});The result:
○ bar
✓ pass #1 - 0.866ms
○ nested #1
✓ nested #1 pass - 0.077ms
✓ nested #1 1 0 - 0.375ms
✓ pass #2 - 0.561ms
○ nested #2
✓ nested #2 pass - 0.039ms
✓ nested #2 1 0 - 0.123ms
✓ pass #3 - 0.187ms
✓ bar 5 0 - 2.156ms
Now this is what we really wanted.