tape-six 1.7.2 → 1.7.3

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
@@ -4,7 +4,7 @@
4
4
  [npm-url]: https://npmjs.org/package/tape-six
5
5
 
6
6
  `tape-six` is a [TAP](https://en.wikipedia.org/wiki/Test_Anything_Protocol)-based library for unit tests.
7
- It is written in the modern JavaScript for the modern JavaScript and works in [Node](https://nodejs.org/), [Deno](https://deno.land/), [Bun](https://bun.sh/) and browsers.
7
+ It is written in the modern JavaScript for the modern JavaScript and works in [Node](https://nodejs.org/), [Deno](https://deno.land/), [Bun](https://bun.sh/) and browsers. **Zero runtime dependencies.**
8
8
 
9
9
  It runs ES modules (`import`-based code) natively and supports CommonJS modules transparently using the built-in [ESM](https://nodejs.org/api/esm.html).
10
10
 
@@ -37,7 +37,7 @@ with existing unit test libraries:
37
37
  - The [DX](https://en.wikipedia.org/wiki/User_experience#Developer_experience) in browsers are usually abysmal.
38
38
  - Both console-based debugging and a UI to navigate results are properly supported.
39
39
  - Integration with browser automation tools is supported for automated testing.
40
- - Examples for such tools are [Playwright](https://playwright.dev/) and [Puppeteer](https://pptr.dev/) are provided.
40
+ - Examples for [Playwright](https://playwright.dev/) and [Puppeteer](https://pptr.dev/) are provided.
41
41
 
42
42
  ## How it looks
43
43
 
@@ -137,6 +137,8 @@ import test from 'tape-six';
137
137
  // const {default: test} = require('tape-six');
138
138
  ```
139
139
 
140
+ To help port tests from other frameworks, `test()` is aliased as `suite()`, `describe()` and `it()`. 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.
141
+
140
142
  This function registers a test suite. Available options:
141
143
 
142
144
  - `async test(name, options, testFn)` — registers a test suite to be executed asynchronously.
@@ -162,11 +164,15 @@ The arguments mentioned above are:
162
164
  - `name` — the optional name of the test suite. If not provided, it will be set to the name of the test function or `'(anonymous)'`.
163
165
  - Can be overridden by the `name` argument.
164
166
  - `timeout` — the optional timeout in milliseconds. It is used for asynchronous tests.
165
- - If the timeout is exceeded, the test suite will be marked as failed.
166
- - **Important:** JavaScript does not provide a generic way to cancel asynchronous operations.
167
- When the timeout is exceeded, `tape6` will stop waiting for the test to finish,
168
- but it will continue running in the background.
167
+ - If the timeout is exceeded, `tape6` will use the tester's `signal` to indicate cancellation and stop waiting for the test to finish.
169
168
  - The default: no timeout.
169
+ - Hooks:
170
+ - `beforeAll` — a function to be executed before all tests in the suite.
171
+ - `afterAll` — a function to be executed after all tests in the suite.
172
+ - `beforeEach` — a function to be executed before each test in the suite.
173
+ - `afterEach` — a function to be executed after each test in the suite.
174
+ - `before` — an alias for `beforeAll`.
175
+ - `after` — an alias for `afterAll`.
170
176
  - `testFn` — the optional test function to be executed (see below).
171
177
  - Can be overridden by the `testFn` argument.
172
178
  - `testPromiseFn` — the optional callback-based test function to be executed.
@@ -307,8 +313,11 @@ The following methods are available (all `msg` arguments are optional):
307
313
  - `skip(name, options, testFn)` — skips a test suite asynchronously. See `test.skip()` above.
308
314
  - `todo(name, options, testFn)` — runs a provisional test suite asynchronously. See `test.todo()` above.
309
315
  - `asPromise(name, options, testPromiseFn)` — runs a test suite asynchronously. See `test.asPromise()` above.
316
+ - Note: top-level `test()` and its aliases auto-delegate to `t.test()` when called inside a test body. Using `t.test()` directly is preferred.
317
+ - Properties:
318
+ - `signal` — an [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that fires when the test is aborted (e.g. on timeout or bail-out). Use it to cancel pending async operations.
310
319
  - Miscellaneous:
311
- - `any` — returns the `any` object. It can be used in deep equivalency asserts to match any value.
320
+ - `any` — a symbol that can be used in deep equivalency asserts to match any value.
312
321
  See [deep6's any](https://github.com/uhop/deep6/wiki/any) for details.
313
322
  - `_` — an alias of `any`.
314
323
  - `plan(n)` — sets the number of tests in the test suite. Rarely used.
@@ -339,7 +348,7 @@ test('Sample test', async t => {
339
348
 
340
349
  ### Before/after hooks
341
350
 
342
- `tape-six` supports scope-based before/after hooks: `beforeAll`, `afterAll`, `beforeEach`, `afterEach`, which can be used to set-up and tear-down a proper environment for tests. Read all about it in [before and after hooks](https://github.com/uhop/tape-six/wiki/Before-and-after-hooks).
351
+ `tape-six` supports scope-based before/after hooks: `beforeAll`, `afterAll`, `beforeEach`, `afterEach` (with `before`/`after` as aliases for `beforeAll`/`afterAll`), which can be used to set-up and tear-down a proper environment for tests. Like `test()` and its aliases, the top-level hook functions auto-delegate to the current tester when called inside a test body. Using `t.beforeAll()`, etc. is preferred. Read all about it in [before and after hooks](https://github.com/uhop/tape-six/wiki/Before-and-after-hooks).
343
352
 
344
353
  ### Running tests
345
354
 
@@ -411,6 +420,7 @@ Test output can be controlled by flags. See [Supported flags](https://github.com
411
420
 
412
421
  The most recent releases:
413
422
 
423
+ - 1.7.3 _Bug fixes in reporters, runners, and assertions. Documentation corrections and improvements._
414
424
  - 1.7.2 _Minor internal refactoring and fixes._
415
425
  - 1.7.1 _Added AI support, added timeout to start test runners, fixed some bugs in the sequential test runner._
416
426
  - 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._
package/TESTING.md ADDED
@@ -0,0 +1,756 @@
1
+ # Testing with tape-six
2
+
3
+ > This guide is for AI agents and developers working on projects that use `tape-six` for testing.
4
+ > It covers how to write tests, run them, and configure test discovery.
5
+
6
+ `tape-six` supports ES modules and CommonJS. TypeScript is supported natively — no transpilation needed (Node 22+, Deno, Bun all run `.ts` files directly).
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm i -D tape-six
12
+ ```
13
+
14
+ ## Quick start
15
+
16
+ Create a test file (e.g., `tests/test-example.js`):
17
+
18
+ ```js
19
+ import test from 'tape-six';
20
+
21
+ test('arithmetic', t => {
22
+ t.equal(2 + 2, 4, 'addition');
23
+ t.ok(10 > 5, 'comparison');
24
+ t.deepEqual({a: 1}, {a: 1}, 'deep equality');
25
+ });
26
+ ```
27
+
28
+ Run it directly:
29
+
30
+ ```bash
31
+ node tests/test-example.js
32
+ ```
33
+
34
+ Run all configured tests:
35
+
36
+ ```bash
37
+ npx tape6 --flags FO
38
+ ```
39
+
40
+ ## Writing tests
41
+
42
+ ### Importing
43
+
44
+ ES modules (`.js`, `.mjs`, `.ts`, `.mts`):
45
+
46
+ ```js
47
+ import test from 'tape-six';
48
+ // or named imports:
49
+ import {test, describe, it, beforeAll, afterAll, beforeEach, afterEach} from 'tape-six';
50
+ ```
51
+
52
+ CommonJS (`.cjs`, `.cts`):
53
+
54
+ ```js
55
+ const {test} = require('tape-six');
56
+ ```
57
+
58
+ ### Registering tests
59
+
60
+ `test(name, options, testFn)` — all arguments are optional, recognized by type.
61
+
62
+ ```js
63
+ test('name', t => {
64
+ t.pass('unconditional pass');
65
+ });
66
+
67
+ test('async test', async t => {
68
+ const result = await fetchData();
69
+ t.equal(result.status, 200, 'status OK');
70
+ });
71
+ ```
72
+
73
+ Aliases: `suite()`, `describe()`, `it()` — all identical to `test()`.
74
+
75
+ When called inside a test body, top-level functions (`test`, `it`, `describe`, and all hooks) automatically delegate to the current tester. Using `t.test()`, `t.before()`, etc. is still preferred because it makes the delegation explicit. The top-level form is convenient when porting tests from frameworks like Mocha or Jest:
76
+
77
+ ```js
78
+ import {describe, it, before, beforeEach} from 'tape-six';
79
+
80
+ describe('module', () => {
81
+ before(() => {
82
+ /* setup — same as t.before() */
83
+ });
84
+ beforeEach(() => {
85
+ /* per-test setup */
86
+ });
87
+
88
+ it('works', t => {
89
+ t.ok(true);
90
+ });
91
+
92
+ it('also works', t => {
93
+ t.equal(1 + 1, 2);
94
+ });
95
+ });
96
+ ```
97
+
98
+ ### Skip and TODO
99
+
100
+ ```js
101
+ test.skip('not ready', t => {
102
+ t.fail();
103
+ }); // skipped entirely
104
+ test.todo('in progress', t => {
105
+ t.equal(1, 2);
106
+ }); // runs, failures not counted
107
+ ```
108
+
109
+ ### Assertions
110
+
111
+ All `msg` arguments are optional. If omitted, a generic message is used.
112
+
113
+ | Method | Checks | Common aliases |
114
+ | ------------------------------------ | ------------------------------- | -------------------------------- |
115
+ | `t.pass(msg)` | Unconditional pass | |
116
+ | `t.fail(msg)` | Unconditional fail | |
117
+ | `t.ok(val, msg)` | `val` is truthy | `true`, `assert` |
118
+ | `t.notOk(val, msg)` | `val` is falsy | `false`, `notok` |
119
+ | `t.error(err, msg)` | `err` is falsy | `ifError`, `ifErr` |
120
+ | `t.equal(a, b, msg)` | `a === b` | `is`, `strictEqual`, `isEqual` |
121
+ | `t.notEqual(a, b, msg)` | `a !== b` | `not`, `notStrictEqual`, `isNot` |
122
+ | `t.deepEqual(a, b, msg)` | Deep strict equality | `same`, `isEquivalent` |
123
+ | `t.notDeepEqual(a, b, msg)` | Not deeply equal | `notSame`, `notEquivalent` |
124
+ | `t.looseEqual(a, b, msg)` | `a == b` | |
125
+ | `t.notLooseEqual(a, b, msg)` | `a != b` | |
126
+ | `t.deepLooseEqual(a, b, msg)` | Deep loose equality | |
127
+ | `t.notDeepLooseEqual(a, b, msg)` | Not deeply loosely equal | |
128
+ | `t.throws(fn, msg)` | `fn()` throws | |
129
+ | `t.doesNotThrow(fn, msg)` | `fn()` does not throw | |
130
+ | `t.matchString(str, re, msg)` | `str` matches `re` | |
131
+ | `t.doesNotMatchString(str, re, msg)` | `str` doesn't match `re` | |
132
+ | `t.match(a, b, msg)` | Structural pattern match | |
133
+ | `t.doesNotMatch(a, b, msg)` | No structural match | |
134
+ | `t.rejects(promise, msg)` | Promise rejects (**await it**) | `doesNotResolve` |
135
+ | `t.resolves(promise, msg)` | Promise resolves (**await it**) | `doesNotReject` |
136
+
137
+ ### Async assertions
138
+
139
+ `rejects` and `resolves` are async — always `await` them:
140
+
141
+ ```js
142
+ test('async asserts', async t => {
143
+ await t.rejects(Promise.reject(new Error('fail')), 'should reject');
144
+ await t.resolves(Promise.resolve(42), 'should resolve');
145
+ });
146
+ ```
147
+
148
+ ### Nested (embedded) tests
149
+
150
+ Tests can be nested. The preferred way is `t.test()` because it makes the delegation explicit. Top-level `test()`/`it()` are equivalent inside a test body — they auto-delegate to the current tester:
151
+
152
+ ```js
153
+ import {test, it} from 'tape-six';
154
+
155
+ test('suite', async t => {
156
+ // these two forms are equivalent:
157
+ await t.test('using t.test', t => {
158
+ t.pass();
159
+ });
160
+
161
+ await it('using top-level it()', t => {
162
+ t.ok(true);
163
+ });
164
+ });
165
+ ```
166
+
167
+ Embedded tests must be `await`ed to preserve execution order.
168
+
169
+ ### Hooks (setup/teardown)
170
+
171
+ Hooks are scoped — they only affect tests at their registration level.
172
+
173
+ `before` is an alias for `beforeAll`, `after` is an alias for `afterAll`. These aliases work everywhere: as named exports, on `test.before`/`test.after`, on `t.before`/`t.after`, and in options objects.
174
+
175
+ **Top-level hooks** (affect all top-level tests in the file):
176
+
177
+ ```js
178
+ import {test, beforeAll, afterAll, beforeEach, afterEach} from 'tape-six';
179
+ // or with aliases:
180
+ import {test, before, after, beforeEach, afterEach} from 'tape-six';
181
+
182
+ beforeAll(() => {
183
+ /* once before first test */
184
+ });
185
+ afterAll(() => {
186
+ /* once after last test */
187
+ });
188
+ beforeEach(() => {
189
+ /* before each test */
190
+ });
191
+ afterEach(() => {
192
+ /* after each test */
193
+ });
194
+ ```
195
+
196
+ **Nested hooks** (affect embedded tests within a suite):
197
+
198
+ The preferred way is `t.before()`/`t.after()` because it makes the scope explicit. Top-level `before()`/`after()` are equivalent inside a test body — they auto-delegate to the current tester:
199
+
200
+ ```js
201
+ import {test, before, after, beforeEach} from 'tape-six';
202
+
203
+ test('database tests', async t => {
204
+ let db;
205
+ // these use top-level functions — they auto-delegate to t:
206
+ before(async () => {
207
+ db = await connect();
208
+ });
209
+ after(async () => {
210
+ await db.close();
211
+ });
212
+ beforeEach(() => {
213
+ /* reset state */
214
+ });
215
+
216
+ // equivalent using t. methods:
217
+ // t.before(async () => { db = await connect(); });
218
+ // t.after(async () => { await db.close(); });
219
+ // t.beforeEach(() => { /* reset state */ });
220
+
221
+ await t.test('insert', async t => {
222
+ const result = await db.insert({name: 'Alice'});
223
+ t.ok(result.id, 'got an id');
224
+ });
225
+
226
+ await t.test('query', async t => {
227
+ const rows = await db.query('SELECT * FROM users');
228
+ t.ok(rows.length > 0, 'has rows');
229
+ });
230
+ });
231
+ ```
232
+
233
+ **Hooks via options** (reusable across tests):
234
+
235
+ ```js
236
+ const dbOpts = {
237
+ beforeEach: () => resetFixtures(),
238
+ afterEach: () => cleanupDb()
239
+ };
240
+
241
+ test('suite A', dbOpts, async t => {
242
+ /* ... */
243
+ });
244
+ test('suite B', dbOpts, async t => {
245
+ /* ... */
246
+ });
247
+ ```
248
+
249
+ ## Migrating from other test frameworks
250
+
251
+ `tape-six` supports `describe`/`it` and `before`/`after` aliases. When called inside a test body, all top-level functions automatically delegate to the current tester. This means migration from Mocha, Jest, or `node:test` is nearly mechanical — change the import and swap assertions.
252
+
253
+ ### Mocha / Jest → tape-six
254
+
255
+ ```js
256
+ // Mocha / Jest
257
+ describe('module', () => {
258
+ before(() => {
259
+ /* setup */
260
+ });
261
+ after(() => {
262
+ /* teardown */
263
+ });
264
+ beforeEach(() => {
265
+ /* per-test setup */
266
+ });
267
+
268
+ it('works', () => {
269
+ expect(1).toBe(1);
270
+ });
271
+ });
272
+ ```
273
+
274
+ ```js
275
+ // tape-six — just change the import and swap assertions
276
+ import {describe, it, before, after, beforeEach} from 'tape-six';
277
+
278
+ describe('module', () => {
279
+ before(() => {
280
+ /* setup */
281
+ });
282
+ after(() => {
283
+ /* teardown */
284
+ });
285
+ beforeEach(() => {
286
+ /* per-test setup */
287
+ });
288
+
289
+ it('works', t => {
290
+ t.equal(1, 1);
291
+ });
292
+ });
293
+ ```
294
+
295
+ Key differences from Mocha/Jest:
296
+
297
+ - **Assertions** use `t.equal`, `t.deepEqual`, etc. instead of `expect`.
298
+ - The test function receives a `t` argument for assertions.
299
+ - No magic globals — everything is imported explicitly.
300
+ - `it()` inside `describe()` is auto-delegated, no need to use `t.test()`.
301
+ - `before()`/`after()` inside `describe()` are auto-delegated, no need to use `t.before()`/`t.after()`.
302
+
303
+ ### Chai → tape-six
304
+
305
+ Chai is commonly used with Mocha and other test frameworks. Its `expect`/`should`/`assert` styles all throw `AssertionError`, which `tape-six` catches automatically. You can use Chai assertions directly inside `tape-six` tests, or replace them with `t.*` equivalents:
306
+
307
+ ```js
308
+ // Chai expect style
309
+ import {expect} from 'chai';
310
+
311
+ describe('module', () => {
312
+ it('works', () => {
313
+ expect(1 + 1).to.equal(2);
314
+ expect([1, 2]).to.deep.equal([1, 2]);
315
+ expect(true).to.be.ok;
316
+ expect(() => badFn()).to.throw();
317
+ });
318
+ });
319
+ ```
320
+
321
+ ```js
322
+ // tape-six — Chai assertions work as-is, or replace with t.*
323
+ import {describe, it} from 'tape-six';
324
+
325
+ describe('module', () => {
326
+ it('works', t => {
327
+ t.equal(1 + 1, 2);
328
+ t.deepEqual([1, 2], [1, 2]);
329
+ t.ok(true);
330
+ t.throws(() => badFn());
331
+ });
332
+ });
333
+ ```
334
+
335
+ You can also keep Chai alongside `tape-six` — failures are reported correctly either way:
336
+
337
+ ```js
338
+ import {describe, it} from 'tape-six';
339
+ import {expect} from 'chai';
340
+
341
+ describe('mixed assertions', () => {
342
+ it('uses both', t => {
343
+ expect(1).to.be.lessThan(2); // Chai — caught automatically
344
+ t.equal(1 + 1, 2); // tape-six native
345
+ });
346
+ });
347
+ ```
348
+
349
+ ### node:test → tape-six
350
+
351
+ ```js
352
+ // node:test
353
+ import {describe, it, before, after} from 'node:test';
354
+ import assert from 'node:assert/strict';
355
+
356
+ describe('module', () => {
357
+ before(() => {
358
+ /* setup */
359
+ });
360
+ it('works', () => {
361
+ assert.equal(1, 1);
362
+ });
363
+ });
364
+ ```
365
+
366
+ ```js
367
+ // tape-six — change import, optionally swap assert for t.*
368
+ import {describe, it, before} from 'tape-six';
369
+
370
+ describe('module', () => {
371
+ before(() => {
372
+ /* setup */
373
+ });
374
+ it('works', t => {
375
+ t.equal(1, 1);
376
+ });
377
+ });
378
+ ```
379
+
380
+ Note: you can also keep using `node:assert` inside tape-six tests — `AssertionError` is caught automatically (see [3rd-party assertion libraries](#3rd-party-assertion-libraries)).
381
+
382
+ ### Quick reference
383
+
384
+ | Mocha / Jest / node:test | tape-six equivalent |
385
+ | ----------------------------------- | ------------------------------------------------- |
386
+ | `describe(name, fn)` | `describe(name, fn)` — same |
387
+ | `it(name, fn)` | `it(name, t => { ... })` — same, but receives `t` |
388
+ | `before(fn)` | `before(fn)` — same (alias for `beforeAll`) |
389
+ | `after(fn)` | `after(fn)` — same (alias for `afterAll`) |
390
+ | `beforeEach(fn)` | `beforeEach(fn)` — same |
391
+ | `afterEach(fn)` | `afterEach(fn)` — same |
392
+ | `expect(a).toBe(b)` | `t.equal(a, b)` |
393
+ | `expect(a).toEqual(b)` | `t.deepEqual(a, b)` |
394
+ | `expect(a).toBeTruthy()` | `t.ok(a)` |
395
+ | `expect(fn).toThrow()` | `t.throws(fn)` |
396
+ | `assert.equal(a, b)` | `t.equal(a, b)` or keep `assert.equal` |
397
+ | `assert.deepEqual(a, b)` | `t.deepEqual(a, b)` or keep `assert.deepEqual` |
398
+ | `expect(a).to.equal(b)` (Chai) | `t.equal(a, b)` or keep `expect` |
399
+ | `expect(a).to.deep.equal(b)` (Chai) | `t.deepEqual(a, b)` or keep `expect` |
400
+ | `expect(a).to.be.ok` (Chai) | `t.ok(a)` or keep `expect` |
401
+ | `expect(fn).to.throw()` (Chai) | `t.throws(fn)` or keep `expect` |
402
+
403
+ ### Wildcard matching with `t.any`
404
+
405
+ Use `t.any` (or `t._`) in deep equality checks to match any value:
406
+
407
+ ```js
408
+ test('partial match', t => {
409
+ const result = {id: 123, name: 'Alice', createdAt: new Date()};
410
+ t.deepEqual(result, {id: 123, name: 'Alice', createdAt: t.any});
411
+ });
412
+ ```
413
+
414
+ ### Testing exceptions
415
+
416
+ ```js
417
+ test('errors', async t => {
418
+ t.throws(() => {
419
+ throw new Error('boom');
420
+ }, 'should throw');
421
+ t.doesNotThrow(() => 42, 'should not throw');
422
+ await t.rejects(Promise.reject(new Error('fail')), 'should reject');
423
+ await t.resolves(Promise.resolve(42), 'should resolve');
424
+ });
425
+ ```
426
+
427
+ ### 3rd-party assertion libraries
428
+
429
+ `tape-six` catches `AssertionError` automatically. You can use `chai` or `node:assert`:
430
+
431
+ ```js
432
+ import test from 'tape-six';
433
+ import {expect} from 'chai';
434
+
435
+ test('with chai', t => {
436
+ expect(1).to.be.lessThan(2);
437
+ expect([1, 2]).to.deep.equal([1, 2]);
438
+ });
439
+ ```
440
+
441
+ ```js
442
+ import test from 'tape-six';
443
+ import assert from 'node:assert/strict';
444
+
445
+ test('with node:assert', t => {
446
+ assert.equal(1 + 1, 2);
447
+ assert.deepEqual({a: 1}, {a: 1});
448
+ });
449
+ ```
450
+
451
+ ## Running tests
452
+
453
+ ### Single file
454
+
455
+ ```bash
456
+ node tests/test-example.js # Node.js
457
+ bun run tests/test-example.js # Bun
458
+ deno run -A tests/test-example.js # Deno
459
+ ```
460
+
461
+ ### All configured tests
462
+
463
+ ```bash
464
+ npx tape6 --flags FO # parallel (worker threads)
465
+ npx tape6-seq --flags FO # sequential (in-process, no workers)
466
+ npx tape6 --par 4 --flags FO # limit to 4 workers
467
+ ```
468
+
469
+ **`tape6` vs `tape6-seq`**: The default `tape6` runner spawns worker threads to run test files in parallel — faster, but each file runs in its own isolated context. `tape6-seq` runs all test files sequentially in a single process — slower, but useful for debugging, for tests that share state, or when worker threads are unavailable.
470
+
471
+ ### Selected test files
472
+
473
+ ```bash
474
+ npx tape6 --flags FO tests/test-foo.js tests/test-bar.js
475
+ npx tape6-seq --flags FO tests/test-foo.js tests/test-bar.js
476
+ ```
477
+
478
+ ### Typical package.json scripts
479
+
480
+ ```json
481
+ {
482
+ "scripts": {
483
+ "test": "tape6 --flags FO",
484
+ "test:bun": "tape6-bun --flags FO",
485
+ "test:deno": "tape6-deno --flags FO",
486
+ "test:seq": "tape6-seq --flags FO",
487
+ "test:seq:bun": "bun run `tape6-seq --self` --flags FO",
488
+ "test:seq:deno": "deno run -A `tape6-seq --self` --flags FO"
489
+ }
490
+ }
491
+ ```
492
+
493
+ ### Flags
494
+
495
+ Flags control test output. Uppercase = enabled, lowercase = disabled.
496
+
497
+ | Flag | Meaning |
498
+ | ---- | -------------------------------------- |
499
+ | `F` | **F**ailures only — hide passing tests |
500
+ | `O` | Fail **o**nce — stop at first failure |
501
+ | `T` | Show **t**ime for each test |
502
+ | `D` | Show **d**ata of failed tests |
503
+ | `B` | Show **b**anner with summary |
504
+ | `N` | Show assert **n**umber |
505
+ | `M` | **M**onochrome — no colors |
506
+ | `C` | Don't **c**apture console output |
507
+ | `H` | **H**ide streams and console output |
508
+
509
+ Common combinations: `FO` (failures only + stop at first), `FOT` (+ show time).
510
+
511
+ ### Environment variables
512
+
513
+ - `TAPE6_FLAGS` — flags string (alternative to `--flags`).
514
+ - `TAPE6_PAR` — number of parallel workers.
515
+ - `TAPE6_TAP` — force TAP output format.
516
+ - `TAPE6_JSONL` — force JSONL output format.
517
+
518
+ ## Configuring test discovery
519
+
520
+ Add to `package.json`:
521
+
522
+ ```json
523
+ {
524
+ "tape6": {
525
+ "tests": ["/tests/test-*.*js"],
526
+ "importmap": {
527
+ "imports": {
528
+ "tape-six": "/node_modules/tape-six/index.js",
529
+ "tape-six/": "/node_modules/tape-six/src/",
530
+ "my-package": "/src/index.js",
531
+ "my-package/": "/src/"
532
+ }
533
+ }
534
+ }
535
+ }
536
+ ```
537
+
538
+ - `tests` — glob patterns for test files (relative to project root with leading `/`). Common for all environments.
539
+ - `cli` — additional patterns for CLI-only environments (Node, Bun, Deno). Typically used for `.cjs` files.
540
+ - `node`, `deno`, `bun`, `browser` — additional patterns specific to a given environment. These are **not overrides** — they are added to `tests` (and `cli` for non-browser).
541
+ - `importmap` — import map for browser testing (standard [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) format).
542
+
543
+ Example with environment-specific tests:
544
+
545
+ ```json
546
+ {
547
+ "tape6": {
548
+ "node": ["/tests/node/test-*.js"],
549
+ "deno": ["/tests/deno/test-*.js"],
550
+ "browser": ["/tests/web/test-*.html"],
551
+ "tests": ["/tests/test-*.*js"],
552
+ "importmap": {
553
+ "imports": {
554
+ "tape-six": "/node_modules/tape-six/index.js",
555
+ "tape-six/": "/node_modules/tape-six/src/"
556
+ }
557
+ }
558
+ }
559
+ }
560
+ ```
561
+
562
+ In this example, running `tape6` on Node will execute tests matching `/tests/node/test-*.js` + `/tests/test-*.*js`. Running in a browser will execute `/tests/web/test-*.html` + `/tests/test-*.*js`.
563
+
564
+ ## Browser testing
565
+
566
+ Browser tests use `tape6-server`, a static file server bundled with `tape-six` that provides a web UI for running tests.
567
+
568
+ ### Setup
569
+
570
+ 1. Configure `importmap` in `package.json` so the browser can resolve bare imports:
571
+
572
+ ```json
573
+ {
574
+ "tape6": {
575
+ "tests": ["/tests/test-*.*js"],
576
+ "browser": ["/tests/web/test-*.html"],
577
+ "importmap": {
578
+ "imports": {
579
+ "tape-six": "/node_modules/tape-six/index.js",
580
+ "tape-six/": "/node_modules/tape-six/src/",
581
+ "my-package": "/src/index.js",
582
+ "my-package/": "/src/"
583
+ }
584
+ }
585
+ }
586
+ }
587
+ ```
588
+
589
+ 2. Start the server:
590
+
591
+ ```bash
592
+ npx tape6-server --trace
593
+ ```
594
+
595
+ 3. Open `http://localhost:3000` in a browser to see the web UI and run all configured tests.
596
+
597
+ ### Running all configured browser tests
598
+
599
+ Navigate to:
600
+
601
+ ```
602
+ http://localhost:3000/
603
+ ```
604
+
605
+ The web app fetches the configured test list from the server and runs them.
606
+
607
+ ### Running specific test files by name
608
+
609
+ Use the `?q=` query parameter (supports multiple values):
610
+
611
+ ```
612
+ http://localhost:3000/?q=/tests/test-foo.js&q=/tests/test-bar.js
613
+ ```
614
+
615
+ These are glob patterns resolved by the server, so wildcards work:
616
+
617
+ ```
618
+ http://localhost:3000/?q=/tests/test-sample.*js
619
+ ```
620
+
621
+ ### Running a single test file (HTML shim)
622
+
623
+ Create an HTML file that loads test scripts directly with an inline import map:
624
+
625
+ ```html
626
+ <!DOCTYPE html>
627
+ <html lang="en">
628
+ <head>
629
+ <meta charset="utf-8" />
630
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
631
+ <title>My tests</title>
632
+ <script type="importmap">
633
+ {
634
+ "imports": {
635
+ "tape-six": "/node_modules/tape-six/index.js",
636
+ "tape-six/": "/node_modules/tape-six/src/"
637
+ }
638
+ }
639
+ </script>
640
+ <script type="module" src="../test-sample.js"></script>
641
+ </head>
642
+ <body>
643
+ <h1>My tests</h1>
644
+ <p>See the console.</p>
645
+ </body>
646
+ </html>
647
+ ```
648
+
649
+ Navigate to the HTML file directly (e.g., `http://localhost:3000/tests/web/test-simple.html`). Results appear in the browser console. This approach does not use the web UI.
650
+
651
+ ### Flags and parallel execution in the browser
652
+
653
+ Append query parameters:
654
+
655
+ ```
656
+ http://localhost:3000/?flags=FO&par=3
657
+ ```
658
+
659
+ ### Browser automation
660
+
661
+ Use Puppeteer or Playwright to run browser tests from the command line:
662
+
663
+ ```js
664
+ import puppeteer from 'puppeteer';
665
+ const browser = await puppeteer.launch({headless: true});
666
+ const page = await browser.newPage();
667
+ page.on('console', msg => console.log(msg.text()));
668
+ await page.exposeFunction('__tape6_reportResults', async text => {
669
+ await browser.close();
670
+ process.exit(text === 'success' ? 0 : 1);
671
+ });
672
+ await page.goto('http://localhost:3000/?flags=M');
673
+ ```
674
+
675
+ ### Browser limitations
676
+
677
+ - Browsers cannot run TypeScript files directly — only `.js` and `.mjs`.
678
+ - Browsers cannot run CommonJS (`.cjs`) files.
679
+ - Browsers can run HTML shim files in addition to JS files.
680
+
681
+ ## Test file conventions
682
+
683
+ - **Naming**: `test-*.js`, `test-*.mjs`, `test-*.cjs`, `test-*.ts`, `test-*.mts`, `test-*.cts`.
684
+ - **Location**: typically `tests/` directory.
685
+ - **Self-contained**: each test file should be directly executable with `node`.
686
+ - **One concern per file**: group related tests in a single file, use embedded tests for sub-grouping.
687
+
688
+ ## Patterns for AI agents writing tests
689
+
690
+ ### Testing a new function
691
+
692
+ ```js
693
+ import test from 'tape-six';
694
+ import {myFunction} from 'my-package/my-module.js';
695
+
696
+ test('myFunction', async t => {
697
+ await t.test('returns correct result for basic input', t => {
698
+ t.deepEqual(myFunction(1, 2), {sum: 3, product: 2});
699
+ });
700
+
701
+ await t.test('handles edge cases', t => {
702
+ t.deepEqual(myFunction(0, 0), {sum: 0, product: 0});
703
+ t.throws(() => myFunction(null), 'throws on null input');
704
+ });
705
+
706
+ await t.test('async variant', async t => {
707
+ const result = await myFunction.async(1, 2);
708
+ t.equal(result.sum, 3);
709
+ });
710
+ });
711
+ ```
712
+
713
+ ### Testing a class
714
+
715
+ ```js
716
+ import test from 'tape-six';
717
+ import {MyClass} from 'my-package/my-class.js';
718
+
719
+ test('MyClass', async t => {
720
+ let instance;
721
+ t.beforeEach(() => {
722
+ instance = new MyClass();
723
+ });
724
+
725
+ await t.test('constructor', t => {
726
+ t.ok(instance, 'creates instance');
727
+ t.equal(instance.size, 0, 'starts empty');
728
+ });
729
+
730
+ await t.test('add', t => {
731
+ instance.add('item');
732
+ t.equal(instance.size, 1, 'size increases');
733
+ });
734
+
735
+ await t.test('remove', t => {
736
+ instance.add('item');
737
+ instance.remove('item');
738
+ t.equal(instance.size, 0, 'size decreases');
739
+ });
740
+ });
741
+ ```
742
+
743
+ ### Verifying after writing tests
744
+
745
+ ```bash
746
+ node tests/test-<name>.js # run your new test file directly
747
+ npm test # run full suite to check for regressions
748
+ ```
749
+
750
+ ## Links
751
+
752
+ - Full API reference: https://github.com/uhop/tape-six/wiki/Tester
753
+ - Hooks documentation: https://github.com/uhop/tape-six/wiki/Before-and-after-hooks
754
+ - Configuration: https://github.com/uhop/tape-six/wiki/Set-up-tests
755
+ - Supported flags: https://github.com/uhop/tape-six/wiki/Supported-flags
756
+ - npm: https://www.npmjs.com/package/tape-six
package/index.d.ts CHANGED
@@ -66,15 +66,15 @@ export declare interface Tester {
66
66
  /**
67
67
  * A symbol that can be used to match any value.
68
68
  */
69
- any: Symbol;
69
+ any: symbol;
70
70
 
71
71
  /**
72
72
  * A symbol that can be used to match any value. An alias of `any`.
73
73
  */
74
- _: Symbol;
74
+ _: symbol;
75
75
 
76
76
  /**
77
- * A signal that can be used to abort asynchronous operations. It is triggered when the test is ended.
77
+ * A signal that can be used to abort asynchronous operations. It is triggered when the test ends.
78
78
  */
79
79
  signal: AbortSignal;
80
80
 
@@ -287,7 +287,7 @@ export declare interface Tester {
287
287
  ): Promise<void>;
288
288
 
289
289
  /**
290
- * Runs non-asynchronous callback-based test.
290
+ * Runs a callback-based test wrapped in a promise.
291
291
  * @param name - The name of the test
292
292
  * @param fn - The test function
293
293
  * @param options - The test options
@@ -299,7 +299,7 @@ export declare interface Tester {
299
299
  ): Promise<void>;
300
300
 
301
301
  /**
302
- * Runs non-asynchronous callback-based test.
302
+ * Runs a callback-based test wrapped in a promise.
303
303
  * @param name - The name of the test
304
304
  * @param options - The test options
305
305
  * @param fn - The test function
@@ -311,7 +311,7 @@ export declare interface Tester {
311
311
  ): Promise<void>;
312
312
 
313
313
  /**
314
- * Runs non-asynchronous callback-based test.
314
+ * Runs a callback-based test wrapped in a promise.
315
315
  * @param fn - The test function
316
316
  * @param options - The test options
317
317
  * @param name - The name of the test
@@ -323,7 +323,7 @@ export declare interface Tester {
323
323
  ): Promise<void>;
324
324
 
325
325
  /**
326
- * Runs non-asynchronous callback-based test.
326
+ * Runs a callback-based test wrapped in a promise.
327
327
  * @param fn - The test function
328
328
  * @param name - The name of the test
329
329
  * @param options - The test options
@@ -335,7 +335,7 @@ export declare interface Tester {
335
335
  ): Promise<void>;
336
336
 
337
337
  /**
338
- * Runs non-asynchronous callback-based test.
338
+ * Runs a callback-based test wrapped in a promise.
339
339
  * @param options - The test options
340
340
  * @param fn - The test function
341
341
  * @param name - The name of the test
@@ -347,7 +347,7 @@ export declare interface Tester {
347
347
  ): Promise<void>;
348
348
 
349
349
  /**
350
- * Runs non-asynchronous callback-based test.
350
+ * Runs a callback-based test wrapped in a promise.
351
351
  * @param options - The test options
352
352
  * @param name - The name of the test
353
353
  * @param fn - The test function
@@ -425,8 +425,8 @@ export declare interface Tester {
425
425
  notOk(value: unknown, message?: string): void;
426
426
 
427
427
  /**
428
- * Asserts that `error` is an error and fails the test.
429
- * @param error - The error to test
428
+ * Asserts that `error` is falsy. If the value is truthy (e.g. an Error object), the assertion fails.
429
+ * @param error - The value to test
430
430
  * @param message - Optional message to display if the assertion fails
431
431
  */
432
432
  error(error: Error | null | unknown, message?: string): void;
@@ -600,22 +600,22 @@ export declare interface Tester {
600
600
  notok(value: unknown, message?: string): void;
601
601
 
602
602
  /**
603
- * Asserts that `error` is an error and fails the test. Alias of `error`.
604
- * @param error - The error to test
603
+ * Asserts that `error` is falsy. If the value is truthy (e.g. an Error object), the assertion fails. Alias of `error`.
604
+ * @param error - The value to test
605
605
  * @param message - Optional message to display if the assertion fails
606
606
  */
607
607
  ifError(error: Error | null | unknown, message?: string): void;
608
608
 
609
609
  /**
610
- * Asserts that `error` is an error and fails the test. Alias of `error`.
611
- * @param error - The error to test
610
+ * Asserts that `error` is falsy. If the value is truthy (e.g. an Error object), the assertion fails. Alias of `error`.
611
+ * @param error - The value to test
612
612
  * @param message - Optional message to display if the assertion fails
613
613
  */
614
614
  ifErr(error: Error | null | unknown, message?: string): void;
615
615
 
616
616
  /**
617
- * Asserts that `error` is an error and fails the test. Alias of `error`.
618
- * @param error - The error to test
617
+ * Asserts that `error` is falsy. If the value is truthy (e.g. an Error object), the assertion fails. Alias of `error`.
618
+ * @param error - The value to test
619
619
  * @param message - Optional message to display if the assertion fails
620
620
  */
621
621
  iferror(error: Error | null | unknown, message?: string): void;
@@ -1122,57 +1122,64 @@ export declare interface Test {
1122
1122
  }
1123
1123
 
1124
1124
  /**
1125
- * The main function, which is used to define tests. Many other functions are defined as properties of this function.
1125
+ * The main function used to define tests. When called inside a test body, it delegates to the current tester.
1126
+ * Many other functions are defined as properties of this function.
1126
1127
  */
1127
1128
  export declare const test: Test;
1128
1129
 
1129
1130
  /**
1130
- * An alias for `test`. Used for compatibility with other testing frameworks to define test suites.
1131
+ * An alias for `test`. When called inside a test body, it delegates to the current tester.
1131
1132
  */
1132
1133
  export declare const suite = test;
1133
1134
 
1134
1135
  /**
1135
- * An alias for `test`. Used for compatibility with other testing frameworks to define test suites.
1136
+ * An alias for `test`. When called inside a test body, it delegates to the current tester.
1136
1137
  */
1137
1138
  export declare const describe = test;
1138
1139
 
1139
1140
  /**
1140
- * An alias for `test`. Used for compatibility with other testing frameworks to define tests.
1141
+ * An alias for `test`. When called inside a test body, it delegates to the current tester.
1141
1142
  */
1142
1143
  export declare const it = test;
1143
1144
 
1144
1145
  /**
1145
1146
  * Registers a function that will be called before all 1st-level embedded tests in the current scope.
1147
+ * When called inside a test body, delegates to the current tester.
1146
1148
  * @param fn a hook function
1147
1149
  */
1148
1150
  export declare const beforeAll: typeof test.beforeAll;
1149
1151
 
1150
1152
  /**
1151
1153
  * Registers a function that will be called after all 1st-level embedded tests in the current scope.
1154
+ * When called inside a test body, delegates to the current tester.
1152
1155
  * @param fn a hook function
1153
1156
  */
1154
1157
  export declare const afterAll: typeof test.afterAll;
1155
1158
 
1156
1159
  /**
1157
1160
  * Registers a function that will be called before each 1st-level embedded test in the current scope.
1161
+ * When called inside a test body, delegates to the current tester.
1158
1162
  * @param fn a hook function
1159
1163
  */
1160
1164
  export declare const beforeEach: typeof test.beforeEach;
1161
1165
 
1162
1166
  /**
1163
1167
  * Registers a function that will be called after each 1st-level embedded test in the current scope.
1168
+ * When called inside a test body, delegates to the current tester.
1164
1169
  * @param fn a hook function
1165
1170
  */
1166
1171
  export declare const afterEach: typeof test.afterEach;
1167
1172
 
1168
1173
  /**
1169
1174
  * Registers a function that will be called before all 1st-level embedded tests in the current scope. An alias for `beforeAll()`.
1175
+ * When called inside a test body, delegates to the current tester.
1170
1176
  * @param fn a hook function
1171
1177
  */
1172
1178
  export declare const before: typeof test.before;
1173
1179
 
1174
1180
  /**
1175
1181
  * Registers a function that will be called after all 1st-level embedded tests in the current scope. An alias for `afterAll()`.
1182
+ * When called inside a test body, delegates to the current tester.
1176
1183
  * @param fn a hook function
1177
1184
  */
1178
1185
  export declare const after: typeof test.after;
package/llms-full.txt CHANGED
@@ -9,6 +9,7 @@
9
9
  - Browser testing with built-in web UI and automation support (Puppeteer, Playwright)
10
10
  - Before/after hooks: `beforeAll`, `afterAll`, `beforeEach`, `afterEach`
11
11
  - `test()` is aliased as `suite()`, `describe()`, and `it()` for easy migration
12
+ - When called inside a test body, top-level functions auto-delegate to the current tester
12
13
  - Compatible with `AssertionError`-based libraries like `node:assert` and `chai`
13
14
 
14
15
  ## Quick start
@@ -128,6 +129,20 @@ test('top', async t => {
128
129
 
129
130
  Always `await` embedded tests to preserve execution order.
130
131
 
132
+ Top-level `test()`/`it()`/`describe()` auto-delegate when called inside a test body, so these are equivalent:
133
+
134
+ ```js
135
+ import {describe, it, before, beforeEach} from 'tape-six';
136
+
137
+ describe('module', () => {
138
+ before(() => { /* setup */ });
139
+ beforeEach(() => { /* per-test setup */ });
140
+
141
+ it('works', t => { t.ok(true); });
142
+ it('also works', t => { t.equal(1, 1); });
143
+ });
144
+ ```
145
+
131
146
  ## Tester API
132
147
 
133
148
  The `Tester` object is passed to test functions. All `msg` arguments are optional.
@@ -163,17 +178,17 @@ The `Tester` object is passed to test functions. All `msg` arguments are optiona
163
178
 
164
179
  ### Embedded test methods
165
180
 
166
- - `test(name, options, testFn)` — nested test suite (async, await it).
181
+ - `test(name, options, testFn)` — nested test suite (async, await it). Top-level `test()`/`it()` also works.
167
182
  - `skip(name, options, testFn)` — skip nested suite.
168
183
  - `todo(name, options, testFn)` — TODO nested suite.
169
184
  - `asPromise(name, options, testPromiseFn)` — callback-style nested suite.
170
185
 
171
186
  ### Hooks
172
187
 
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.
188
+ - `beforeAll(fn)` / `before(fn)` — run before first nested test. Top-level `beforeAll()`/`before()` also works.
189
+ - `afterAll(fn)` / `after(fn)` — run after last nested test. Top-level `afterAll()`/`after()` also works.
190
+ - `beforeEach(fn)` — run before each nested test. Top-level `beforeEach()` also works.
191
+ - `afterEach(fn)` — run after each nested test. Top-level `afterEach()` also works.
177
192
 
178
193
  ### Miscellaneous
179
194
 
@@ -211,12 +226,16 @@ beforeEach(() => { /* runs before each top-level test */ });
211
226
  afterEach(() => { /* runs after each top-level test */ });
212
227
  ```
213
228
 
214
- Nested hooks (via tester object):
229
+ Nested hooks (top-level functions auto-delegate to current tester):
215
230
 
216
231
  ```js
232
+ import {test, beforeEach, afterEach} from 'tape-six';
233
+
217
234
  test('suite', async t => {
218
- t.beforeEach(() => { /* before each nested test */ });
219
- t.afterEach(() => { /* after each nested test */ });
235
+ beforeEach(() => { /* before each nested test */ });
236
+ afterEach(() => { /* after each nested test */ });
237
+
238
+ // equivalent: t.beforeEach(), t.afterEach()
220
239
 
221
240
  await t.test('test 1', t => t.pass());
222
241
  await t.test('test 2', t => t.pass());
@@ -323,6 +342,7 @@ Browser: `http://localhost:3000/?flags=FO`
323
342
  - `TAPE6_PAR` — number of parallel workers.
324
343
  - `TAPE6_TAP` — force TAP reporter (any non-empty value).
325
344
  - `TAPE6_JSONL` — force JSONL reporter (any non-empty value).
345
+ - `TAPE6_MIN` — force minimal reporter (any non-empty value).
326
346
  - `TAPE6_TEST_FILE_NAME` — set by runners to identify the current test file.
327
347
 
328
348
  ## Browser testing
package/llms.txt CHANGED
@@ -33,6 +33,7 @@ Registers a test. All three arguments are optional and can be in any order (reco
33
33
  Returns a promise that resolves when the test finishes. Usually no need to await.
34
34
 
35
35
  Aliases: `suite`, `describe`, `it` — all are the same function.
36
+ When called inside a test body, these (and all hook functions) automatically delegate to the current tester — no need to use `t.test()` or `t.before()` explicitly.
36
37
 
37
38
  ```js
38
39
  import {test, describe, it, suite} from 'tape-six';
@@ -97,7 +98,7 @@ The object passed to test functions. Provides assertions and test control.
97
98
 
98
99
  #### Embedded tests (all async, should be awaited)
99
100
 
100
- - `await t.test(name, options, testFn)` — nested test.
101
+ - `await t.test(name, options, testFn)` — nested test. Top-level `test()`/`it()` also works (auto-delegates).
101
102
  - `await t.skip(name, options, testFn)` — nested skipped test.
102
103
  - `await t.todo(name, options, testFn)` — nested TODO test.
103
104
  - `await t.asPromise(name, options, testPromiseFn)` — nested callback-style test.
@@ -122,12 +123,14 @@ afterAll(() => { /* runs once after all tests */ });
122
123
  beforeEach(() => { /* runs before each test */ });
123
124
  afterEach(() => { /* runs after each test */ });
124
125
 
125
- // Or inside a test:
126
+ // Inside a test — top-level functions auto-delegate to current tester:
126
127
  test('suite', async t => {
127
- t.beforeAll(() => { /* before embedded tests */ });
128
- t.afterAll(() => { /* after embedded tests */ });
129
- t.beforeEach(() => { /* before each embedded test */ });
130
- t.afterEach(() => { /* after each embedded test */ });
128
+ beforeAll(() => { /* before embedded tests */ });
129
+ afterAll(() => { /* after embedded tests */ });
130
+ beforeEach(() => { /* before each embedded test */ });
131
+ afterEach(() => { /* after each embedded test */ });
132
+
133
+ // equivalent: t.beforeAll(), t.afterAll(), t.beforeEach(), t.afterEach()
131
134
 
132
135
  await t.test('inner', t => { t.pass(); });
133
136
  });
@@ -198,9 +201,12 @@ test('partial match', t => {
198
201
  ### Using describe/it style
199
202
 
200
203
  ```js
201
- import {describe, it} from 'tape-six';
204
+ import {describe, it, before, beforeEach} from 'tape-six';
202
205
 
203
206
  describe('my module', () => {
207
+ before(() => { /* setup — auto-delegates to current tester */ });
208
+ beforeEach(() => { /* per-test setup */ });
209
+
204
210
  it('should work', t => {
205
211
  t.ok(true);
206
212
  });
@@ -223,6 +229,15 @@ npx tape6-seq # run sequentially (no worker threads)
223
229
  npx tape6-server --trace # start browser test server
224
230
  ```
225
231
 
232
+ ## Environment variables
233
+
234
+ - `TAPE6_FLAGS` — flags string.
235
+ - `TAPE6_PAR` — number of parallel workers.
236
+ - `TAPE6_TAP` — force TAP reporter (any non-empty value).
237
+ - `TAPE6_JSONL` — force JSONL reporter (any non-empty value).
238
+ - `TAPE6_MIN` — force minimal reporter (any non-empty value).
239
+ - `TAPE6_TEST_FILE_NAME` — set by runners to identify the current test file.
240
+
226
241
  ## Configuration (package.json)
227
242
 
228
243
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tape-six",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "TAP-based unit test library for Node, Deno, Bun, and browsers. ES modules, TypeScript, zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -61,7 +61,8 @@
61
61
  "bun",
62
62
  "nodejs",
63
63
  "tap-protocol",
64
- "cross-runtime"
64
+ "cross-runtime",
65
+ "zero-dependency"
65
66
  ],
66
67
  "author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (https://www.lazutkin.com/)",
67
68
  "funding": "https://github.com/sponsors/uhop",
@@ -78,7 +79,9 @@
78
79
  "web-app",
79
80
  "src",
80
81
  "llms.txt",
81
- "llms-full.txt"
82
+ "llms-full.txt",
83
+ "TESTING.md",
84
+ "workflows"
82
85
  ],
83
86
  "tape6": {
84
87
  "tests": [
@@ -101,7 +104,7 @@
101
104
  },
102
105
  "devDependencies": {
103
106
  "@types/chai": "^5.2.3",
104
- "@types/node": "^25.3.0",
107
+ "@types/node": "^25.3.1",
105
108
  "chai": "^6.2.2",
106
109
  "playwright": "^1.58.2",
107
110
  "puppeteer": "^24.37.5",
package/src/Tester.js CHANGED
@@ -236,7 +236,7 @@ export class Tester {
236
236
 
237
237
  deepLooseEqual(a, b, msg) {
238
238
  this.reporter.report({
239
- name: msg || 'should be loosely equal',
239
+ name: msg || 'should be deeply loosely equal',
240
240
  test: this.testNumber,
241
241
  marker: new Error(),
242
242
  time: this.timer.now(),
@@ -251,7 +251,7 @@ export class Tester {
251
251
 
252
252
  notDeepLooseEqual(a, b, msg) {
253
253
  this.reporter.report({
254
- name: msg || 'should not be loosely equal',
254
+ name: msg || 'should not be deeply loosely equal',
255
255
  test: this.testNumber,
256
256
  marker: new Error(),
257
257
  time: this.timer.now(),
@@ -1,16 +1,5 @@
1
1
  import Reporter from './Reporter.js';
2
2
 
3
- const getEnvVar = name => {
4
- if (typeof Deno == 'object' && Deno?.version) {
5
- return Deno.env.get(name);
6
- } else if (typeof Bun == 'object' && Bun?.version) {
7
- return Bun.env[name];
8
- } else if (typeof process == 'object' && process?.versions?.node) {
9
- return process.env[name];
10
- }
11
- return undefined;
12
- };
13
-
14
3
  export class MinReporter extends Reporter {
15
4
  constructor({failOnce = false, originalConsole} = {}) {
16
5
  super({failOnce});
@@ -76,7 +76,7 @@ export class Reporter {
76
76
  console: 'onConsole',
77
77
  stdout: 'onStdout',
78
78
  stderr: 'onStderr',
79
- bailOut: 'onBailOut'
79
+ 'bail-out': 'onBailOut'
80
80
  };
81
81
  }
82
82
 
@@ -1,7 +1,7 @@
1
1
  const DEFAULT_START_TIMEOUT = 5_000;
2
2
 
3
3
  const getTimeout = () => {
4
- const timeoutValue = Deno.env.get('TAPE6_WORKER_START TIMEOUT');
4
+ const timeoutValue = Deno.env.get('TAPE6_WORKER_START_TIMEOUT');
5
5
  if (!timeoutValue) return DEFAULT_START_TIMEOUT;
6
6
  let timeout = Number(timeoutValue);
7
7
  if (isNaN(timeout) || timeout <= 0 || timeout === Infinity) timeout = DEFAULT_START_TIMEOUT;
@@ -25,8 +25,8 @@ export class BypassReporter {
25
25
  return this.reporter.signal;
26
26
  }
27
27
 
28
- get abort() {
29
- return this.reporter.abort;
28
+ abort() {
29
+ this.reporter.abort();
30
30
  }
31
31
 
32
32
  report(event) {
package/src/test.js CHANGED
@@ -203,6 +203,7 @@ export const runTests = async tests => {
203
203
  });
204
204
  } else {
205
205
  tester.reporter.report({
206
+ type: 'assert',
206
207
  name: 'UNEXPECTED EXCEPTION: ' + String(error),
207
208
  test: testNumber,
208
209
  marker: new Error(),
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: Write or update tape-six tests for a module or feature
3
+ ---
4
+
5
+ # Write Tests
6
+
7
+ Write or update tests using the tape-six testing library.
8
+
9
+ ## Notes
10
+
11
+ - `tape-six` supports ES modules (`.js`, `.mjs`, `.ts`, `.mts`) and CommonJS (`.cjs`, `.cts`).
12
+ - TypeScript is supported natively — no transpilation needed (Node 22+, Deno, Bun run `.ts` files directly).
13
+ - The default `tape6` runner uses worker threads for parallel execution. `tape6-seq` runs sequentially in-process — useful for debugging or when tests share state.
14
+
15
+ ## Steps
16
+
17
+ 1. Read the testing guide at `node_modules/tape-six/TESTING.md` for API reference and patterns.
18
+ 2. Identify the module or feature to test. Read its source code to understand the public API.
19
+ 3. Create or update the test file in `tests/test-<name>.js` (or `.ts` for TypeScript projects):
20
+ - Import `test` from `tape-six` (ESM: `import test from 'tape-six'`; CJS: `const {test} = require('tape-six')`).
21
+ - Import the module under test using the project's package name.
22
+ - Write one top-level `test()` per logical group.
23
+ - Use embedded `await t.test()` for sub-cases.
24
+ - Use `t.beforeEach`/`t.afterEach` for shared setup/teardown.
25
+ - Cover: normal operation, edge cases, error conditions.
26
+ - Use `t.equal` for primitives, `t.deepEqual` for objects/arrays, `t.throws` for errors, `await t.rejects` for async errors.
27
+ - All `msg` arguments are optional but recommended for clarity.
28
+ // turbo
29
+ 4. Run the new test file directly to verify: `node tests/test-<name>.js`
30
+ // turbo
31
+ 5. Run the full test suite to check for regressions: `npm test`
32
+ - If debugging, use `npm run test:seq` (runs sequentially, easier to trace issues).
33
+ 6. Report results and any failures.