3rd‐party assertion libraries - uhop/tape-six GitHub Wiki
3rd-party assertion libraries
tape-six doesn't bundle a third-party assertion library. Instead, it catches whatever your test code throws and reports it as a failure. Two cases get nicer formatting:
AssertionError— anything throwing a node-compatibleAssertionError(withname === 'AssertionError', anoperatorfield, andactual/expectedproperties) is counted as a regular assertion and rendered with stack trace, actual, and expected values.- Other thrown errors — caught and reported as
UNEXPECTED EXCEPTIONwith the message and stack. Less pretty, but the test still fails as it should.
Practical consequence: bring whatever assertion style you like. If it throws AssertionError, you get great output for free. If it throws something else, wrap it in t.throws() for negative cases, or use it inline and accept the exception-style render for positive failures.
Quick check: does my library throw AssertionError?
A 5-line probe:
import test from 'tape-six';
import {expect} from 'some-library';
test('shape probe', t => {
let err;
try {
expect(1).toBe(2);
} catch (e) {
err = e;
}
t.comment(`name = ${err?.name}`);
t.comment(`is AssertionError? ${err?.name === 'AssertionError'}`);
});
Run once; the comments tell you which path you're on.
Verified libraries
node:assert
Built into Node, Bun, and Deno. Throws AssertionError. Best path for AssertionError integration without an extra dependency:
import assert from 'node:assert';
import test from 'tape-six';
test('node:assert', t => {
t.pass('before');
assert.strict.deepEqual([1], [1]);
assert.strict.equal(1 + 1, 2);
t.pass('after');
});
Failures produce a clean diff:
not ok 2 AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
operator: deepStrictEqual
expected: [2]
actual: [1]
Not available in browsers — use chai for the same shape across runtimes.
chai
Throws AssertionError. Three styles (expect, should, assert) all flow through the same path:
import {expect, assert} from 'chai';
import test from 'tape-six';
test('chai expect', t => {
t.pass('before');
expect([1]).to.deep.equal([1]);
expect(1 + 1).to.equal(2);
t.pass('after');
});
test('chai assert', t => {
assert.deepEqual([1], [1]);
assert.equal(1 + 1, 2);
});
Failures render with chai's diff and tape-six's stack trace.
Browser tests need an importmap entry
Browser tests load modules through the importmap configured in package.json under tape6.importmap. Add an entry pointing at chai's installed copy so import {expect} from 'chai' resolves:
{
"tape6": {
"tests": ["/tests/test-*.js"],
"importmap": {
"imports": {
"tape-six": "/node_modules/tape-six/index.js",
"tape-six/": "/node_modules/tape-six/src/",
"chai": "/node_modules/chai/index.js"
}
}
}
}
Same pattern for any third-party module a browser test imports — the file path is whatever node_modules ships as the entry point. Node, Bun, and Deno don't need this; they resolve chai through their own module systems.
expect (Jest's standalone package)
The expect package extracted from Jest. Throws plain Error with name === 'Error', not AssertionError. The error has a matcherResult property and a colorized message.
It works, but with caveats:
- Failures render as
UNEXPECTED EXCEPTIONrather than as named assertions. - Default messages are wrapped in ANSI color codes; the JSONL/TAP output looks noisy.
- Not counted as an assertion — only the failure shows up.
import {expect} from 'expect';
import test from 'tape-six';
test('expect — passing assertions', t => {
t.pass('before');
expect([1, 2]).toEqual([1, 2]);
expect({a: 1}).toMatchObject({a: 1});
t.pass('after');
});
test('expect — negative case via t.throws', t => {
t.throws(() => expect(1).toBe(2));
});
Recommendation: use native t.* assertions in tape-six tests; use expect only when porting from Jest and you want to keep the matcher syntax during the transition.
Notable differences
tape-sixassertions don't terminate the test. A failedt.equal()records the failure and the test keeps running. AssertionError-throwing assertions always stop the test on the first failure.- The
O(fail-once) flag changes tape-six to fail-fast — see Supported flags.
- The
tape-sixcounts passing assertions.t.equal(1, 1)shows up in the count;expect(1).toEqual(1)doesn't, because nothing is thrown to count.- Async pitfall. A throw from inside an async callback (e.g. an event handler) can be lost or misattributed. Native
t.*assertions report through the tester regardless of context. See the AsyncContext proposal for the moving target on the platform side.
See also
- Mock libraries —
node:testmock, sinon. - Property-based testing — fast-check.