An open API service indexing awesome lists of open source software.

https://github.com/tapjs/node-test-example


https://github.com/tapjs/node-test-example

Last synced: 2 months ago
JSON representation

Awesome Lists containing this project

README

        

# node-test-example

An example showing `node:test`, `node --test`, `import 'tap'` and
`tap run` being used together, and how they interoperate.

This contains a `test/tap.test.js` and `test/node.test.js`, which
both run essentially the same tests, one using
[`tap`](https://node-tap.org) and the other using
[`node:test`](https://nodejs.org/api/test.html)

## The tests fail!

I know. That's kinda the point.

* `npm run test:node` Executes both test suite files with the
`node --test` runner.
* `npm run test:tap` Execute both test suite files with the
`tap` runner.

In both cases, you can see that the results are pretty similar.

## Differences

- When running with the `tap` runner, they're almost identical.
The main thing is that the `node:test` doesn't provide
per-assertion reporting, so you only see a report on the test
block, and possibly the first failure, not all the assertions
within it.
- When running with the `node --test` runner, the `tap` test
provides diffs and source callsite printing, while the
`node:test` test shows a `console.log()` of the thrown Error.

Of course, the two runners produce very different output overall,
but they should both be pretty sensible.

Personally, I think the tap runner is a lot more useful, and
certainly if you write tests in TypeScript (or use tap's `import`
mocking) it's nice to not have to specify the `--loader` and
`--import` arguments explicitly.

But on the flip side, that fanciness comes with a cost. With
TypeScript disabled, `tap` runs these two tests in about 450ms on
my system (350ms or so with coverage disabled), while `node
--test` does it in around 170ms. In both cases, the
`test/tap.test.js` test takes around 150ms to run, and the
`test/node.test.js` takes under 10ms.

Real world tests doing complicated stuff would show a less
dramatic difference, so this is in no way a representative
benchmark, but as always, performance and features are
fundamentally opposed, because features require running code, and
not running code is always faster.

The goal of the `node:test` interoperability in node-tap is to
make it possible for you to get the best of both worlds. You
could have part of your test suite written as `node:test` tests,
if they don't need `t.mockImport` or TypeScript, and other tests
written in `tap`.

## Coverage

The `test:mix` and `test:cross` show using the `node --test` and
`tap` runners so that they dump coverage into the same folder.
Then you can use `tap report` to report on it.

## Enough talk! Show the output!

GitHub strips colors from README.md files. [A more representative
example with colors can be found on the node-tap
website.](https://node-tap.org/node-test-interop/#enough-talk!-show-the-output!)

Running with `tap`:

 FAIL  test/node.test.js 2 failed of 4 6.834ms

suite of tests that fail > uhoh, this one throws
suite of tests that fail > failer
FAIL test/tap.test.js 3 failed of 18 340ms
suite of tests that fail > uhoh, this one throws > Invalid time value lib/index.mjs:11:43
suite of tests that fail > failer > should be equal test/tap.test.js:35:7
suite of tests that fail > failer > should be equal test/tap.test.js:37:7


🌈 TEST COMPLETE 🌈


FAIL test/node.test.js 2 failed of 4 6.834ms
suite of tests that fail > uhoh, this one throws
test/node.test.js
20 })
21
22 test('suite of tests that fail', async t => {
23 await t.test('uhoh, this one throws', () => {
━━━━━━━━━━━━━
24 assert.equal(thrower(0), '1970-01-01T00:00:00.000Z')
25 assert.equal(thrower(1234567891011), '2009-02-13T23:31:31.011Z')
26 assert.equal(thrower({}), 'Invalid Date')
27 })
error origin: lib/index.mjs
8
9 // This is a function that throws, to show how both
10 // handle errors.
11 export const thrower = (n) => new Date(n).toISOString()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
13 // one that fails, to show how failures are handled
14 export const failer = (n) => String(n + 1)
error: Invalid time value
code: ERR_TEST_FAILURE
failureType: testCodeFailure
name: RangeError
Date.toISOString (<anonymous>)
thrower (lib/index.mjs:11:43)
TestContext.<anonymous> (test/node.test.js:26:18)
TestContext.<anonymous> (test/node.test.js:23:11)

suite of tests that fail > failer
test/node.test.js
26 assert.equal(thrower({}), 'Invalid Date')
27 })
28
29 await t.test('failer', () => {
━━━━━━━━━━━━━
30 assert.equal(failer(1), '2')
31 assert.equal(failer(-1), '0')
32 // expect to convert string numbers to Number, but doesn't
33 assert.equal(failer('1'), '2')
error origin: test/node.test.js
30 assert.equal(failer(1), '2')
31 assert.equal(failer(-1), '0')
32 // expect to convert string numbers to Number, but doesn't
33 assert.equal(failer('1'), '2')
━━━━━━━━━━━━━━
34 // expect to convert non-numerics to 0, but it doesn't
35 assert.equal(failer({}), '1')
36 })
37 })
--- expected
+++ actual
@@ -1,1 +1,1 @@
-"2"
+"11"
error: "'11' == '2'"
code: ERR_ASSERTION
failureType: testCodeFailure
name: AssertionError
operator: ==
TestContext.<anonymous> (test/node.test.js:33:12)
TestContext.<anonymous> (test/node.test.js:29:11)

