supertape 7.7.0 → 8.0.1

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/ChangeLog CHANGED
@@ -1,3 +1,40 @@
1
+ 2022.09.07, v8.0.1
2
+
3
+ feature:
4
+ - package: @supertape/operator-stub v3.0.0
5
+ - @supertape/operator-stub: type: Result -> OperationResult
6
+ - (package) supertape v8.0.0
7
+
8
+ 2022.09.07, v8.0.0
9
+
10
+ fix:
11
+ - @supertape/formatter-short: drop support of node < 16
12
+ - @supertape/formatter-tap: drop support of node < 16
13
+ - @supertape/formatter-tap: get back commonjs, since @supertape/formatter-fail is commonjs
14
+
15
+ feature:
16
+ - package: @supertape/formatter-progress-bar v3.0.0
17
+ - formatters: convert to ESM
18
+ - supertape: add ability to use 'createFormatter()' to create formatters
19
+ - @putout/formatter-progress-bar: convert to ESM
20
+ - package: @supertape/formatter-fail v3.0.0
21
+ - @supertape/formatter-json-lines: drop support of node < 16
22
+ - @supertape/formatter-fail: drop support of node < 16
23
+ - package: @supertape/formatter-tap v3.0.1
24
+ - package: @supertape/formatter-json-lines v2.0.0
25
+ - package: @supertape/formatter-short v2.0.0
26
+ - package: @supertape/formatter-tap v3.0.0
27
+ - @supertape/formatter-short: convert to ESM
28
+ - @supertape/formatter-tap: convert to ESM
29
+ - @supertape/formatter-json-lines: convert to ESM
30
+ - supertape: add support of ESM formatters
31
+ - supertape: actual -> result
32
+
33
+ 2022.08.29, v7.7.1
34
+
35
+ feature:
36
+ - package: jest-diff v29.0.1
37
+
1
38
  2022.08.28, v7.7.0
2
39
 
3
40
  feature:
package/README.md CHANGED
@@ -1,37 +1,43 @@
1
- # 📼 Supertape [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL]
1
+ # 📼 Supertape [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL] [![License: MIT][MITLicenseIMGURL]][MITLicenseURL]
2
2
 
3
3
  [NPMURL]: https://npmjs.org/package/supertape "npm"
4
4
  [NPMIMGURL]: https://img.shields.io/npm/v/supertape.svg?style=flat&longCache=true
5
- [BuildStatusURL]: https://github.com/coderaiser/putout/actions?query=workflow%3A%22Node+CI%22 "Build Status"
6
- [BuildStatusIMGURL]: https://github.com/coderaiser/putout/workflows/Node%20CI/badge.svg
5
+ [BuildStatusURL]: https://github.com/coderaiser/supertape/actions?query=workflow%3A%22Node+CI%22 "Build Status"
6
+ [BuildStatusIMGURL]: https://github.com/coderaiser/supertape/workflows/Node%20CI/badge.svg
7
7
  [BuildStatusURL]: https://travis-ci.org/coderaiser/supertape "Build Status"
8
8
  [CoverageURL]: https://coveralls.io/github/coderaiser/supertape?branch=master
9
9
  [CoverageIMGURL]: https://coveralls.io/repos/coderaiser/supertape/badge.svg?branch=master&service=github
10
+ [MITLicenseURL]: https://opensource.org/licenses/MIT
11
+ [MITLicenseIMGURL]: https://img.shields.io/badge/License-MIT-green.svg
10
12
 
