1 | # tape <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
|
2 |
|
3 | tap-producing test harness for node and browsers
|
4 |
|
5 | [![github actions][actions-image]][actions-url]
|
6 | [![coverage][codecov-image]][codecov-url]
|
7 | [![dependency status][deps-svg]][deps-url]
|
8 | [![dev dependency status][dev-deps-svg]][dev-deps-url]
|
9 | [![License][license-image]][license-url]
|
10 | [![Downloads][downloads-image]][downloads-url]
|
11 |
|
12 | [![npm badge][npm-badge-png]][package-url]
|
13 |
|
14 | ![tape](https://web.archive.org/web/20170612184731if_/http://substack.net/images/tape_drive.png)
|
15 |
|
16 | # example
|
17 |
|
18 | ``` js
|
19 | var test = require('tape');
|
20 |
|
21 | test('timing test', function (t) {
|
22 | t.plan(2);
|
23 |
|
24 | t.equal(typeof Date.now, 'function');
|
25 | var start = Date.now();
|
26 |
|
27 | setTimeout(function () {
|
28 | t.equal(Date.now() - start, 100);
|
29 | }, 100);
|
30 | });
|
31 |
|
32 | test('test using promises', async function (t) {
|
33 | const result = await someAsyncThing();
|
34 | t.ok(result);
|
35 | });
|
36 | ```
|
37 |
|
38 | ```
|
39 | $ node example/timing.js
|
40 | TAP version 13
|
41 | # timing test
|
42 | ok 1 should be strictly equal
|
43 | not ok 2 should be strictly equal
|
44 | ---
|
45 | operator: equal
|
46 | expected: 100
|
47 | actual: 107
|
48 | ...
|
49 |
|
50 | 1..2
|
51 | # tests 2
|
52 | # pass 1
|
53 | # fail 1
|
54 | ```
|
55 |
|
56 | # usage
|
57 |
|
58 | You always need to `require('tape')` in test files. You can run the tests by usual node means (`require('test-file.js')` or `node test-file.js`).
|
59 | You can also run tests using the `tape` binary to utilize globbing, on Windows for example:
|
60 |
|
61 | ```sh
|
62 | $ tape tests/**/*.js
|
63 | ```
|
64 |
|
65 | `tape`'s arguments are passed to the [`glob`](https://www.npmjs.com/package/glob) module.
|
66 | If you want `glob` to perform the expansion on a system where the shell performs such expansion, quote the arguments as necessary:
|
67 |
|
68 | ```sh
|
69 | $ tape 'tests/**/*.js'
|
70 | $ tape "tests/**/*.js"
|
71 | ```
|
72 |
|
73 | ## Preloading modules
|
74 |
|
75 | Additionally, it is possible to make `tape` load one or more modules before running any tests, by using the `-r` or `--require` flag. Here's an example that loads [babel-register](http://babeljs.io/docs/usage/require/) before running any tests, to allow for JIT compilation:
|
76 |
|
77 | ```sh
|
78 | $ tape -r babel-register tests/**/*.js
|
79 | ```
|
80 |
|
81 | Depending on the module you're loading, you may be able to parameterize it using environment variables or auxiliary files. Babel, for instance, will load options from [`.babelrc`](http://babeljs.io/docs/usage/babelrc/) at runtime.
|
82 |
|
83 | The `-r` flag behaves exactly like node's `require`, and uses the same module resolution algorithm. This means that if you need to load local modules, you have to prepend their path with `./` or `../` accordingly.
|
84 |
|
85 | For example:
|
86 |
|
87 | ```sh
|
88 | $ tape -r ./my/local/module tests/**/*.js
|
89 | ```
|
90 |
|
91 | Please note that all modules loaded using the `-r` flag will run *before* any tests, regardless of when they are specified. For example, `tape -r a b -r c` will actually load `a` and `c` *before* loading `b`, since they are flagged as required modules.
|
92 |
|
93 | # things that go well with tape
|
94 |
|
95 | `tape` maintains a fairly minimal core. Additional features are usually added by using another module alongside `tape`.
|
96 |
|
97 | ## pretty reporters
|
98 |
|
99 | The default TAP output is good for machines and humans that are robots.
|
100 |
|
101 | If you want a more colorful / pretty output there are lots of modules on npm that will output something pretty if you pipe TAP into them:
|
102 |
|
103 | - [tap-spec](https://github.com/scottcorgan/tap-spec)
|
104 | - [tap-dot](https://github.com/scottcorgan/tap-dot)
|
105 | - [faucet](https://github.com/ljharb/faucet)
|
106 | - [tap-bail](https://github.com/juliangruber/tap-bail)
|
107 | - [tap-browser-color](https://github.com/kirbysayshi/tap-browser-color)
|
108 | - [tap-json](https://github.com/gummesson/tap-json)
|
109 | - [tap-min](https://github.com/derhuerst/tap-min)
|
110 | - [tap-nyan](https://github.com/calvinmetcalf/tap-nyan)
|
111 | - [tap-pessimist](https://www.npmjs.org/package/tap-pessimist)
|
112 | - [tap-prettify](https://github.com/toolness/tap-prettify)
|
113 | - [colortape](https://github.com/shuhei/colortape)
|
114 | - [tap-xunit](https://github.com/aghassemi/tap-xunit)
|
115 | - [tap-difflet](https://github.com/namuol/tap-difflet)
|
116 | - [tape-dom](https://github.com/gritzko/tape-dom)
|
117 | - [tap-diff](https://github.com/axross/tap-diff)
|
118 | - [tap-notify](https://github.com/axross/tap-notify)
|
119 | - [tap-summary](https://github.com/zoubin/tap-summary)
|
120 | - [tap-markdown](https://github.com/Hypercubed/tap-markdown)
|
121 | - [tap-html](https://github.com/gabrielcsapo/tap-html)
|
122 | - [tap-react-browser](https://github.com/mcnuttandrew/tap-react-browser)
|
123 | - [tap-junit](https://github.com/dhershman1/tap-junit)
|
124 | - [tap-nyc](https://github.com/MegaArman/tap-nyc)
|
125 | - [tap-spec (emoji patch)](https://github.com/Sceat/tap-spec-emoji)
|
126 | - [tape-repeater](https://github.com/rgruesbeck/tape-repeater)
|
127 | - [tabe](https://github.com/Josenzo/tabe)
|
128 |
|
129 | To use them, try `node test/index.js | tap-spec` or pipe it into one of the modules of your choice!
|
130 |
|
131 | ## uncaught exceptions
|
132 |
|
133 | By default, uncaught exceptions in your tests will not be intercepted, and will cause `tape` to crash. If you find this behavior undesirable, use [`tape-catch`](https://github.com/michaelrhodes/tape-catch) to report any exceptions as TAP errors.
|
134 |
|
135 | ## other
|
136 |
|
137 | - CoffeeScript support with https://www.npmjs.com/package/coffeetape
|
138 | - ES6 support with https://www.npmjs.com/package/babel-tape-runner or https://www.npmjs.com/package/buble-tape-runner
|
139 | - Different test syntax with https://github.com/pguth/flip-tape (warning: mutates String.prototype)
|
140 | - Electron test runner with https://github.com/tundrax/electron-tap
|
141 | - Concurrency support with https://github.com/imsnif/mixed-tape
|
142 | - In-process reporting with https://github.com/DavidAnson/tape-player
|
143 | - Describe blocks with https://github.com/mattriley/tape-describe
|
144 |
|
145 | # command-line flags
|
146 |
|
147 | While running tests, top-level configurations can be passed via the command line to specify desired behavior.
|
148 |
|
149 | Available configurations are listed below:
|
150 |
|
151 | ## --require
|
152 |
|
153 | **Alias**: `-r`
|
154 |
|
155 | This is used to load modules before running tests and is explained extensively in the [preloading modules](#preloading-modules) section.
|
156 |
|
157 | ## --ignore
|
158 |
|
159 | **Alias**: `-i`
|
160 |
|
161 | This flag is used when tests from certain folders and/or files are not intended to be run.
|
162 | The argument is a path to a file that contains the patterns to be ignored.
|
163 | It defaults to `.gitignore` when passed with no argument.
|
164 |
|
165 | ```sh
|
166 | tape -i .ignore '**/*.js'
|
167 | ```
|
168 |
|
169 | An error is thrown if the specified file passed as argument does not exist.
|
170 |
|
171 | ## --ignore-pattern
|
172 |
|
173 | Same functionality as `--ignore`, but passing the pattern directly instead of an ignore file.
|
174 | If both `--ignore` and `--ignore-pattern` are given, the `--ignore-pattern` argument is appended to the content of the ignore file.
|
175 |
|
176 | ```sh
|
177 | tape --ignore-pattern 'integration_tests/**/*.js' '**/*.js'
|
178 | ```
|
179 |
|
180 | ## --no-only
|
181 | This is particularly useful in a CI environment where an [only test](#testonlyname-opts-cb) is not supposed to go unnoticed.
|
182 |
|
183 | By passing the `--no-only` flag, any existing [only test](#testonlyname-opts-cb) causes tests to fail.
|
184 |
|
185 | ```sh
|
186 | tape --no-only **/*.js
|
187 | ```
|
188 |
|
189 | Alternatively, the environment variable `NODE_TAPE_NO_ONLY_TEST` can be set to `true` to achieve the same behavior; the command-line flag takes precedence.
|
190 |
|
191 | # methods
|
192 |
|
193 | The assertion methods in `tape` are heavily influenced or copied from the methods in [node-tap](https://github.com/isaacs/node-tap).
|
194 |
|
195 | ```js
|
196 | var test = require('tape')
|
197 | ```
|
198 |
|
199 | ## test([name], [opts], cb)
|
200 |
|
201 | Create a new test with an optional `name` string and optional `opts` object.
|
202 | `cb(t)` fires with the new test object `t` once all preceding tests have finished.
|
203 | Tests execute serially.
|
204 |
|
205 | Available `opts` options are:
|
206 | - opts.skip = true/false. See test.skip.
|
207 | - opts.timeout = 500. Set a timeout for the test, after which it will fail. See test.timeoutAfter.
|
208 | - opts.objectPrintDepth = 5. Configure max depth of expected / actual object printing. Environmental variable `NODE_TAPE_OBJECT_PRINT_DEPTH` can set the desired default depth for all tests; locally-set values will take precedence.
|
209 | - opts.todo = true/false. Test will be allowed to fail.
|
210 |
|
211 | If you forget to `t.plan()` out how many assertions you are going to run and you don't call `t.end()` explicitly, or return a Promise that eventually settles, your test will hang.
|
212 |
|
213 | If `cb` returns a Promise, it will be implicitly awaited. If that promise rejects, the test will be failed; if it fulfills, the test will end. Explicitly calling `t.end()` while also returning a Promise that fulfills is an error.
|
214 |
|
215 | ## test.skip([name], [opts], cb)
|
216 |
|
217 | Generate a new test that will be skipped over.
|
218 |
|
219 | ## test.onFinish(fn)
|
220 |
|
221 | The onFinish hook will get invoked when ALL `tape` tests have finished right before `tape` is about to print the test summary.
|
222 |
|
223 | `fn` is called with no arguments, and its return value is ignored.
|
224 |
|
225 | ## test.onFailure(fn)
|
226 |
|
227 | The onFailure hook will get invoked whenever any `tape` tests has failed.
|
228 |
|
229 | `fn` is called with no arguments, and its return value is ignored.
|
230 |
|
231 | ## t.plan(n)
|
232 |
|
233 | Declare that `n` assertions should be run. `t.end()` will be called automatically after the `n`th assertion.
|
234 | If there are any more assertions after the `n`th, or after `t.end()` is called, they will generate errors.
|
235 |
|
236 | ## t.end(err)
|
237 |
|
238 | Declare the end of a test explicitly. If `err` is passed in `t.end` will assert that it is falsy.
|
239 |
|
240 | Do not call `t.end()` if your test callback returns a Promise.
|
241 |
|
242 | ## t.teardown(cb)
|
243 |
|
244 | Register a callback to run after the individual test has completed. Multiple registered teardown callbacks will run in order. Useful for undoing side effects, closing network connections, etc.
|
245 |
|
246 | ## t.fail(msg)
|
247 |
|
248 | Generate a failing assertion with a message `msg`.
|
249 |
|
250 | ## t.pass(msg)
|
251 |
|
252 | Generate a passing assertion with a message `msg`.
|
253 |
|
254 | ## t.timeoutAfter(ms)
|
255 |
|
256 | Automatically timeout the test after X ms.
|
257 |
|
258 | ## t.skip(msg)
|
259 |
|
260 | Generate an assertion that will be skipped over.
|
261 |
|
262 | ## t.ok(value, msg)
|
263 |
|
264 | Assert that `value` is truthy with an optional description of the assertion `msg`.
|
265 |
|
266 | Aliases: `t.true()`, `t.assert()`
|
267 |
|
268 | ## t.notOk(value, msg)
|
269 |
|
270 | Assert that `value` is falsy with an optional description of the assertion `msg`.
|
271 |
|
272 | Aliases: `t.false()`, `t.notok()`
|
273 |
|
274 | ## t.error(err, msg)
|
275 |
|
276 | Assert that `err` is falsy. If `err` is non-falsy, use its `err.message` as the description message.
|
277 |
|
278 | Aliases: `t.ifError()`, `t.ifErr()`, `t.iferror()`
|
279 |
|
280 | ## t.equal(actual, expected, msg)
|
281 |
|
282 | Assert that `Object.is(actual, expected)` with an optional description of the assertion `msg`.
|
283 |
|
284 | Aliases: `t.equals()`, `t.isEqual()`, `t.strictEqual()`, `t.strictEquals()`, `t.is()`
|
285 |
|
286 | ## t.notEqual(actual, expected, msg)
|
287 |
|
288 | Assert that `!Object.is(actual, expected)` with an optional description of the assertion `msg`.
|
289 |
|
290 | Aliases: `t.notEquals()`, `t.isNotEqual()`, `t.doesNotEqual()`, `t.isInequal()`, `t.notStrictEqual()`, `t.notStrictEquals()`, `t.isNot()`, `t.not()`
|
291 |
|
292 | ## t.looseEqual(actual, expected, msg)
|
293 |
|
294 | Assert that `actual == expected` with an optional description of the assertion `msg`.
|
295 |
|
296 | Aliases: `t.looseEquals()`
|
297 |
|
298 | ## t.notLooseEqual(actual, expected, msg)
|
299 |
|
300 | Assert that `actual != expected` with an optional description of the assertion `msg`.
|
301 |
|
302 | Aliases: `t.notLooseEquals()`
|
303 |
|
304 | ## t.deepEqual(actual, expected, msg)
|
305 |
|
306 | Assert that `actual` and `expected` have the same structure and nested values using [node's deepEqual() algorithm](https://github.com/inspect-js/node-deep-equal) with strict comparisons (`===`) on leaf nodes and an optional description of the assertion `msg`.
|
307 |
|
308 | Aliases: `t.deepEquals()`, `t.isEquivalent()`, `t.same()`
|
309 |
|
310 | ## t.notDeepEqual(actual, expected, msg)
|
311 |
|
312 | Assert that `actual` and `expected` do not have the same structure and nested values using [node's deepEqual() algorithm](https://github.com/inspect-js/node-deep-equal) with strict comparisons (`===`) on leaf nodes and an optional description of the assertion `msg`.
|
313 |
|
314 | Aliases: `t.notDeepEquals`, `t.notEquivalent()`, `t.notDeeply()`, `t.notSame()`,
|
315 | `t.isNotDeepEqual()`, `t.isNotDeeply()`, `t.isNotEquivalent()`,
|
316 | `t.isInequivalent()`
|
317 |
|
318 | ## t.deepLooseEqual(actual, expected, msg)
|
319 |
|
320 | Assert that `actual` and `expected` have the same structure and nested values using [node's deepEqual() algorithm](https://github.com/inspect-js/node-deep-equal) with loose comparisons (`==`) on leaf nodes and an optional description of the assertion `msg`.
|
321 |
|
322 | ## t.notDeepLooseEqual(actual, expected, msg)
|
323 |
|
324 | Assert that `actual` and `expected` do not have the same structure and nested values using [node's deepEqual() algorithm](https://github.com/inspect-js/node-deep-equal) with loose comparisons (`==`) on leaf nodes and an optional description of the assertion `msg`.
|
325 |
|
326 | Aliases: `t.notLooseEqual()`, `t.notLooseEquals()`
|
327 |
|
328 | ## t.throws(fn, expected, msg)
|
329 |
|
330 | Assert that the function call `fn()` throws an exception. `expected`, if present, must be a `RegExp`, `Function`, or `Object`. The `RegExp` matches the string representation of the exception, as generated by `err.toString()`. For example, if you set `expected` to `/user/`, the test will pass only if the string representation of the exception contains the word `user`. Any other exception will result in a failed test. The `Function` is the exception thrown (e.g. `Error`). `Object` in this case corresponds to a so-called validation object, in which each property is tested for strict deep equality. As an example, see the following two tests--each passes a validation object to `t.throws()` as the second parameter. The first test will pass, because all property values in the actual error object are deeply strictly equal to the property values in the validation object.
|
331 | ```
|
332 | const err = new TypeError("Wrong value");
|
333 | err.code = 404;
|
334 | err.check = true;
|
335 |
|
336 | // Passing test.
|
337 | t.throws(
|
338 | () => {
|
339 | throw err;
|
340 | },
|
341 | {
|
342 | code: 404,
|
343 | check: true
|
344 | },
|
345 | "Test message."
|
346 | );
|
347 | ```
|
348 | This next test will fail, because all property values in the actual error object are _not_ deeply strictly equal to the property values in the validation object.
|
349 | ```
|
350 | const err = new TypeError("Wrong value");
|
351 | err.code = 404;
|
352 | err.check = "true";
|
353 |
|
354 | // Failing test.
|
355 | t.throws(
|
356 | () => {
|
357 | throw err;
|
358 | },
|
359 | {
|
360 | code: 404,
|
361 | check: true // This is not deeply strictly equal to err.check.
|
362 | },
|
363 | "Test message."
|
364 | );
|
365 | ```
|
366 |
|
367 | This is very similar to how Node's `assert.throws()` method tests validation objects (please see the [Node _assert.throws()_ documentation](https://nodejs.org/api/assert.html#assert_assert_throws_fn_error_message) for more information).
|
368 |
|
369 | If `expected` is not of type `RegExp`, `Function`, or `Object`, or omitted entirely, any exception will result in a passed test. `msg` is an optional description of the assertion.
|
370 |
|
371 | Please note that the second parameter, `expected`, cannot be of type `string`. If a value of type `string` is provided for `expected`, then `t.throws(fn, expected, msg)` will execute, but the value of `expected` will be set to `undefined`, and the specified string will be set as the value for the `msg` parameter (regardless of what _actually_ passed as the third parameter). This can cause unexpected results, so please be mindful.
|
372 |
|
373 | ## t.doesNotThrow(fn, expected, msg)
|
374 |
|
375 | Assert that the function call `fn()` does not throw an exception. `expected`, if present, limits what should not be thrown, and must be a `RegExp` or `Function`. The `RegExp` matches the string representation of the exception, as generated by `err.toString()`. For example, if you set `expected` to `/user/`, the test will fail only if the string representation of the exception contains the word `user`. Any other exception will result in a passed test. The `Function` is the exception thrown (e.g. `Error`). If `expected` is not of type `RegExp` or `Function`, or omitted entirely, any exception will result in a failed test. `msg` is an optional description of the assertion.
|
376 |
|
377 | Please note that the second parameter, `expected`, cannot be of type `string`. If a value of type `string` is provided for `expected`, then `t.doesNotThrows(fn, expected, msg)` will execute, but the value of `expected` will be set to `undefined`, and the specified string will be set as the value for the `msg` parameter (regardless of what _actually_ passed as the third parameter). This can cause unexpected results, so please be mindful.
|
378 |
|
379 | ## t.test(name, [opts], cb)
|
380 |
|
381 | Create a subtest with a new test handle `st` from `cb(st)` inside the current test `t`. `cb(st)` will only fire when `t` finishes. Additional tests queued up after `t` will not be run until all subtests finish.
|
382 |
|
383 | You may pass the same options that [`test()`](#testname-opts-cb) accepts.
|
384 |
|
385 | ## t.comment(message)
|
386 |
|
387 | Print a message without breaking the tap output. (Useful when using e.g. `tap-colorize` where output is buffered & `console.log` will print in incorrect order vis-a-vis tap output.)
|
388 |
|
389 | Multiline output will be split by `\n` characters, and each one printed as a comment.
|
390 |
|
391 | ## t.match(string, regexp, message)
|
392 |
|
393 | Assert that `string` matches the RegExp `regexp`. Will fail when the first two arguments are the wrong type.
|
394 |
|
395 | ## t.doesNotMatch(string, regexp, message)
|
396 |
|
397 | Assert that `string` does not match the RegExp `regexp`. Will fail when the first two arguments are the wrong type.
|
398 |
|
399 | ## var htest = test.createHarness()
|
400 |
|
401 | Create a new test harness instance, which is a function like `test()`, but with a new pending stack and test state.
|
402 |
|
403 | By default the TAP output goes to `console.log()`. You can pipe the output to someplace else if you `htest.createStream().pipe()` to a destination stream on the first tick.
|
404 |
|
405 | ## test.only([name], [opts], cb)
|
406 |
|
407 | Like `test([name], [opts], cb)` except if you use `.only` this is the only test case that will run for the entire process, all other test cases using `tape` will be ignored.
|
408 |
|
409 | Check out how the usage of [the --no-only flag](#--no-only) could help ensure there is no `.only` test running in a specified environment.
|
410 |
|
411 | ## var stream = test.createStream(opts)
|
412 |
|
413 | Create a stream of output, bypassing the default output stream that writes messages to `console.log()`. By default `stream` will be a text stream of TAP output, but you can get an object stream instead by setting `opts.objectMode` to `true`.
|
414 |
|
415 | ### tap stream reporter
|
416 |
|
417 | You can create your own custom test reporter using this `createStream()` api:
|
418 |
|
419 | ``` js
|
420 | var test = require('tape');
|
421 | var path = require('path');
|
422 |
|
423 | test.createStream().pipe(process.stdout);
|
424 |
|
425 | process.argv.slice(2).forEach(function (file) {
|
426 | require(path.resolve(file));
|
427 | });
|
428 | ```
|
429 |
|
430 | You could substitute `process.stdout` for whatever other output stream you want, like a network connection or a file.
|
431 |
|
432 | Pass in test files to run as arguments:
|
433 |
|
434 | ```sh
|
435 | $ node tap.js test/x.js test/y.js
|
436 | TAP version 13
|
437 | # (anonymous)
|
438 | not ok 1 should be strictly equal
|
439 | ---
|
440 | operator: equal
|
441 | expected: "boop"
|
442 | actual: "beep"
|
443 | ...
|
444 | # (anonymous)
|
445 | ok 2 should be strictly equal
|
446 | ok 3 (unnamed assert)
|
447 | # wheee
|
448 | ok 4 (unnamed assert)
|
449 |
|
450 | 1..4
|
451 | # tests 4
|
452 | # pass 3
|
453 | # fail 1
|
454 | ```
|
455 |
|
456 | ### object stream reporter
|
457 |
|
458 | Here's how you can render an object stream instead of TAP:
|
459 |
|
460 | ``` js
|
461 | var test = require('tape');
|
462 | var path = require('path');
|
463 |
|
464 | test.createStream({ objectMode: true }).on('data', function (row) {
|
465 | console.log(JSON.stringify(row))
|
466 | });
|
467 |
|
468 | process.argv.slice(2).forEach(function (file) {
|
469 | require(path.resolve(file));
|
470 | });
|
471 | ```
|
472 |
|
473 | The output for this runner is:
|
474 |
|
475 | ```sh
|
476 | $ node object.js test/x.js test/y.js
|
477 | {"type":"test","name":"(anonymous)","id":0}
|
478 | {"id":0,"ok":false,"name":"should be strictly equal","operator":"equal","actual":"beep","expected":"boop","error":{},"test":0,"type":"assert"}
|
479 | {"type":"end","test":0}
|
480 | {"type":"test","name":"(anonymous)","id":1}
|
481 | {"id":0,"ok":true,"name":"should be strictly equal","operator":"equal","actual":2,"expected":2,"test":1,"type":"assert"}
|
482 | {"id":1,"ok":true,"name":"(unnamed assert)","operator":"ok","actual":true,"expected":true,"test":1,"type":"assert"}
|
483 | {"type":"end","test":1}
|
484 | {"type":"test","name":"wheee","id":2}
|
485 | {"id":0,"ok":true,"name":"(unnamed assert)","operator":"ok","actual":true,"expected":true,"test":2,"type":"assert"}
|
486 | {"type":"end","test":2}
|
487 | ```
|
488 |
|
489 | A convenient alternative to achieve the same:
|
490 | ```js
|
491 | // report.js
|
492 | var test = require('tape');
|
493 |
|
494 | test.createStream({ objectMode: true }).on('data', function (row) {
|
495 | console.log(JSON.stringify(row)) // for example
|
496 | });
|
497 | ```
|
498 | and then:
|
499 | ```sh
|
500 | $ tape -r ./report.js **/*.test.js
|
501 | ```
|
502 |
|
503 | # install
|
504 |
|
505 | With [npm](https://npmjs.org) do:
|
506 |
|
507 | ```sh
|
508 | npm install tape --save-dev
|
509 | ```
|
510 |
|
511 | # troubleshooting
|
512 |
|
513 | Sometimes `t.end()` doesn’t preserve the expected output ordering.
|
514 |
|
515 | For instance the following:
|
516 |
|
517 | ```js
|
518 | var test = require('tape');
|
519 |
|
520 | test('first', function (t) {
|
521 |
|
522 | setTimeout(function () {
|
523 | t.ok(1, 'first test');
|
524 | t.end();
|
525 | }, 200);
|
526 |
|
527 | t.test('second', function (t) {
|
528 | t.ok(1, 'second test');
|
529 | t.end();
|
530 | });
|
531 | });
|
532 |
|
533 | test('third', function (t) {
|
534 | setTimeout(function () {
|
535 | t.ok(1, 'third test');
|
536 | t.end();
|
537 | }, 100);
|
538 | });
|
539 | ```
|
540 |
|
541 | will output:
|
542 |
|
543 | ```
|
544 | ok 1 second test
|
545 | ok 2 third test
|
546 | ok 3 first test
|
547 | ```
|
548 |
|
549 | because `second` and `third` assume `first` has ended before it actually does.
|
550 |
|
551 | Use `t.plan()` instead to let other tests know they should wait:
|
552 |
|
553 | ```diff
|
554 | var test = require('tape');
|
555 |
|
556 | test('first', function (t) {
|
557 |
|
558 | + t.plan(2);
|
559 |
|
560 | setTimeout(function () {
|
561 | t.ok(1, 'first test');
|
562 | - t.end();
|
563 | }, 200);
|
564 |
|
565 | t.test('second', function (t) {
|
566 | t.ok(1, 'second test');
|
567 | t.end();
|
568 | });
|
569 | });
|
570 |
|
571 | test('third', function (t) {
|
572 | setTimeout(function () {
|
573 | t.ok(1, 'third test');
|
574 | t.end();
|
575 | }, 100);
|
576 | });
|
577 | ```
|
578 |
|
579 | # license
|
580 |
|
581 | MIT
|
582 |
|
583 | [package-url]: https://npmjs.org/package/tape
|
584 | [npm-version-svg]: https://versionbadg.es/ljharb/tape.svg
|
585 | [deps-svg]: https://david-dm.org/ljharb/tape.svg
|
586 | [deps-url]: https://david-dm.org/ljharb/tape
|
587 | [dev-deps-svg]: https://david-dm.org/ljharb/tape/dev-status.svg
|
588 | [dev-deps-url]: https://david-dm.org/ljharb/tape#info=devDependencies
|
589 | [npm-badge-png]: https://nodei.co/npm/tape.png?downloads=true&stars=true
|
590 | [license-image]: https://img.shields.io/npm/l/tape.svg
|
591 | [license-url]: LICENSE
|
592 | [downloads-image]: https://img.shields.io/npm/dm/tape.svg
|
593 | [downloads-url]: https://npm-stat.com/charts.html?package=tape
|
594 | [codecov-image]: https://codecov.io/gh/ljharb/tape/branch/master/graphs/badge.svg
|
595 | [codecov-url]: https://app.codecov.io/gh/ljharb/tape/
|
596 | [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/tape
|
597 | [actions-url]: https://github.com/ljharb/tape/actions
|