FAIL test/tap.test.js 3 failed of 18 340ms
suite of tests that fail > uhoh, this one throws > Invalid time value
lib/index.mjs
8
9 // This is a function that throws, to show how both
10 // handle errors.
11 export const thrower = (n) => new Date(n).toISOString()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
13 // one that fails, to show how failures are handled
14 export const failer = (n) => String(n + 1)
type: RangeError
tapCaught: testFunctionThrow
Date.toISOString (<anonymous>)
thrower (lib/index.mjs:11:43)
Test.<anonymous> (test/tap.test.js:27:13)

suite of tests that fail > failer > should be equal
test/tap.test.js
32 t.equal(failer(1), '2')
33 t.equal(failer(-1), '0')
34 // expect to convert string numbers to Number, but doesn't
35 t.equal(failer('1'), '2')
━━━━━━━━━
36 // expect to convert non-numerics to 0, but it doesn't
37 t.equal(failer({}), '1')
38 t.end()
39 })
--- expected
+++ actual
@@ -1,1 +1,1 @@
-2
+11
compare: ===
Test.<anonymous> (test/tap.test.js:35:7)
Test.<anonymous> (test/tap.test.js:31:5)
test/tap.test.js:23:3

suite of tests that fail > failer > should be equal
test/tap.test.js
34 // expect to convert string numbers to Number, but doesn't
35 t.equal(failer('1'), '2')
36 // expect to convert non-numerics to 0, but it doesn't
37 t.equal(failer({}), '1')
━━━━━━━━━
38 t.end()
39 })
40
41 t.end()
--- expected
+++ actual
@@ -1,1 +1,1 @@
-1
+[object Object]1
compare: ===
Test.<anonymous> (test/tap.test.js:37:7)
Test.<anonymous> (test/tap.test.js:31:5)
test/tap.test.js:23:3

Asserts: 17 pass 5 fail 22 of 22 complete
Suites: 0 pass 2 fail 2 of 2 complete

# { total: 22, pass: 17, fail: 5 }
# time=459.924ms

Running with `node --test`:

 add (0.569917ms)

stringOrNull (0.063833ms)
suite of tests that fail
uhoh, this one throws (0.910959ms)
RangeError [Error]: Invalid time value
at Date.toISOString (<anonymous>)
at thrower (file:///Users/isaacs/dev/tapjs/node-test-example/lib/index.mjs:11:43)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:26:18)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)
at Test.start (node:internal/test_runner/test:542:17)
at TestContext.test (node:internal/test_runner/test:167:20)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:23:11)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)