11
13
  [![supertape](https://asciinema.org/a/Cgc3rDOfZAeDnJSxzEYpPfBMY.svg)](https://asciinema.org/a/Cgc3rDOfZAeDnJSxzEYpPfBMY)
12
14
 
13
- [Tape](https://github.com/substack/tape)-inspired [TAP](https://testanything.org/)-compatible simplest high speed test runner with superpowers.
15
+ [**Tape**](https://github.com/substack/tape)-inspired [`TAP`](https://testanything.org/)-compatible simplest high speed test runner with superpowers.
14
16
 
15
- 📼`Supertape` written from scratch after messing a lot with `tape`, it willing to be compatible with it as much as possible.
16
- and has a couple differences. It contains:
17
+ 📼 **Supertape** is a fast, minimal test runner with the soul of **tape**. It's designed to be as compatible as possible with **tape** while still having some key improvements, such as:
17
18
 
18
- - ability to work with [esm modules](https://nodejs.org/api/esm.html) (take a look at [mock-import](https://github.com/coderaiser/mock-import) for mocking).
19
- - shows colored diff when test not `equal` or not `deepEqual`;
20
- - produces deteiled stack traces for `async functions`;
21
- - as many `only` as you wish;
22
- - ability to extend;
23
- - smart timeouts for long running tests 🏃‍♂️(configured with `SUPERTAPE_TIMEOUT`);
24
- - more natural assertions: `expected, result` -> `result, expected`, for example:
19
+ - the ability to work with [ESM Modules](https://nodejs.org/api/esm.html) (take a look at [mock-import](https://github.com/coderaiser/mock-import) for mocking and 🎩[ESCover](https://github.com/coderaiser/escover) for coverage)
20
+ - a number of [built-in pretty output formatters](#formatting)
21
+ - easy [configuration](#list-of-options)
22
+ - the ability to [extend](#extending)
23
+ - showing colored diff when using the [`t.equal()`](#tequalresult-any-expected-any-message-string) and [`t.deepEqual()`](#tdeepequalresult-any-expected-any-message-string) assertion operators
24
+ - detailed stack traces for `async` functions
25
+ - multiple [`test.only`'s](#testonlymessage-string-fn-t-test--void-options-testoptions)
26
+ - [smart timeouts](#supertape_timeout) for long running tests 🏃‍♂️
27
+ - more natural assertions: `expected, result` -> `result, expected`:
25
28
 
26
- ```js
27
- t.equal(error.message, 'hello world', `expected error.message to be 'hello world'`);
28
- ```
29
+ ```js
30
+ t.equal(error.message, 'hello world', `expected error.message to be 'hello world'`);
31
+ ```
32
+
33
+ 📼 **Supertape** doesn't contain:
29
34
 
30
- Doesn't contain:
35
+ - assertion aliases, making the available operators far more concise
36
+ - `es3 code` and lot's of [ponyfills](https://github.com/sindresorhus/ponyfill#how-are-ponyfills-better-than-polyfills)
37
+ - `t.throws()`, `t.doesNotThrow()` - use [**tryCatch**](https://github.com/coderaiser/try-catch) or [**tryToCatch**](https://github.com/coderaiser/try-to-catch) with [`t.equal()`](#tequalresult-any-expected-any-message-string) instead
38
+ - [`t.plan()`](https://github.com/substack/tape#tplann)
31
39
 
32
- - `es3 code` and lot's of [ponyfills](https://github.com/sindresorhus/ponyfill#how-are-ponyfills-better-than-polyfills).
33
- - aliases, methods list much shorter;
34
- - `throws`, `doesNotThrows` - use [tryCatch](https://github.com/coderaiser/try-catch), [tryToCatch](https://github.com/coderaiser/try-to-catch) with `equal` instead.
40
+ For a list of all built-in assertions, see [Operators](#operators).
35
41
 
36
42
  ## Install
37
43
 
@@ -84,7 +90,73 @@ Here is [result example](https://github.com/coderaiser/cloudcmd/commit/74d56f795
84
90
 
85
91
  ## Operators
86
92
 
87
- To simplify `supertape` core operators located in separate packages, called `operators`:
93
+ The assertion methods of 📼 **Supertape** are heavily influenced by [**tape**](https://github.com/substack/tape). However, to keep a minimal core of assertions, there are no aliases and some superfluous operators have been removed (such as `t.throws()`).
94
+
95
+ The following is a list of the base methods maintained by 📼 **Supertape**. Others, such as assertions for stubbing, are maintained in [separate packages](#other-built-in-operators). To add custom assertion operators, see [Extending](#extending).
96
+
97
+ ### Core Operators
98
+
99
+ #### `t.equal(result: any, expected: any, message?: string)`
100
+
101
+ Asserts that `result` and `expected` are strictly equal. If `message` is provided, it will be outputted as a description of the assertion.
102
+
103
+ *Note: uses `Object.is(result, expected)`*
104
+
105
+ #### `t.notEqual(result: any, expected: any, message?: string)`
106
+
107
+ Asserts that `result` and `expected` are not strictly equal. If `message` is provided, it will be outputted as a description of the assertion.
108
+
109
+ *Note: uses `!Object.is(result, expected)`*
110
+
111
+ #### `t.deepEqual(result: any, expected: any, message?: string)`
112
+
113
+ Asserts that `result` and `expected` are loosely equal, with the same structure and nested values. If `message` is provided, it will be outputted as a description of the assertion.
114
+
115
+ *Note: uses [node's deepEqual() algorithm][NodeDeepEqual] with strict comparisons (`===`) on leaf nodes*
116
+
117
+ #### `t.notDeepEqual(result: any, expected: any, message?: string)`
118
+
119
+ Asserts that `result` and `expected` not loosely equal, with different structure and/or nested values. If `message` is provided, it will be outputted as a description of the assertion.
120
+
121
+ *Note: uses [node's deepEqual() algorithm][NodeDeepEqual] with strict comparisons (`===`) on leaf nodes*
122
+
123
+ [NodeDeepEqual]: https://github.com/substack/node-deep-equal
124
+
125
+ #### `t.ok(result: boolean | any, message?: string)`
126
+
127
+ Asserts that `result` is truthy. If `message` is provided, it will be outputted as a description of the assertion.
128
+
129
+ #### `t.notOk(result: boolean | any, message?: string)`
130
+
131
+ Asserts that `result` is falsy. If `message` is provided, it will be outputted as a description of the assertion.
132
+
133
+ #### `t.pass(message: string)`
134
+
135
+ Generates a passing assertion with `message` as a description.
136
+
137
+ #### `t.fail(message: string)`
138
+
139
+ Generates a failing assertion with `message` as a description.
140
+
141
+ #### `t.end()`
142
+
143
+ Declares the end of a test explicitly. Must be called exactly once per test. (See: [Single Call to `t.end()`](#single-call-to-tend))
144
+
145
+ #### `t.match(result: string, pattern: string | RegExp, message?: string)`
146
+
147
+ Asserts that `result` matches the regex `pattern`. If `pattern` is not a valid regex, the assertion fails. If `message` is provided, it will be outputted as a description of the assertion.
148
+
149
+ #### `t.notMatch(result: string, pattern: string | RegExp, message?: string)`
150
+
151
+ Asserts that `result` does not match the regex `pattern`. If `pattern` is not a valid regex, the assertion always fails. If `message` is provided, it will be outputted as a description of the assertion.
152
+
153
+ #### `t.comment(message: string)`
154
+
155
+ Print a message without breaking the `TAP` output. Useful when using a `tap`-reporter such as `tap-colorize`, where the output is buffered and `console.log()` will print in incorrect order vis-a-vis `TAP` output.
156
+
157
+ ### Special Operators
158
+
159
+ To simplify the core of 📼 **Supertape**, other operators are maintained in separate packages. The following is a list of all such packages:
88
160
 
89
161
  Here is a list of built-int operators:
90
162
 
@@ -196,31 +268,31 @@ Assert that `value` is truthy with an optional description of the assertion `msg
196
268
 
197
269
  Assert that `value` is falsy with an optional description of the assertion `msg`.
198
270
 
199
- ## t.match(actual, pattern[, msg])
271
+ ## t.match(result, pattern[, msg])
200
272
 
201
- Assert that `pattern: string | regexp` matches `actual` with an optional description of the assertion `msg`.
273
+ Assert that `pattern: string | regexp` matches `result` with an optional description of the assertion `msg`.
202
274
 
203
- ## t.notMatch(actual, pattern[, msg])
275
+ ## t.notMatch(result, pattern[, msg])
204
276
 
205
- Assert that `pattern: string | regexp` not matches `actual` with an optional description of the assertion `msg`.
277
+ Assert that `pattern: string | regexp` not matches `result` with an optional description of the assertion `msg`.
206
278
 
207
- ## t.equal(actual, expected, msg)
279
+ ## t.equal(result, expected, msg)
208
280
 
209
- Assert that `Object.is(actual, expected)` with an optional description of the assertion `msg`.
281
+ Assert that `Object.is(result, expected)` with an optional description of the assertion `msg`.
210
282
 
211
- ## t.notEqual(actual, expected, msg)
283
+ ## t.notEqual(result, expected, msg)
212
284
 
213
- Assert that `!Object.is(actual, expected)` with an optional description of the assertion `msg`.
285
+ Assert that `!Object.is(result, expected)` with an optional description of the assertion `msg`.
214
286
 
215
- ## t.deepEqual(actual, expected, msg)
287
+ ## t.deepEqual(result, expected, msg)
216
288
 
217
- Assert that `actual` and `expected` have the same structure and nested values using
289
+ Assert that `result` and `expected` have the same structure and nested values using
218
290
  [node's deepEqual() algorithm](https://github.com/substack/node-deep-equal)
219
291
  with strict comparisons (`===`) on leaf nodes and an optional description of the assertion `msg`.
220
292
 
221
- ## t.notDeepEqual(actual, expected, msg)
293
+ ## t.notDeepEqual(result, expected, msg)
222
294
 
223
- Assert that `actual` and `expected` do not have the same structure and nested values using
295
+ Assert that `result` and `expected` do not have the same structure and nested values using
224
296
  [node's deepEqual() algorithm](https://github.com/substack/node-deep-equal)
225
297
  with strict comparisons (`===`) on leaf nodes and an optional description of the assertion `msg`.
226
298
 
package/lib/cli.js CHANGED
@@ -169,7 +169,9 @@ async function cli({argv, cwd, stdout, isStop}) {
169
169
  checkAssertionsCount,
170
170
  });
171
171
 
172
- supertape.createStream().pipe(stdout);
172
+ const stream = await supertape.createStream();
173
+
174
+ stream.pipe(stdout);
173
175
 
174
176
  const promises = [];
175
177
  const files = removeDuplicates(allFiles);
@@ -40,7 +40,7 @@ function prepare(reporter) {
40
40
  success: stub,
41
41
  comment: stub,
42
42
  end: stub,
43
- ...reporter,
43
+ ...reporter.createFormatter?.() || reporter,
44
44
  });
45
45
 
46
46
  return result;
@@ -3,11 +3,12 @@
3
3
  const {EventEmitter} = require('events');
4
4
  const {createHarness} = require('./harness');
5
5
 
6
- const resolveFormatter = (name) => require(`@supertape/formatter-${name}`);
6
+ const resolveFormatter = async (name) => await import(`@supertape/formatter-${name}`);
7
+ const isString = (a) => typeof a === 'string';
7
8
 
8
- module.exports.createFormatter = (name) => {
9
+ module.exports.createFormatter = async (name) => {
9
10
  const formatter = new EventEmitter();
10
- const harness = createHarness(resolveFormatter(name));
11
+ const harness = createHarness(!isString(name) ? name : await resolveFormatter(name));
11
12
 
12
13
  formatter.on('start', ({total}) => {
13
14
  harness.write({
@@ -48,14 +49,14 @@ module.exports.createFormatter = (name) => {
48
49
  });
49
50
  });
50
51
 
51
- formatter.on('test:fail', ({at, count, message, operator, actual, expected, output, errorStack}) => {
52
+ formatter.on('test:fail', ({at, count, message, operator, result, expected, output, errorStack}) => {
52
53
  harness.write({
53
54
  type: 'fail',
54
55
  at,
55
56
  count,
56
57
  message,
57
58
  operator,
58
- actual,
59
+ result,
59
60
  expected,
60
61
  output,
61
62
  errorStack,
package/lib/operators.mjs CHANGED
@@ -16,17 +16,17 @@ const isObj = (a) => typeof a === 'object';
16
16
 
17
17
  const end = () => {};
18
18
 
19
- const ok = (actual, message = 'should be truthy') => ({
20
- is: Boolean(actual),
19
+ const ok = (result, message = 'should be truthy') => ({
20
+ is: Boolean(result),
21
21
  expected: true,
22
- actual,
22
+ result,
23
23
  message,
24
24
  });
25
25
 
26
- const notOk = (actual, message = 'should be falsy') => ({
27
- is: !actual,
26
+ const notOk = (result, message = 'should be falsy') => ({
27
+ is: !result,
28
28
  expected: false,
29
- actual: actual && stringify(actual),
29
+ result: result && stringify(result),
30
30
  message,
31
31
  });
32
32
 
@@ -42,56 +42,56 @@ const validateRegExp = (regexp) => {
42
42
 
43
43
  const {stringify} = JSON;
44
44
 
45
- function match(actual, regexp, message = 'should match') {
45
+ function match(result, regexp, message = 'should match') {
46
46
  const error = validateRegExp(regexp);
47
47
 
48
48
  if (error)
49
49
  return fail(error);
50
50
 
51
- const is = maybeRegExp(regexp).test(actual);
51
+ const is = maybeRegExp(regexp).test(result);
52
52
 
53
53
  return {
54
54
  is,
55
- actual,
55
+ result,
56
56
  expected: regexp,
57
57
  message,
58
58
  };
59
59
  }
60
60
 
61
- function notMatch(actual, regexp, message = 'should not match') {
62
- const {is} = match(actual, regexp, message);
61
+ function notMatch(result, regexp, message = 'should not match') {
62
+ const {is} = match(result, regexp, message);
63
63
 
64
64
  return {
65
65
  is: !is,
66
- actual,
66
+ result,
67
67
  expected: regexp,
68
68
  message,
69
69
  };
70
70
  }
71
71
 
72
- function equal(actual, expected, message = 'should equal') {
72
+ function equal(result, expected, message = 'should equal') {
73
73
  let output = '';
74
- const is = Object.is(actual, expected);
74
+ const is = Object.is(result, expected);
75
75
 
76
76
  if (!is)
77
- output = diff(expected, actual) || ' result: values not equal, but deepEqual';
77
+ output = diff(expected, result) || ' result: values not equal, but deepEqual';
78
78
 
79
79
  return {
80
80
  is,
81
- actual,
81
+ result,
82
82
  expected,
83
83
  message,
84
84
  output,
85
85
  };
86
86
  }
87
87
 
88
- function notEqual(actual, expected, message = 'should not equal') {
89
- const is = !Object.is(actual, expected);
90
- const output = is ? '' : diff(expected, actual);
88
+ function notEqual(result, expected, message = 'should not equal') {
89
+ const is = !Object.is(result, expected);
90
+ const output = is ? '' : diff(expected, result);
91
91
 
92
92
  return {
93
93
  is,
94
- actual,
94
+ result,
95
95
  expected,
96
96
  message,
97
97
  output,
@@ -112,26 +112,26 @@ const fail = (error, at) => ({
112
112
  at,
113
113
  });
114
114
 
115
- const deepEqual = (actual, expected, message = 'should deep equal') => {
116
- const is = deepEqualCheck(actual, expected);
117
- const output = is ? '' : diff(expected, actual);
115
+ const deepEqual = (result, expected, message = 'should deep equal') => {
116
+ const is = deepEqualCheck(result, expected);
117
+ const output = is ? '' : diff(expected, result);
118
118
 
119
119
  return {
120
120
  is: is || !output,
121
- actual,
121
+ result,
122
122
  expected,
123
123
  message,
124
124
  output,
125
125
  };
126
126
  };
127
127
 
128
- const notDeepEqual = (actual, expected, message = 'should not deep equal') => {
129
- const is = !deepEqualCheck(actual, expected);
130
- const output = is ? '' : diff(expected, actual);
128
+ const notDeepEqual = (result, expected, message = 'should not deep equal') => {
129
+ const is = !deepEqualCheck(result, expected);
130
+ const output = is ? '' : diff(expected, result);
131
131
 
132
132
  return {
133
133
  is,
134
- actual,
134
+ result,
135
135
  expected,
136
136
  message,
137
137
  output,
@@ -245,7 +245,7 @@ function run(name, {formatter, count, incCount, incPassed, incFailed}, testState
245
245
  is,
246
246
  message,
247
247
  expected,
248
- actual,
248
+ result,
249
249
  output,
250
250
  stack,
251
251
  at,
@@ -272,7 +272,7 @@ function run(name, {formatter, count, incCount, incPassed, incFailed}, testState
272
272
  count: count(),
273
273
  message,
274
274
  operator: name,
275
- actual,
275
+ result,
276
276
  expected,
277
277
  output,
278
278
  errorStack: formatOutput(errorStack),
@@ -5,30 +5,30 @@ import {
5
5
  Stub,
6
6
  } from '@cloudcmd/stub';
7
7
 
8
- type Result = {
8
+ type OperationResult = {
9
9
  is: boolean,
10
10
  expected: unknown,
11
- actual: unknown,
11
+ result: unknown,
12
12
  message: string,
13
13
  output: string,
14
14
  };
15
15
 
16
16
  type Operator = {
17
- [index: string]: (...args: any[]) => Result
17
+ [index: string]: (...args: any[]) => OperationResult;
18
18
  };
19
19
 
20
20
  type Test = Operator & OperatorStub & {
21
- equal: (result: unknown, expected: unknown, message?: string) => Result;
22
- notEqual: (result: unknown, expected: unknown, message?: string) => Result;
23
- deepEqual: (result: unknown, expected: unknown, message?: string) => Result;
24
- notDeepEqual: (result: unknown, expected: unknown, message?: string) => Result;
25
- fail: (message: string) => Result;
26
- pass: (message: string) => Result;
27
- ok: (result: boolean | unknown, message?: string) => Result;
28
- comment: (message: string) => Result;
29
- notOk: (result: boolean | unknown, message?: string) => Result;
30
- match: (result: string, pattern: string | RegExp, message?: string) => Result;
31
- notMatch: (result: string, pattern: string | RegExp, message?: string) => Result;
21
+ equal: (result: unknown, expected: unknown, message?: string) => OperationResult;
22
+ notEqual: (result: unknown, expected: unknown, message?: string) => OperationResult;
23
+ deepEqual: (result: unknown, expected: unknown, message?: string) => OperationResult;
24
+ notDeepEqual: (result: unknown, expected: unknown, message?: string) => OperationResult;
25
+ fail: (message: string) => OperationResult;
26
+ pass: (message: string) => OperationResult;
27
+ ok: (result: boolean | unknown, message?: string) => OperationResult;
28
+ comment: (message: string) => OperationResult;
29
+ notOk: (result: boolean | unknown, message?: string) => OperationResult;
30
+ match: (result: string, pattern: string | RegExp, message?: string) => OperationResult;
31
+ notMatch: (result: string, pattern: string | RegExp, message?: string) => OperationResult;
32
32
  end: () => void;
33
33
  };
34
34
 
@@ -47,7 +47,7 @@ declare namespace test {
47
47
  export default test;
48
48
 
49
49
  type CustomOperator = {
50
- [index: string]: (operator: Operator) => (...args: any[]) => Result
50
+ [index: string]: (operator: Operator) => (...args: any[]) => OperationResult
51
51
  };
52
52
 
53
53
  declare function extend(customOperator: CustomOperator): typeof test;
package/lib/supertape.js CHANGED
@@ -1,13 +1,16 @@
1
1
  'use strict';
2
2
 
3
3
  const {EventEmitter} = require('events');
4
+ const {PassThrough} = require('stream');
5
+
4
6
  const once = require('once');
5
7
 
6
8
  const options = require('../supertape.json');
7
9
 
8
10
  const {getAt, setValidations} = require('./validator');
9
11
  const runTests = require('./run-tests');
10
- const createFormatter = once(require('./formatter').createFormatter);
12
+ const _createFormatter = require('./formatter').createFormatter;
13
+ const createFormatter = once(_createFormatter);
11
14
 
12
15
  const createEmitter = once(_createEmitter);
13
16
 
@@ -38,7 +41,7 @@ const defaultOptions = {
38
41
  checkScopes: true,
39
42
  };
40
43
 
41
- function _createEmitter({quiet, format, getOperators, isStop}) {
44
+ function _createEmitter({quiet, stream = stdout, format, getOperators, isStop, readyFormatter}) {
42
45
  const tests = [];
43
46
  const emitter = new EventEmitter();
44
47
 
@@ -62,10 +65,10 @@ function _createEmitter({quiet, format, getOperators, isStop}) {
62
65
  });
63
66
 
64
67
  emitter.on('run', async () => {
65
- const {harness, formatter} = createFormatter(format);
68
+ const {harness, formatter} = readyFormatter || await createFormatter(format);
66
69
 
67
70
  if (!quiet)
68
- harness.pipe(stdout);
71
+ harness.pipe(stream);
69
72
 
70
73
  const operators = await getOperators();
71
74
  const result = await runTests(tests, {
@@ -90,14 +93,45 @@ module.exports.init = (options) => {
90
93
  assign(initedOptions, options);
91
94
  };
92
95
 
93
- const createStream = () => {
96
+ const createStream = async () => {
94
97
  const {format} = initedOptions;
95
- const {harness} = createFormatter(format);
98
+ const {harness} = await createFormatter(format);
96
99
 
97
100
  return harness;
98
101
  };
99
102
 
100
103
  module.exports.createStream = createStream;
104
+ module.exports.createTest = async (testOptions = {}) => {
105
+ const {format = 'tap', formatter} = testOptions;
106
+ const readyFormatter = await _createFormatter(formatter || format);
107
+
108
+ const stream = new PassThrough();
109
+ const emitter = _createEmitter({
110
+ ...defaultOptions,
111
+ ...testOptions,
112
+ readyFormatter,
113
+ stream,
114
+ });
115
+
116
+ const fn = (message, fn, options = {}) => {
117
+ return test(message, fn, {
118
+ ...testOptions,
119
+ ...options,
120
+ emitter,
121
+ });
122
+ };
123
+
124
+ assign(fn, {
125
+ stream,
126
+ ...test,
127
+ test: fn,
128
+ run: () => {
129
+ emitter.emit('run');
130
+ },
131
+ });
132
+
133
+ return fn;
134
+ };
101
135
 
102
136
  function test(message, fn, options = {}) {
103
137
  const {
@@ -130,7 +164,7 @@ function test(message, fn, options = {}) {
130
164
 
131
165
  const at = getAt();
132
166
 
133
- const emitter = createEmitter({
167
+ const emitter = options.emitter || createEmitter({
134
168
  format,
135
169
  quiet,
136
170
  getOperators,
package/lib/supertape.mjs CHANGED
@@ -1,6 +1,13 @@
1
1
  import test from './supertape.js';
2
2
 
3
- const {extend, stub} = test;
3
+ const {
4
+ extend,
5
+ stub,
6
+ createStream,
7
+ init,
8
+ run,
9
+ createTest,
10
+ } = test;
4
11
 
5
12
  export default test;
6
13
 
@@ -8,4 +15,8 @@ export {
8
15
  extend,
9
16
  test,
10
17
  stub,
18
+ createStream,
19
+ init,
20
+ run,
21
+ createTest,
11
22
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supertape",
3
- "version": "7.7.0",
3
+ "version": "8.0.1",
4
4
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
5
5
  "description": "📼 Supertape simplest high speed test runner with superpowers",
6
6
  "homepage": "http://github.com/coderaiser/supertape",
@@ -44,17 +44,17 @@
44
44
  "@putout/cli-keypress": "^1.0.0",
45
45
  "@putout/cli-validate-args": "^1.0.1",
46
46
  "@supertape/engine-loader": "^1.0.0",
47
- "@supertape/formatter-fail": "^2.0.0",
48
- "@supertape/formatter-json-lines": "^1.0.0",
49
- "@supertape/formatter-progress-bar": "^2.0.0",
50
- "@supertape/formatter-short": "^1.0.0",
51
- "@supertape/formatter-tap": "^2.0.0",
52
- "@supertape/operator-stub": "^2.0.0",
47
+ "@supertape/formatter-fail": "^3.0.0",
48
+ "@supertape/formatter-json-lines": "^2.0.0",
49
+ "@supertape/formatter-progress-bar": "^3.0.0",
50
+ "@supertape/formatter-short": "^2.0.0",
51
+ "@supertape/formatter-tap": "^3.0.0",
52
+ "@supertape/operator-stub": "^3.0.0",
53
53
  "cli-progress": "^3.8.2",
54
54
  "deep-equal": "^2.0.3",
55
55
  "fullstore": "^3.0.0",
56
56
  "glob": "^8.0.3",
57
- "jest-diff": "^28.1.1",
57
+ "jest-diff": "^29.0.1",
58
58
  "once": "^1.4.0",
59
59
  "resolve": "^1.17.0",
60
60
  "stacktracey": "^2.1.7",
@@ -79,7 +79,7 @@
79
79
  "c8": "^7.3.5",
80
80
  "check-dts": "^0.6.5",
81
81
  "eslint": "^8.0.0",
82
- "eslint-plugin-node": "^11.1.0",
82
+ "eslint-plugin-n": "^15.2.5",
83
83
  "eslint-plugin-putout": "^16.0.1",
84
84
  "find-up": "^6.3.0",
85
85
  "madrun": "^9.0.0",