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 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()` &mdash; an alias of `notStrictEqual()`.
248
266
  - `doesNotEqual()` &mdash; an alias of `notStrictEqual()`.
249
267
  - `isUnequal()` &mdash; an alias of `notStrictEqual()`.
268
+ - `isNotEqual()` &mdash; an alias of `notStrictEqual()`.
269
+ - `isNot()` &mdash; an alias of `notStrictEqual()`.
250
270
  - `looseEqual(a, b, msg)` &mdash; asserts that `a` and `b` are loosely equal.
251
271
  - Loose equality is defined as `a == b`.
252
272
  - `looseEquals()` &mdash; an alias of `looseEqual()`.
@@ -290,6 +310,7 @@ The following methods are available (all `msg` arguments are optional):
290
310
  - Miscellaneous:
291
311
  - `any` &mdash; 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
+ - `_` &mdash; an alias of `any`.
293
314
  - `plan(n)` &mdash; sets the number of tests in the test suite. Rarely used.
294
315
  - `comment(msg)` &mdash; sends a comment to the test harness. Rarely used.
295
316
  - `skipTest(...args, msg)` &mdash; 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` &mdash; 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 {resolveTests, resolvePatterns, getReporterType} from '../src/utils/config.js';
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 = reporters[reporterType] || reporters.tty,
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 {resolveTests, resolvePatterns, getReporterType} from '../src/utils/config.js';
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 = reporters[reporterType] || reporters.tty,
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 {resolveTests, resolvePatterns, getReporterType} from '../src/utils/config.js';
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) parallel = globalThis.navigator?.hardwareConcurrency || 1;
87
- };
88
-
89
- const reporters = {
90
- jsonl: 'JSONLReporter.js',
91
- tap: 'TapReporter.js',
92
- tty: 'TTYReporter.js'
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 = reporters[reporterType] || reporters.tty,
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 {resolveTests, resolvePatterns, getReporterType} from '../src/utils/config.js';
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 = reporters[reporterType] || reporters.tty,
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 deeply equal to `expected`. Alias of `strictEqual`.
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.