failer (0.532708ms)
AssertionError [ERR_ASSERTION]: '11' == '2'
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:33:12)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)
at Test.start (node:internal/test_runner/test:542:17)
at TestContext.test (node:internal/test_runner/test:167:20)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:29:11)
at async Test.run (node:internal/test_runner/test:632:9)
at async Test.processPendingSubtests (node:internal/test_runner/test:374:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: '11',
expected: '2',
operator: '=='
}

suite of tests that fail (1.684292ms)

add (1.774ms)
stringOrNull (1.091ms)
suite of tests that fail
uhoh, this one throws (10.016ms)
Error: Invalid time value
| // This is a function that throws, to show how both
| // handle errors.
| export const thrower = (n) => new Date(n).toISOString()
| ------------------------------------------^
|
| // one that fails, to show how failures are handled
at Date.toISOString (<anonymous>)
at thrower (/Users/isaacs/dev/tapjs/node-test-example/lib/index.mjs:11:43)
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:27:13) {
type: 'RangeError',
tapCaught: 'testFunctionThrow'
}

failer (3.676ms)
Error: should be equal
--- expected
+++ actual
@@ -1,1 +1,1 @@
-2
+11
| t.equal(failer(-1), '0')
| // expect to convert string numbers to Number, but doesn't
| t.equal(failer('1'), '2')
| ------^
| // expect to convert non-numerics to 0, but it doesn't
| t.equal(failer({}), '1')
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:35:7)
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:31:5)
at /Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:23:3 {
compare: '==='
}

suite of tests that fail (17.681ms)

tests 9
suites 1
pass 4
fail 5
cancelled 0
skipped 0
todo 0
duration_ms 160.809375

failing tests:

test at file:/Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:23:11
uhoh, this one throws (0.910959ms)
RangeError [Error]: Invalid time value
at Date.toISOString (<anonymous>)
at thrower (file:///Users/isaacs/dev/tapjs/node-test-example/lib/index.mjs:11:43)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:26:18)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)
at Test.start (node:internal/test_runner/test:542:17)
at TestContext.test (node:internal/test_runner/test:167:20)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:23:11)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)

test at file:/Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:29:11
failer (0.532708ms)
AssertionError [ERR_ASSERTION]: '11' == '2'
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:33:12)
at Test.runInAsyncScope (node:async_hooks:206:9)
at Test.run (node:internal/test_runner/test:631:25)
at Test.start (node:internal/test_runner/test:542:17)
at TestContext.test (node:internal/test_runner/test:167:20)
at TestContext.<anonymous> (file:///Users/isaacs/dev/tapjs/node-test-example/test/node.test.js:29:11)
at async Test.run (node:internal/test_runner/test:632:9)
at async Test.processPendingSubtests (node:internal/test_runner/test:374:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: '11',
expected: '2',
operator: '=='
}

test at test/tap.test.js:24:5
uhoh, this one throws (10.016ms)
Error: Invalid time value
| // This is a function that throws, to show how both
| // handle errors.
| export const thrower = (n) => new Date(n).toISOString()
| ------------------------------------------^
|
| // one that fails, to show how failures are handled
at Date.toISOString (<anonymous>)
at thrower (/Users/isaacs/dev/tapjs/node-test-example/lib/index.mjs:11:43)
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:27:13) {
type: 'RangeError',
tapCaught: 'testFunctionThrow'
}

test at test/tap.test.js:31:5
failer (3.676ms)
Error: should be equal
--- expected
+++ actual
@@ -1,1 +1,1 @@
-2
+11
| t.equal(failer(-1), '0')
| // expect to convert string numbers to Number, but doesn't
| t.equal(failer('1'), '2')
| ------^
| // expect to convert non-numerics to 0, but it doesn't
| t.equal(failer({}), '1')
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:35:7)
at Test.<anonymous> (/Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:31:5)
at /Users/isaacs/dev/tapjs/node-test-example/test/tap.test.js:23:3 {
compare: '==='
}