tape-six 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/bin/tape6-bun.js +7 -8
- package/bin/tape6-deno.js +7 -8
- package/bin/tape6-node.js +25 -9
- package/bin/tape6-seq.js +7 -8
- package/index.d.ts +1 -1
- package/index.js +9 -0
- package/llms-full.txt +384 -0
- package/llms.txt +243 -0
- package/package.json +24 -8
- package/src/reporters/MinReporter.js +37 -0
- package/src/reporters/TTYReporter.js +4 -4
- package/src/runners/bun/worker.js +33 -5
- package/src/runners/deno/worker.js +33 -5
- package/src/runners/node/worker.js +34 -5
- package/src/runners/seq/TestWorker.js +68 -24
- package/src/test.js +6 -4
- package/src/utils/config.js +42 -4
- package/src/utils/listing.js +12 -20
- package/src/utils/fileSets.js +0 -114
package/README.md
CHANGED
|
@@ -99,11 +99,29 @@ And:
|
|
|
99
99
|
|
|
100
100
|
<img width="240" height="329" alt="image" src="https://github.com/user-attachments/assets/f3d8ac65-9e6a-499d-837f-0271146da1de" />
|
|
101
101
|
|
|
102
|
+
## Project structure
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
tape-six/
|
|
106
|
+
├── index.js # Main entry point, exports test, hooks, aliases
|
|
107
|
+
├── index.d.ts # TypeScript definitions for the public API
|
|
108
|
+
├── package.json # Package config; "tape6" section configures test discovery
|
|
109
|
+
├── bin/ # CLI utilities: tape6, tape6-server, tape6-node, tape6-bun, tape6-deno, tape6-seq
|
|
110
|
+
├── src/ # Source code (test engine, reporters, runners, utilities)
|
|
111
|
+
├── web-app/ # Browser test UI application
|
|
112
|
+
├── tests/ # Test files
|
|
113
|
+
├── ts-tests/ # TypeScript test files
|
|
114
|
+
├── wiki/ # GitHub wiki documentation (submodule)
|
|
115
|
+
└── vendors/ # Git submodules (deep6)
|
|
116
|
+
```
|
|
117
|
+
|
|
102
118
|
## Docs
|
|
103
119
|
|
|
104
120
|
The documentation can be found in the [wiki](https://github.com/uhop/tape-six/wiki).
|
|
105
121
|
See how it can be used in [tests/](https://github.com/uhop/tape-six/tree/master/tests).
|
|
106
122
|
|
|
123
|
+
For AI assistants: see [llms.txt](https://github.com/uhop/tape-six/blob/master/llms.txt) and [llms-full.txt](https://github.com/uhop/tape-six/blob/master/llms-full.txt) for LLM-optimized documentation.
|
|
124
|
+
|
|
107
125
|
The whole API is based on two objects: `test` and `Tester`.
|
|
108
126
|
|
|
109
127
|
### `test`
|
|
@@ -247,6 +265,8 @@ The following methods are available (all `msg` arguments are optional):
|
|
|
247
265
|
- `notStrictEquals()` — an alias of `notStrictEqual()`.
|
|
248
266
|
- `doesNotEqual()` — an alias of `notStrictEqual()`.
|
|
249
267
|
- `isUnequal()` — an alias of `notStrictEqual()`.
|
|
268
|
+
- `isNotEqual()` — an alias of `notStrictEqual()`.
|
|
269
|
+
- `isNot()` — an alias of `notStrictEqual()`.
|
|
250
270
|
- `looseEqual(a, b, msg)` — asserts that `a` and `b` are loosely equal.
|
|
251
271
|
- Loose equality is defined as `a == b`.
|
|
252
272
|
- `looseEquals()` — an alias of `looseEqual()`.
|
|
@@ -290,6 +310,7 @@ The following methods are available (all `msg` arguments are optional):
|
|
|
290
310
|
- Miscellaneous:
|
|
291
311
|
- `any` — returns the `any` object. It can be used in deep equivalency asserts to match any value.
|
|
292
312
|
See [deep6's any](https://github.com/uhop/deep6/wiki/any) for details.
|
|
313
|
+
- `_` — an alias of `any`.
|
|
293
314
|
- `plan(n)` — sets the number of tests in the test suite. Rarely used.
|
|
294
315
|
- `comment(msg)` — sends a comment to the test harness. Rarely used.
|
|
295
316
|
- `skipTest(...args, msg)` — skips the current test yet sends a message to the test harness.
|
|
@@ -390,6 +411,8 @@ Test output can be controlled by flags. See [Supported flags](https://github.com
|
|
|
390
411
|
|
|
391
412
|
The most recent releases:
|
|
392
413
|
|
|
414
|
+
- 1.7.2 _Minor internal refactoring and fixes._
|
|
415
|
+
- 1.7.1 _Added AI support, added timeout to start test runners, fixed some bugs in the sequential test runner._
|
|
393
416
|
- 1.7.0 _New features: after/before hooks for tests, aliases for `suite()`, `describe()`, `it()`, `tape6-seq` — an in-process sequential test runner. Improvements: stricter monochrome detection, refactoring, bugfixes, updated dev dependencies and the documentation._
|
|
394
417
|
- 1.6.0 _New features: support for `AssertionError` and 3rd-party assertion libraries based on it like `node:assert` and `chai`, support for `console.assert()`, support for `signal` to cancel asynchronous operations, tests wait for embedded tests, improved reporting of errors, updated dev dependencies._
|
|
395
418
|
- 1.5.1 _Better support for stopping parallel tests, better support for "failed to load" errors._
|
package/bin/tape6-bun.js
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import {fileURLToPath} from 'node:url';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
resolveTests,
|
|
7
|
+
resolvePatterns,
|
|
8
|
+
getReporterFileName,
|
|
9
|
+
getReporterType
|
|
10
|
+
} from '../src/utils/config.js';
|
|
6
11
|
|
|
7
12
|
import {getReporter, setReporter} from '../src/test.js';
|
|
8
13
|
import {selectTimer} from '../src/utils/timer.js';
|
|
@@ -85,17 +90,11 @@ const config = () => {
|
|
|
85
90
|
if (!parallel) parallel = globalThis.navigator?.hardwareConcurrency || 1;
|
|
86
91
|
};
|
|
87
92
|
|
|
88
|
-
const reporters = {
|
|
89
|
-
jsonl: 'JSONLReporter.js',
|
|
90
|
-
tap: 'TapReporter.js',
|
|
91
|
-
tty: 'TTYReporter.js'
|
|
92
|
-
};
|
|
93
|
-
|
|
94
93
|
const init = async () => {
|
|
95
94
|
const currentReporter = getReporter();
|
|
96
95
|
if (!currentReporter) {
|
|
97
96
|
const reporterType = getReporterType(),
|
|
98
|
-
reporterFile =
|
|
97
|
+
reporterFile = getReporterFileName(reporterType),
|
|
99
98
|
CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
|
|
100
99
|
hasColors = !(
|
|
101
100
|
options.monochrome ||
|
package/bin/tape6-deno.js
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import {fileURLToPath} from 'node:url';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
resolveTests,
|
|
7
|
+
resolvePatterns,
|
|
8
|
+
getReporterFileName,
|
|
9
|
+
getReporterType
|
|
10
|
+
} from '../src/utils/config.js';
|
|
6
11
|
|
|
7
12
|
import {getReporter, setReporter} from '../src/test.js';
|
|
8
13
|
import {selectTimer} from '../src/utils/timer.js';
|
|
@@ -85,17 +90,11 @@ const config = () => {
|
|
|
85
90
|
if (!parallel) parallel = globalThis.navigator?.hardwareConcurrency || 1;
|
|
86
91
|
};
|
|
87
92
|
|
|
88
|
-
const reporters = {
|
|
89
|
-
jsonl: 'JSONLReporter.js',
|
|
90
|
-
tap: 'TapReporter.js',
|
|
91
|
-
tty: 'TTYReporter.js'
|
|
92
|
-
};
|
|
93
|
-
|
|
94
93
|
const init = async () => {
|
|
95
94
|
const currentReporter = getReporter();
|
|
96
95
|
if (!currentReporter) {
|
|
97
96
|
const reporterType = getReporterType(),
|
|
98
|
-
reporterFile =
|
|
97
|
+
reporterFile = getReporterFileName(reporterType),
|
|
99
98
|
CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
|
|
100
99
|
hasColors = !(
|
|
101
100
|
options.monochrome ||
|
package/bin/tape6-node.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import process from 'node:process';
|
|
4
|
+
import os from 'node:os';
|
|
4
5
|
import {fileURLToPath} from 'node:url';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
resolveTests,
|
|
9
|
+
resolvePatterns,
|
|
10
|
+
getReporterFileName,
|
|
11
|
+
getReporterType
|
|
12
|
+
} from '../src/utils/config.js';
|
|
7
13
|
|
|
8
14
|
import {getReporter, setReporter} from '../src/test.js';
|
|
9
15
|
import {selectTimer} from '../src/utils/timer.js';
|
|
@@ -83,20 +89,25 @@ const config = () => {
|
|
|
83
89
|
} else {
|
|
84
90
|
parallel = 0;
|
|
85
91
|
}
|
|
86
|
-
if (!parallel)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
if (!parallel) {
|
|
93
|
+
if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {
|
|
94
|
+
parallel = navigator.hardwareConcurrency;
|
|
95
|
+
} else {
|
|
96
|
+
try {
|
|
97
|
+
parallel = os.availableParallelism();
|
|
98
|
+
} catch (e) {
|
|
99
|
+
void e;
|
|
100
|
+
parallel = 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
93
104
|
};
|
|
94
105
|
|
|
95
106
|
const init = async () => {
|
|
96
107
|
const currentReporter = getReporter();
|
|
97
108
|
if (!currentReporter) {
|
|
98
109
|
const reporterType = getReporterType(),
|
|
99
|
-
reporterFile =
|
|
110
|
+
reporterFile = getReporterFileName(reporterType),
|
|
100
111
|
CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
|
|
101
112
|
hasColors = !(
|
|
102
113
|
options.monochrome ||
|
|
@@ -125,6 +136,11 @@ const main = async () => {
|
|
|
125
136
|
console.error('UNHANDLED ERROR:', origin, error)
|
|
126
137
|
);
|
|
127
138
|
|
|
139
|
+
if (!files.length) {
|
|
140
|
+
console.log('No files found.');
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
128
144
|
const reporter = getReporter(),
|
|
129
145
|
worker = new TestWorker(reporter, parallel, options);
|
|
130
146
|
|
package/bin/tape6-seq.js
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
import process from 'node:process';
|
|
4
4
|
import {fileURLToPath} from 'node:url';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
resolveTests,
|
|
8
|
+
resolvePatterns,
|
|
9
|
+
getReporterFileName,
|
|
10
|
+
getReporterType
|
|
11
|
+
} from '../src/utils/config.js';
|
|
7
12
|
|
|
8
13
|
import {getReporter, setReporter, setConfiguredFlag, testRunner} from '../src/test.js';
|
|
9
14
|
import {selectTimer} from '../src/utils/timer.js';
|
|
@@ -68,17 +73,11 @@ const config = () => {
|
|
|
68
73
|
options.flags = flags;
|
|
69
74
|
};
|
|
70
75
|
|
|
71
|
-
const reporters = {
|
|
72
|
-
jsonl: 'JSONLReporter.js',
|
|
73
|
-
tap: 'TapReporter.js',
|
|
74
|
-
tty: 'TTYReporter.js'
|
|
75
|
-
};
|
|
76
|
-
|
|
77
76
|
const init = async () => {
|
|
78
77
|
const currentReporter = getReporter();
|
|
79
78
|
if (!currentReporter) {
|
|
80
79
|
const reporterType = getReporterType(),
|
|
81
|
-
reporterFile =
|
|
80
|
+
reporterFile = getReporterFileName(reporterType),
|
|
82
81
|
CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
|
|
83
82
|
hasColors = !(
|
|
84
83
|
options.monochrome ||
|
package/index.d.ts
CHANGED
|
@@ -629,7 +629,7 @@ export declare interface Tester {
|
|
|
629
629
|
is(a: unknown, b: unknown, message?: string): void;
|
|
630
630
|
|
|
631
631
|
/**
|
|
632
|
-
* Asserts that `actual` is
|
|
632
|
+
* Asserts that `actual` is strictly equal to `expected`. Alias of `strictEqual`.
|
|
633
633
|
* @param actual - The actual value
|
|
634
634
|
* @param expected - The expected value
|
|
635
635
|
* @param message - Optional message to display if the assertion fails
|
package/index.js
CHANGED
|
@@ -110,6 +110,9 @@ const init = async () => {
|
|
|
110
110
|
if (Deno.env.get('TAPE6_JSONL')) {
|
|
111
111
|
const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
|
|
112
112
|
reporter = new JSONLReporter({...options, originalConsole, hasColors});
|
|
113
|
+
} else if (Deno.env.get('TAPE6_MIN')) {
|
|
114
|
+
const {MinReporter} = await import('./src/reporters/MinReporter.js');
|
|
115
|
+
reporter = new MinReporter({...options, originalConsole});
|
|
113
116
|
} else if (!Deno.env.get('TAPE6_TAP')) {
|
|
114
117
|
const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
|
|
115
118
|
reporter = new TTYReporter({...options, originalConsole, hasColors});
|
|
@@ -124,6 +127,9 @@ const init = async () => {
|
|
|
124
127
|
if (Bun.env.TAPE6_JSONL) {
|
|
125
128
|
const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
|
|
126
129
|
reporter = new JSONLReporter({...options, originalConsole, hasColors});
|
|
130
|
+
} else if (Bun.env.TAPE6_MIN) {
|
|
131
|
+
const {MinReporter} = await import('./src/reporters/MinReporter.js');
|
|
132
|
+
reporter = new MinReporter({...options, originalConsole});
|
|
127
133
|
} else if (!Bun.env.TAPE6_TAP) {
|
|
128
134
|
const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
|
|
129
135
|
reporter = new TTYReporter({...options, originalConsole, hasColors});
|
|
@@ -138,6 +144,9 @@ const init = async () => {
|
|
|
138
144
|
if (process.env.TAPE6_JSONL) {
|
|
139
145
|
const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
|
|
140
146
|
reporter = new JSONLReporter({...options, originalConsole, hasColors});
|
|
147
|
+
} else if (process.env.TAPE6_MIN) {
|
|
148
|
+
const {MinReporter} = await import('./src/reporters/MinReporter.js');
|
|
149
|
+
reporter = new MinReporter({...options, originalConsole});
|
|
141
150
|
} else if (!process.env.TAPE6_TAP) {
|
|
142
151
|
const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
|
|
143
152
|
reporter = new TTYReporter({...options, originalConsole, hasColors});
|
package/llms-full.txt
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# tape-six
|
|
2
|
+
|
|
3
|
+
> A TAP-based unit testing library for modern JavaScript (ES6+). Works in Node, Deno, Bun, and browsers. Runs ES modules natively, supports TypeScript without transpilation. The npm package name is `tape-six` but all internal names use `tape6`.
|
|
4
|
+
|
|
5
|
+
- Minimal, zero-dependency test library with a familiar API
|
|
6
|
+
- Test files are directly executable: `node test.js`, `bun run test.js`, `deno run -A test.js`
|
|
7
|
+
- Parallel test execution via worker threads
|
|
8
|
+
- TAP, TTY (colored), and JSONL output formats
|
|
9
|
+
- Browser testing with built-in web UI and automation support (Puppeteer, Playwright)
|
|
10
|
+
- Before/after hooks: `beforeAll`, `afterAll`, `beforeEach`, `afterEach`
|
|
11
|
+
- `test()` is aliased as `suite()`, `describe()`, and `it()` for easy migration
|
|
12
|
+
- Compatible with `AssertionError`-based libraries like `node:assert` and `chai`
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
Install:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i -D tape-six
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Write a test (`tests/test-example.js`):
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import test from 'tape-six';
|
|
26
|
+
|
|
27
|
+
test('example', t => {
|
|
28
|
+
t.ok(true, 'truthy');
|
|
29
|
+
t.equal(1 + 1, 2, 'math works');
|
|
30
|
+
t.deepEqual([1, 2], [1, 2], 'arrays match');
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Run it directly:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node tests/test-example.js
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or run all configured tests:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx tape6 --flags FO
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Importing
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import test from 'tape-six';
|
|
50
|
+
// or: import {test} from 'tape-six';
|
|
51
|
+
// or: import {test, beforeAll, afterAll, beforeEach, afterEach} from 'tape-six';
|
|
52
|
+
// or: import {describe, it} from 'tape-six';
|
|
53
|
+
|
|
54
|
+
// CommonJS:
|
|
55
|
+
// const {test} = require('tape-six');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## test() API
|
|
59
|
+
|
|
60
|
+
`test` registers a test suite. All three arguments are optional and recognized by type:
|
|
61
|
+
|
|
62
|
+
- `async test(name, options, testFn)` — registers a test suite.
|
|
63
|
+
- `test.skip(name, options, testFn)` — registers a skipped test suite.
|
|
64
|
+
- `test.todo(name, options, testFn)` — registers a TODO test suite (failures not counted).
|
|
65
|
+
- `test.asPromise(name, options, testPromiseFn)` — registers a callback-style test: `testPromiseFn(tester, resolve, reject)`.
|
|
66
|
+
|
|
67
|
+
Arguments:
|
|
68
|
+
|
|
69
|
+
- `name` (string, optional) — test name. Defaults to function name or `'(anonymous)'`.
|
|
70
|
+
- `options` (object, optional):
|
|
71
|
+
- `name` — overridden by the `name` argument.
|
|
72
|
+
- `skip` (boolean) — skip this test.
|
|
73
|
+
- `todo` (boolean) — mark as TODO.
|
|
74
|
+
- `timeout` (number, ms) — timeout for async tests.
|
|
75
|
+
- `beforeAll`, `afterAll`, `beforeEach`, `afterEach` — hook functions.
|
|
76
|
+
- `before` — alias for `beforeAll`.
|
|
77
|
+
- `after` — alias for `afterAll`.
|
|
78
|
+
- `testFn` (function) — `async testFn(tester)`. Can be sync or async.
|
|
79
|
+
|
|
80
|
+
Flexible call signatures:
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
test(name, options, testFn);
|
|
84
|
+
test(name, testFn);
|
|
85
|
+
test(testFn);
|
|
86
|
+
test(name, options);
|
|
87
|
+
test(options, testFn);
|
|
88
|
+
test(options);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
test('foo', t => {
|
|
95
|
+
t.pass();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('bar', async t => {
|
|
99
|
+
const result = await fetchData();
|
|
100
|
+
t.equal(result.status, 200);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test.skip('not ready yet', t => {
|
|
104
|
+
t.fail();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test.todo('work in progress', t => {
|
|
108
|
+
t.ok(false); // reported but not counted as failure
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test.asPromise('callback style', (t, resolve, reject) => {
|
|
112
|
+
const stream = getStream();
|
|
113
|
+
stream.on('end', resolve);
|
|
114
|
+
stream.on('error', reject);
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Embedded tests
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
test('top', async t => {
|
|
122
|
+
t.pass();
|
|
123
|
+
await t.test('nested', async t => {
|
|
124
|
+
t.pass();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Always `await` embedded tests to preserve execution order.
|
|
130
|
+
|
|
131
|
+
## Tester API
|
|
132
|
+
|
|
133
|
+
The `Tester` object is passed to test functions. All `msg` arguments are optional.
|
|
134
|
+
|
|
135
|
+
### Properties
|
|
136
|
+
|
|
137
|
+
- `signal` — `AbortSignal` triggered when the test is stopped or timed out.
|
|
138
|
+
- `any` (alias `_`) — wildcard for deep equality matching.
|
|
139
|
+
|
|
140
|
+
### Assert methods
|
|
141
|
+
|
|
142
|
+
- `pass(msg)` — assert pass.
|
|
143
|
+
- `fail(msg)` — assert fail.
|
|
144
|
+
- `ok(val, msg)` — assert truthy. Aliases: `true()`, `assert()`.
|
|
145
|
+
- `notOk(val, msg)` — assert falsy. Aliases: `false()`, `notok()`.
|
|
146
|
+
- `error(err, msg)` — assert err is falsy. Aliases: `ifError()`, `ifErr()`, `iferror()`.
|
|
147
|
+
- `strictEqual(a, b, msg)` — assert `a === b`. Aliases: `is()`, `equal()`, `isEqual()`, `equals()`, `strictEquals()`.
|
|
148
|
+
- `notStrictEqual(a, b, msg)` — assert `a !== b`. Aliases: `not()`, `notEqual()`, `notEquals()`, `notStrictEquals()`, `doesNotEqual()`, `isUnequal()`, `isNotEqual()`, `isNot()`.
|
|
149
|
+
- `looseEqual(a, b, msg)` — assert `a == b`. Alias: `looseEquals()`.
|
|
150
|
+
- `notLooseEqual(a, b, msg)` — assert `a != b`. Alias: `notLooseEquals()`.
|
|
151
|
+
- `deepEqual(a, b, msg)` — deep strict equality. Aliases: `same()`, `deepEquals()`, `isEquivalent()`.
|
|
152
|
+
- `notDeepEqual(a, b, msg)` — not deeply equal. Aliases: `notSame()`, `notDeepEquals()`, `notEquivalent()`, `notDeeply()`, `isNotDeepEqual()`, `isNotEquivalent()`.
|
|
153
|
+
- `deepLooseEqual(a, b, msg)` — deep loose equality.
|
|
154
|
+
- `notDeepLooseEqual(a, b, msg)` — not deeply loosely equal.
|
|
155
|
+
- `throws(fn, msg)` — assert fn throws.
|
|
156
|
+
- `doesNotThrow(fn, msg)` — assert fn does not throw.
|
|
157
|
+
- `matchString(string, regexp, msg)` — assert string matches regexp.
|
|
158
|
+
- `doesNotMatchString(string, regexp, msg)` — assert string does not match regexp.
|
|
159
|
+
- `match(a, b, msg)` — deep structural match (supports wildcards).
|
|
160
|
+
- `doesNotMatch(a, b, msg)` — assert no deep match.
|
|
161
|
+
- `rejects(promise, msg)` — assert promise rejects (async, await it). Alias: `doesNotResolve()`.
|
|
162
|
+
- `resolves(promise, msg)` — assert promise resolves (async, await it). Alias: `doesNotReject()`.
|
|
163
|
+
|
|
164
|
+
### Embedded test methods
|
|
165
|
+
|
|
166
|
+
- `test(name, options, testFn)` — nested test suite (async, await it).
|
|
167
|
+
- `skip(name, options, testFn)` — skip nested suite.
|
|
168
|
+
- `todo(name, options, testFn)` — TODO nested suite.
|
|
169
|
+
- `asPromise(name, options, testPromiseFn)` — callback-style nested suite.
|
|
170
|
+
|
|
171
|
+
### Hooks
|
|
172
|
+
|
|
173
|
+
- `beforeAll(fn)` / `before(fn)` — run before first nested test.
|
|
174
|
+
- `afterAll(fn)` / `after(fn)` — run after last nested test.
|
|
175
|
+
- `beforeEach(fn)` — run before each nested test.
|
|
176
|
+
- `afterEach(fn)` — run after each nested test.
|
|
177
|
+
|
|
178
|
+
### Miscellaneous
|
|
179
|
+
|
|
180
|
+
- `plan(n)` — set expected number of assertions.
|
|
181
|
+
- `comment(msg)` — send a comment to the reporter.
|
|
182
|
+
- `skipTest(...args, msg)` — skip current test with a message.
|
|
183
|
+
- `bailOut(msg)` — abort the test suite.
|
|
184
|
+
|
|
185
|
+
### Expression evaluator
|
|
186
|
+
|
|
187
|
+
- `OK(condition, msg, options)` — returns code string for `eval()`. Aliases: `TRUE()`, `ASSERT()`.
|
|
188
|
+
- `condition`: a JavaScript expression as a string.
|
|
189
|
+
- On failure, reports values of all variables in the expression.
|
|
190
|
+
- `options.self`: tester variable name (default: `"t"`).
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
test('evaluator', t => {
|
|
194
|
+
const a = 1, b = 2;
|
|
195
|
+
eval(t.OK('a + b === 3'));
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Before and after hooks
|
|
200
|
+
|
|
201
|
+
Hooks are scoped — they only affect tests at their level.
|
|
202
|
+
|
|
203
|
+
Top-level hooks (affect top-level tests only):
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
import {test, beforeAll, afterAll, beforeEach, afterEach} from 'tape-six';
|
|
207
|
+
|
|
208
|
+
beforeAll(() => { /* runs once before first top-level test */ });
|
|
209
|
+
afterAll(() => { /* runs once after last top-level test */ });
|
|
210
|
+
beforeEach(() => { /* runs before each top-level test */ });
|
|
211
|
+
afterEach(() => { /* runs after each top-level test */ });
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Nested hooks (via tester object):
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
test('suite', async t => {
|
|
218
|
+
t.beforeEach(() => { /* before each nested test */ });
|
|
219
|
+
t.afterEach(() => { /* after each nested test */ });
|
|
220
|
+
|
|
221
|
+
await t.test('test 1', t => t.pass());
|
|
222
|
+
await t.test('test 2', t => t.pass());
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Hooks via options (reusable):
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
const opts = {
|
|
230
|
+
beforeEach: () => setupDb(),
|
|
231
|
+
afterEach: () => teardownDb()
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
test('suite', opts, async t => {
|
|
235
|
+
await t.test('test 1', t => t.pass());
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Multiple hooks of the same type run in registration order (before) or reverse order (after).
|
|
240
|
+
|
|
241
|
+
## Configuring tests
|
|
242
|
+
|
|
243
|
+
Configuration is read from `tape6.json` or the `"tape6"` section of `package.json`:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"tape6": {
|
|
248
|
+
"tests": ["/tests/test-*.*js"],
|
|
249
|
+
"cli": ["/tests/test-*.cjs"],
|
|
250
|
+
"browser": ["/tests/web/test-*.html"],
|
|
251
|
+
"importmap": {
|
|
252
|
+
"imports": {
|
|
253
|
+
"tape-six": "/node_modules/tape-six/index.js",
|
|
254
|
+
"tape-six/": "/node_modules/tape-six/src/"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Environment-specific subsections: `node`, `deno`, `bun`, `browser`.
|
|
262
|
+
|
|
263
|
+
## Command-line utilities
|
|
264
|
+
|
|
265
|
+
### tape6
|
|
266
|
+
|
|
267
|
+
Runs test files in parallel using worker threads.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
tape6 [--flags FLAGS] [--par N] [tests...]
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
- `--flags FLAGS` — output control flags (see below).
|
|
274
|
+
- `--par N` — number of parallel workers (default: all CPU cores).
|
|
275
|
+
- No arguments: runs tests from configuration.
|
|
276
|
+
|
|
277
|
+
### tape6-seq
|
|
278
|
+
|
|
279
|
+
Sequential in-process runner. Same options as `tape6` but no threads.
|
|
280
|
+
|
|
281
|
+
### tape6-server
|
|
282
|
+
|
|
283
|
+
Web server for browser testing:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
tape6-server [--trace] [--port N]
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Default port: 3000. Navigate to `http://localhost:3000` for the web UI.
|
|
290
|
+
|
|
291
|
+
### Runtime-specific runners
|
|
292
|
+
|
|
293
|
+
- `tape6-node` — Node.js runner.
|
|
294
|
+
- `tape6-bun` — Bun runner.
|
|
295
|
+
- `tape6-deno` — Deno runner.
|
|
296
|
+
|
|
297
|
+
## Supported flags
|
|
298
|
+
|
|
299
|
+
Flags are a string of characters. Uppercase = enabled, lowercase = disabled.
|
|
300
|
+
|
|
301
|
+
- `F` — Failures only: show only failed tests.
|
|
302
|
+
- `T` — show Time for each test.
|
|
303
|
+
- `B` — show Banner with summary.
|
|
304
|
+
- `D` — show Data of failed tests.
|
|
305
|
+
- `O` — fail Once: stop at first failure.
|
|
306
|
+
- `N` — show assert Number.
|
|
307
|
+
- `M` — Monochrome: no colors.
|
|
308
|
+
- `C` — don't Capture console output.
|
|
309
|
+
- `H` — Hide streams and console output.
|
|
310
|
+
|
|
311
|
+
Usage:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
tape6 --flags FO
|
|
315
|
+
TAPE6_FLAGS=FO node tests/test-example.js
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Browser: `http://localhost:3000/?flags=FO`
|
|
319
|
+
|
|
320
|
+
## Environment variables
|
|
321
|
+
|
|
322
|
+
- `TAPE6_FLAGS` — flags string.
|
|
323
|
+
- `TAPE6_PAR` — number of parallel workers.
|
|
324
|
+
- `TAPE6_TAP` — force TAP reporter (any non-empty value).
|
|
325
|
+
- `TAPE6_JSONL` — force JSONL reporter (any non-empty value).
|
|
326
|
+
- `TAPE6_TEST_FILE_NAME` — set by runners to identify the current test file.
|
|
327
|
+
|
|
328
|
+
## Browser testing
|
|
329
|
+
|
|
330
|
+
1. Start the server: `npm start` (runs `tape6-server --trace`).
|
|
331
|
+
2. Open `http://localhost:3000` for the web UI.
|
|
332
|
+
3. Or automate with Puppeteer/Playwright:
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
// Puppeteer example
|
|
336
|
+
import puppeteer from 'puppeteer';
|
|
337
|
+
const browser = await puppeteer.launch({headless: true});
|
|
338
|
+
const page = await browser.newPage();
|
|
339
|
+
page.on('console', msg => console.log(msg.text()));
|
|
340
|
+
await page.exposeFunction('__tape6_reportResults', async text => {
|
|
341
|
+
await browser.close();
|
|
342
|
+
process.exit(text === 'success' ? 0 : 1);
|
|
343
|
+
});
|
|
344
|
+
await page.goto('http://localhost:3000/tests/web/test-simple.html?flags=M');
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
// Playwright example
|
|
349
|
+
import {chromium} from 'playwright';
|
|
350
|
+
const browser = await chromium.launch({headless: true});
|
|
351
|
+
const page = await browser.newPage();
|
|
352
|
+
page.on('console', msg => console.log(msg.text()));
|
|
353
|
+
await page.exposeFunction('__tape6_reportResults', async text => {
|
|
354
|
+
await browser.close();
|
|
355
|
+
process.exit(text === 'success' ? 0 : 1);
|
|
356
|
+
});
|
|
357
|
+
await page.goto('http://localhost:3000/tests/web/test-simple.html?flags=M');
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## 3rd-party assertion libraries
|
|
361
|
+
|
|
362
|
+
`tape-six` supports `AssertionError`-based assertions. You can use `node:assert` or `chai` inside test functions:
|
|
363
|
+
|
|
364
|
+
```js
|
|
365
|
+
import test from 'tape-six';
|
|
366
|
+
import {assert, expect} from 'chai';
|
|
367
|
+
|
|
368
|
+
test('with chai', t => {
|
|
369
|
+
expect(1).to.be.lessThan(2);
|
|
370
|
+
assert.deepEqual([1], [1]);
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
import test from 'tape-six';
|
|
376
|
+
import assert from 'node:assert/strict';
|
|
377
|
+
|
|
378
|
+
test('with node:assert', t => {
|
|
379
|
+
assert.equal(1 + 1, 2);
|
|
380
|
+
assert.deepEqual({a: 1}, {a: 1});
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Assertions that throw `AssertionError` are automatically caught and reported.
|