supertape 9.4.0 → 10.0.0

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,17 @@
1
+ 2024.01.26, v10.0.0
2
+
3
+ feature:
4
+ - 174a856 supertape: help
5
+ - 0e55c2f supertape: isStop
6
+ - 64c7acb supertape: add support of worker_threads
7
+ - 1e4429d supertape: putout v35.0.0
8
+
9
+ 2024.01.05, v9.5.0
10
+
11
+ feature:
12
+ - 3abf553 supertape: operator: improve fail message when operator returns function
13
+ - 74893c0 supertape: c8 v9.0.0
14
+
1
15
  2023.12.28, v9.4.0
2
16
 
3
17
  feature:
package/README.md CHANGED
@@ -56,6 +56,7 @@ Options
56
56
  --no-check-scopes do not check that messages contains scope: 'scope: message'
57
57
  --no-check-assertions-count do not check that assertion count is no more then 1
58
58
  --no-check-duplicates do not check messages for duplicates
59
+ --no-worker disable worker thread
59
60
  ```
60
61
 
61
62
  ## Environment variables
@@ -0,0 +1,45 @@
1
+ import {
2
+ parentPort,
3
+ workerData,
4
+ } from 'node:worker_threads';
5
+ import {EventEmitter} from 'node:events';
6
+
7
+ const {assign} = Object;
8
+
9
+ export const createCommunication = (argv) => {
10
+ if (parentPort)
11
+ return {
12
+ parentPort,
13
+ workerData,
14
+ };
15
+
16
+ const {newWorker, newParentPort} = fakeWorkers();
17
+
18
+ return {
19
+ worker: newWorker,
20
+ parentPort: newParentPort,
21
+ workerData: argv,
22
+ };
23
+ };
24
+
25
+ export function fakeWorkers() {
26
+ const newWorker = new EventEmitter();
27
+ const newParentPort = new EventEmitter();
28
+
29
+ assign(newWorker, {
30
+ postMessage: (a) => {
31
+ newParentPort.emit('message', a);
32
+ },
33
+ });
34
+
35
+ assign(newParentPort, {
36
+ postMessage: (a) => {
37
+ newWorker.emit('message', a);
38
+ },
39
+ });
40
+
41
+ return {
42
+ newParentPort,
43
+ newWorker,
44
+ };
45
+ }
@@ -0,0 +1,63 @@
1
+ import {EventEmitter} from 'node:events';
2
+
3
+ export const createFormatter = (parentPort) => {
4
+ const formatter = new EventEmitter();
5
+
6
+ formatter.on('start', ({total}) => {
7
+ parentPort.postMessage(['start', {
8
+ total,
9
+ }]);
10
+ });
11
+
12
+ formatter.on('test', ({test}) => {
13
+ parentPort.postMessage(['test', {
14
+ test,
15
+ }]);
16
+ });
17
+
18
+ formatter.on('test:end', ({count, total, failed, test}) => {
19
+ parentPort.postMessage(['test:end', {
20
+ total,
21
+ count,
22
+ failed,
23
+ test,
24
+ }]);
25
+ });
26
+
27
+ formatter.on('comment', (message) => {
28
+ parentPort.postMessage(['test:end', {
29
+ message,
30
+ }]);
31
+ });
32
+
33
+ formatter.on('test:success', ({count, message}) => {
34
+ parentPort.postMessage(['test:success', {
35
+ count,
36
+ message,
37
+ }]);
38
+ });
39
+
40
+ formatter.on('test:fail', ({at, count, message, operator, result, expected, output, errorStack}) => {
41
+ parentPort.postMessage(['fail', {
42
+ at,
43
+ count,
44
+ message,
45
+ operator,
46
+ result: JSON.stringify(result),
47
+ expected: JSON.stringify(expected),
48
+ output,
49
+ errorStack,
50
+ }]);
51
+ });
52
+
53
+ formatter.on('end', ({count, passed, failed, skiped}) => {
54
+ parentPort.postMessage(['end', {
55
+ count,
56
+ passed,
57
+ failed,
58
+ skiped,
59
+ }]);
60
+ });
61
+
62
+ return formatter;
63
+ };
@@ -0,0 +1,17 @@
1
+ import fullstore from 'fullstore';
2
+
3
+ const noop = () => {};
4
+
5
+ export const createIsStop = (parentPort) => {
6
+ if (!parentPort)
7
+ return noop;
8
+
9
+ const isStop = fullstore(false);
10
+
11
+ parentPort?.on('message', ([event]) => {
12
+ if (event === 'stop')
13
+ isStop(true);
14
+ });
15
+
16
+ return isStop;
17
+ };
@@ -0,0 +1,28 @@
1
+ import keyPress from '@putout/cli-keypress';
2
+ import harnessCreator from '../lib/formatter/harness.js';
3
+
4
+ const {createHarness} = harnessCreator;
5
+
6
+ const resolveFormatter = async (name) => await import(`@supertape/formatter-${name}`);
7
+
8
+ export async function subscribe({name, quiet, exit, worker, stdout}) {
9
+ const {isStop} = keyPress();
10
+ const harness = createHarness(await resolveFormatter(name));
11
+
12
+ if (!quiet)
13
+ harness.pipe(stdout);
14
+
15
+ worker.on('exit', (code) => {
16
+ exit(code);
17
+ });
18
+
19
+ worker.on('message', ([type, a]) => {
20
+ harness.write({
21
+ type,
22
+ ...a,
23
+ });
24
+
25
+ if (isStop())
26
+ worker.postMessage(['stop']);
27
+ });
28
+ }
package/bin/supertape.mjs CHANGED
@@ -1,18 +1,43 @@
1
- #!/usr/bin/env node
2
-
3
1
  import process from 'node:process';
2
+ import {createCommunication} from './communication.mjs';
3
+ import {subscribe} from './subscribe.mjs';
4
+ import {createIsStop} from './is-stop.mjs';
5
+ import {createFormatter} from './formatter.mjs';
6
+ import {parseArgs} from '../lib/cli/parse-args.js';
4
7
  import cli from '../lib/cli.js';
5
8
 
9
+ const {
10
+ worker,
11
+ parentPort,
12
+ workerData,
13
+ } = createCommunication(process.argv);
14
+
15
+ const args = parseArgs(process.argv.slice(2));
16
+
6
17
  const {
7
18
  stdout,
8
19
  stderr,
9
20
  exit,
10
21
  } = process;
11
22
 
12
- export default cli({
23
+ const workerFormatter = createFormatter(parentPort);
24
+ const isStop = createIsStop(parentPort);
25
+
26
+ if (worker)
27
+ subscribe({
28
+ name: args.format,
29
+ quiet: args.quiet,
30
+ exit,
31
+ worker,
32
+ stdout,
33
+ });
34
+
35
+ export default await cli({
13
36
  stdout,
14
37
  stderr,
15
38
  exit,
16
39
  cwd: process.cwd(),
17
- argv: process.argv.slice(2),
40
+ argv: workerData.slice(2),
41
+ workerFormatter,
42
+ isStop,
18
43
  });
package/bin/trace.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export const createTrace = (parentPort) => (event, data) => {
2
+ parentPort?.postMessage([event, data]);
3
+ };
package/bin/tracer.mjs ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ import process from 'node:process';
4
+ import {Worker} from 'node:worker_threads';
5
+ import {parseArgs} from '../lib/cli/parse-args.js';
6
+ import {subscribe} from './subscribe.mjs';
7
+
8
+ const {
9
+ cwd,
10
+ exit,
11
+ stdout,
12
+ } = process;
13
+
14
+ const args = parseArgs(process.argv.slice(2));
15
+ const write = stdout.write.bind(stdout);
16
+
17
+ if (!args.worker) {
18
+ await import('./supertape.mjs');
19
+ exit();
20
+ }
21
+
22
+ const slave = new URL('./supertape.mjs', import.meta.url);
23
+
24
+ const worker = new Worker(slave, {
25
+ workerData: process.argv,
26
+ stdin: true,
27
+ });
28
+
29
+ await subscribe({
30
+ name: args.format,
31
+ args,
32
+ worker,
33
+ exit,
34
+ cwd,
35
+ write,
36
+ stdout,
37
+ });
package/help.json CHANGED
@@ -5,5 +5,6 @@
5
5
  "-r, --require ": "require module",
6
6
  "--no-check-scopes ": "do not check that messages contains scope: 'scope: message'",
7
7
  "--no-check-assertions-count": "do not check that assertion count is no more then 1",
8
- "--no-check-duplicates ": "do not check messages for duplicates"
8
+ "--no-check-duplicates ": "do not check messages for duplicates",
9
+ "--no-worker ": "disable worker thread"
9
10
  }
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ const process = require('node:process');
4
+ const yargsParser = require('yargs-parser');
5
+ const {isArray} = Array;
6
+ const maybeFirst = (a) => isArray(a) ? a.pop() : a;
7
+ const maybeArray = (a) => isArray(a) ? a : [a];
8
+
9
+ const {
10
+ SUPERTAPE_CHECK_DUPLICATES = '1',
11
+ SUPERTAPE_CHECK_SCOPES = '1',
12
+ SUPERTAPE_CHECK_ASSERTIONS_COUNT = '1',
13
+ } = process.env;
14
+
15
+ const yargsOptions = {
16
+ configuration: {
17
+ 'strip-aliased': true,
18
+ 'strip-dashed': true,
19
+ },
20
+ coerce: {
21
+ require: maybeArray,
22
+ format: maybeFirst,
23
+ },
24
+ string: [
25
+ 'format',
26
+ 'require',
27
+ ],
28
+ boolean: [
29
+ 'version',
30
+ 'help',
31
+ 'check-duplicates',
32
+ 'check-scopes',
33
+ 'check-assertions-count',
34
+ 'worker',
35
+ ],
36
+ alias: {
37
+ version: 'v',
38
+ format: 'f',
39
+ help: 'h',
40
+ require: 'r',
41
+ checkDuplicates: 'd',
42
+ checkScopes: 's',
43
+ checkAssertionsCount: 'a',
44
+ },
45
+ default: {
46
+ format: 'progress-bar',
47
+ require: [],
48
+ checkDuplicates: SUPERTAPE_CHECK_DUPLICATES !== '0',
49
+ checkScopes: SUPERTAPE_CHECK_SCOPES !== '0',
50
+ checkAssertionsCount: SUPERTAPE_CHECK_ASSERTIONS_COUNT !== '0',
51
+ worker: true,
52
+ },
53
+ };
54
+
55
+ module.exports.yargsOptions = yargsOptions;
56
+ module.exports.parseArgs = (argv) => yargsParser(argv, yargsOptions);
package/lib/cli.js CHANGED
@@ -5,12 +5,13 @@ const {resolve: resolvePath} = require('path');
5
5
  const {once} = require('events');
6
6
  const {pathToFileURL} = require('url');
7
7
 
8
- const yargsParser = require('yargs-parser');
9
8
  const glob = require('glob');
10
9
  const fullstore = require('fullstore');
11
10
  const tryToCatch = require('try-to-catch');
12
11
  const keypress = require('@putout/cli-keypress');
12
+
13
13
  const {simpleImport} = require('./simple-import');
14
+ const {parseArgs, yargsOptions} = require('./cli/parse-args');
14
15
 
15
16
  const supertape = require('..');
16
17
  const {
@@ -22,30 +23,23 @@ const {
22
23
  SKIPED,
23
24
  } = require('./exit-codes');
24
25
 
25
- const {isArray} = Array;
26
-
27
- const maybeFirst = (a) => isArray(a) ? a.pop() : a;
28
- const maybeArray = (a) => isArray(a) ? a : [a];
29
26
  const isExclude = (a) => !a.includes('node_modules');
30
-
31
27
  const removeDuplicates = (a) => Array.from(new Set(a));
28
+
32
29
  const filesCount = fullstore(0);
33
30
 
34
- const {
35
- SUPERTAPE_CHECK_DUPLICATES = '1',
36
- SUPERTAPE_CHECK_SCOPES = '1',
37
- SUPERTAPE_CHECK_ASSERTIONS_COUNT = '1',
38
- SUPERTAPE_CHECK_SKIPED = '0',
39
- } = process.env;
31
+ const {SUPERTAPE_CHECK_SKIPED = '0'} = process.env;
40
32
 
41
- module.exports = async ({argv, cwd, stdout, stderr, exit}) => {
42
- const {isStop} = keypress();
33
+ module.exports = async ({argv, cwd, stdout, stderr, exit, isStop, workerFormatter}) => {
34
+ isStop = isStop || keypress().isStop;
35
+
43
36
  const [error, result] = await tryToCatch(cli, {
44
37
  argv,
45
38
  cwd,
46
39
  stdout,
47
40
  exit,
48
41
  isStop,
42
+ workerFormatter,
49
43
  });
50
44
 
51
45
  if (error) {
@@ -77,46 +71,8 @@ module.exports = async ({argv, cwd, stdout, stderr, exit}) => {
77
71
  return exit(OK);
78
72
  };
79
73
 
80
- const yargsOptions = {
81
- configuration: {
82
- 'strip-aliased': true,
83
- 'strip-dashed': true,
84
- },
85
- coerce: {
86
- require: maybeArray,
87
- format: maybeFirst,
88
- },
89
- string: [
90
- 'format',
91
- 'require',
92
- ],
93
- boolean: [
94
- 'version',
95
- 'help',
96
- 'check-duplicates',
97
- 'check-scopes',
98
- 'check-assertions-count',
99
- ],
100
- alias: {
101
- version: 'v',
102
- format: 'f',
103
- help: 'h',
104
- require: 'r',
105
- checkDuplicates: 'd',
106
- checkScopes: 's',
107
- checkAssertionsCount: 'a',
108
- },
109
- default: {
110
- format: 'progress-bar',
111
- require: [],
112
- checkDuplicates: SUPERTAPE_CHECK_DUPLICATES !== '0',
113
- checkScopes: SUPERTAPE_CHECK_SCOPES !== '0',
114
- checkAssertionsCount: SUPERTAPE_CHECK_ASSERTIONS_COUNT !== '0',
115
- },
116
- };
117
-
118
- async function cli({argv, cwd, stdout, isStop}) {
119
- const args = yargsParser(argv, yargsOptions);
74
+ async function cli({argv, cwd, stdout, isStop, workerFormatter}) {
75
+ const args = parseArgs(argv);
120
76
 
121
77
  if (args.version) {
122
78
  stdout.write(`v${require('../package').version}\n`);
@@ -171,6 +127,7 @@ async function cli({argv, cwd, stdout, isStop}) {
171
127
  checkDuplicates,
172
128
  checkScopes,
173
129
  checkAssertionsCount,
130
+ workerFormatter,
174
131
  });
175
132
 
176
133
  const stream = await supertape.createStream();
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const {parentPort, workerData} = require('node:worker_threads');
4
+
5
+ const {EventEmitter} = require('node:events');
6
+ const process = require('node:process');
7
+
8
+ const {assign} = Object;
9
+
10
+ module.exports.createCommunication = () => {
11
+ if (parentPort)
12
+ return {
13
+ parentPort,
14
+ workerData,
15
+ };
16
+
17
+ const newWorker = new EventEmitter();
18
+ const newParentPort = new EventEmitter();
19
+
20
+ assign(newWorker, {
21
+ postMessage: (a) => {
22
+ newParentPort.emit('message', a);
23
+ },
24
+ });
25
+
26
+ assign(newParentPort, {
27
+ postMessage: (a) => {
28
+ newWorker.emit('message', a);
29
+ },
30
+ });
31
+
32
+ return {
33
+ worker: newWorker,
34
+ parentPort: newParentPort,
35
+ workerData: process.argv,
36
+ };
37
+ };
@@ -69,5 +69,6 @@ function run(reporter, type, data) {
69
69
  if (type === 'fail')
70
70
  return reporter.fail(data);
71
71
 
72
- return reporter.end(data);
72
+ if (type === 'end')
73
+ return reporter.end(data);
73
74
  }
package/lib/operators.mjs CHANGED
@@ -240,12 +240,12 @@ function validateEnd({name, operators, runnerState}) {
240
240
 
241
241
  const validate = (a) => {
242
242
  if (isFn(a))
243
- return fail('looks like operator returns function, it will always fail');
243
+ return fail(`☝️ Looks like operator returns function, it will always fail: '${a}'`);
244
244
 
245
245
  return a;
246
246
  };
247
247
 
248
- const returnMissing = () => fail('looks like operator returns nothing, it will always fail');
248
+ const returnMissing = () => fail('☝️ Looks like operator returns nothing, it will always fail');
249
249
 
250
250
  function run(name, {formatter, count, incCount, incPassed, incFailed}, testState = returnMissing()) {
251
251
  const {
package/lib/run-tests.js CHANGED
@@ -16,7 +16,6 @@ const notSkip = ({skip}) => !skip;
16
16
  const getInitOperators = async () => await import('./operators.mjs');
17
17
 
18
18
  const {SUPERTAPE_TIMEOUT = 3000} = process.env;
19
-
20
19
  const DEBUG_TIME = 3000 * 1000;
21
20
 
22
21
  const timeout = (time, value) => {
package/lib/supertape.js CHANGED
@@ -45,7 +45,7 @@ const defaultOptions = {
45
45
  checkScopes: true,
46
46
  };
47
47
 
48
- function _createEmitter({quiet, stream = stdout, format, getOperators, isStop, readyFormatter}) {
48
+ function _createEmitter({quiet, stream = stdout, format, getOperators, isStop, readyFormatter, workerFormatter}) {
49
49
  const tests = [];
50
50
  const emitter = new EventEmitter();
51
51
 
@@ -77,7 +77,7 @@ function _createEmitter({quiet, stream = stdout, format, getOperators, isStop, r
77
77
  const operators = await getOperators();
78
78
 
79
79
  const result = await runTests(tests, {
80
- formatter,
80
+ formatter: workerFormatter || formatter,
81
81
  operators,
82
82
  isStop,
83
83
  });
@@ -152,6 +152,7 @@ function test(message, fn, options = {}) {
152
152
  checkScopes,
153
153
  checkAssertionsCount,
154
154
  checkIfEnded,
155
+ workerFormatter,
155
156
  } = {
156
157
  ...defaultOptions,
157
158
  ...initedOptions,
@@ -168,12 +169,12 @@ function test(message, fn, options = {}) {
168
169
  setValidations(validations);
169
170
 
170
171
  const at = getAt();
171
-
172
172
  const emitter = options.emitter || createEmitter({
173
173
  format,
174
174
  quiet,
175
175
  getOperators,
176
176
  isStop,
177
+ workerFormatter,
177
178
  });
178
179
 
179
180
  mainEmitter = emitter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supertape",
3
- "version": "9.4.0",
3
+ "version": "10.0.0",
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",
@@ -19,8 +19,8 @@
19
19
  },
20
20
  "type": "commonjs",
21
21
  "bin": {
22
- "tape": "bin/supertape.mjs",
23
- "supertape": "bin/supertape.mjs"
22
+ "tape": "bin/tracer.mjs",
23
+ "supertape": "bin/tracer.mjs"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -74,9 +74,9 @@
74
74
  "testing"
75
75
  ],
76
76
  "devDependencies": {
77
- "@babel/core": "^7.12.9",
77
+ "@babel/core": "^8.0.0-alpha.5",
78
78
  "@iocmd/wait": "^2.1.0",
79
- "c8": "^8.0.0",
79
+ "c8": "^9.0.0",
80
80
  "check-dts": "^0.7.0",
81
81
  "currify": "^4.0.0",
82
82
  "eslint": "^8.0.0",
@@ -88,7 +88,7 @@
88
88
  "montag": "^1.0.0",
89
89
  "nodemon": "^3.0.1",
90
90
  "pullout": "^4.0.0",
91
- "putout": "^34.0.0",
91
+ "putout": "^35.0.0",
92
92
  "runsome": "^1.0.0",
93
93
  "try-catch": "^3.0.0",
94
94
  "typescript": "^5.1.6"