tape-six 1.2.0 → 1.3.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/README.md +1 -0
- package/bin/tape6-bun.js +2 -1
- package/bin/tape6-deno.js +2 -1
- package/bin/tape6-node.js +2 -1
- package/index.js +2 -1
- package/package.json +3 -3
- package/src/JSONLReporter.js +6 -8
- package/src/TTYReporter.js +61 -23
- package/src/TapReporter.js +22 -2
- package/src/bun/TestWorker.js +2 -2
- package/src/bun/worker.js +24 -1
- package/src/deno/TestWorker.js +2 -2
- package/src/deno/worker.js +24 -1
- package/src/node/TestWorker.js +2 -2
- package/src/node/worker.js +23 -1
- package/src/utils/EventServer.js +13 -1
package/README.md
CHANGED
|
@@ -236,6 +236,7 @@ See [set-up tests](https://github.com/uhop/tape-six/wiki/Set-up-tests) for detai
|
|
|
236
236
|
|
|
237
237
|
The most recent releases:
|
|
238
238
|
|
|
239
|
+
- 1.3.0 _Bugfixes, updated dependencies, new feature: proxied console calls._
|
|
239
240
|
- 1.2.0 _Updated dependencies + added an optional prefix for JSON lines._
|
|
240
241
|
- 1.1.2 _Updated dependencies._
|
|
241
242
|
- 1.1.1 _Technical re-release with the missing `index.d.ts` file._
|
package/bin/tape6-bun.js
CHANGED
package/bin/tape6-deno.js
CHANGED
package/bin/tape6-node.js
CHANGED
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tape-six",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "TAP the test harness for the modern JavaScript (ES6).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@types/node": "^25.0.
|
|
75
|
-
"puppeteer": "^24.
|
|
74
|
+
"@types/node": "^25.0.8",
|
|
75
|
+
"puppeteer": "^24.35.0",
|
|
76
76
|
"typescript": "^5.9.3"
|
|
77
77
|
}
|
|
78
78
|
}
|
package/src/JSONLReporter.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import {getEnv} from './utils/config.js';
|
|
2
2
|
|
|
3
|
-
class JSONLReporter {
|
|
4
|
-
constructor({renumberAsserts = false} = {}) {
|
|
3
|
+
export class JSONLReporter {
|
|
4
|
+
constructor({renumberAsserts = false, prefix} = {}) {
|
|
5
5
|
this.renumberAsserts = renumberAsserts;
|
|
6
6
|
this.assertCounter = 0;
|
|
7
7
|
|
|
8
8
|
const env = getEnv({});
|
|
9
|
-
|
|
9
|
+
prefix ||= env.TAPE6_JSONL_PREFIX;
|
|
10
|
+
this.prefix = prefix ? '\n' + prefix : '';
|
|
10
11
|
}
|
|
11
12
|
report(event) {
|
|
12
13
|
if (event.type === 'assert' && this.renumberAsserts) {
|
|
13
14
|
event = {...event, id: ++this.assertCounter};
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} else {
|
|
18
|
-
console.log(JSON.stringify(event));
|
|
19
|
-
}
|
|
16
|
+
const jsonEvent = JSON.stringify(event);
|
|
17
|
+
console.log(this.prefix ? this.prefix + jsonEvent : jsonEvent);
|
|
20
18
|
}
|
|
21
19
|
}
|
|
22
20
|
|
package/src/TTYReporter.js
CHANGED
|
@@ -24,7 +24,7 @@ const successStyle = `\x1B[48;5;${buildColor(0, 32, 0)};1;97m`,
|
|
|
24
24
|
|
|
25
25
|
// main
|
|
26
26
|
|
|
27
|
-
class TTYReporter {
|
|
27
|
+
export class TTYReporter {
|
|
28
28
|
constructor({
|
|
29
29
|
output = process.stdout,
|
|
30
30
|
renumberAsserts = false,
|
|
@@ -33,7 +33,8 @@ class TTYReporter {
|
|
|
33
33
|
showTime = true,
|
|
34
34
|
showData = true,
|
|
35
35
|
showAssertNumber = false,
|
|
36
|
-
hasColors = true
|
|
36
|
+
hasColors = true,
|
|
37
|
+
dontCaptureConsole = false
|
|
37
38
|
} = {}) {
|
|
38
39
|
this.output = output;
|
|
39
40
|
this.hasColors =
|
|
@@ -75,6 +76,8 @@ class TTYReporter {
|
|
|
75
76
|
this.success = this.paint(successStyle, reset);
|
|
76
77
|
this.failure = this.paint(failureStyle, reset);
|
|
77
78
|
this.skipped = this.paint(skippedStyle, reset);
|
|
79
|
+
this.stdoutPaint = this.paint('\x1B[90m');
|
|
80
|
+
this.stderrPaint = this.paint('\x1B[31m');
|
|
78
81
|
|
|
79
82
|
// watching for console output
|
|
80
83
|
|
|
@@ -82,31 +85,27 @@ class TTYReporter {
|
|
|
82
85
|
this.consoleLastNewLine = false;
|
|
83
86
|
this.consoleSkipChecks = false;
|
|
84
87
|
|
|
85
|
-
while (this.output.isTTY) {
|
|
88
|
+
while (!dontCaptureConsole && this.output.isTTY) {
|
|
86
89
|
this.out('');
|
|
87
90
|
|
|
88
91
|
const isCurrentTTY = this.output === process.stdout || this.output === process.stderr;
|
|
89
92
|
if (!isCurrentTTY) break;
|
|
90
93
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
94
|
+
const console = globalThis.console,
|
|
95
|
+
self = this;
|
|
96
|
+
globalThis.console = new Proxy(console, {
|
|
97
|
+
get(target, property, receiver) {
|
|
98
|
+
const prop = Reflect.get(target, property, receiver);
|
|
99
|
+
if (typeof prop !== 'function') return prop;
|
|
100
|
+
return (...args) => {
|
|
101
|
+
if (!self.consoleSkipChecks) {
|
|
102
|
+
self.consoleWasUsed = true;
|
|
103
|
+
self.consoleLastNewLine = true;
|
|
104
|
+
}
|
|
105
|
+
return prop.apply(receiver, args);
|
|
106
|
+
};
|
|
97
107
|
}
|
|
98
|
-
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const oldStderrWrite = process.stderr.write;
|
|
102
|
-
process.stderr.write = (chunk, ...args) => {
|
|
103
|
-
if (!this.consoleSkipChecks && chunk) {
|
|
104
|
-
this.consoleWasUsed = true;
|
|
105
|
-
const text = chunk.toString();
|
|
106
|
-
this.consoleLastNewLine = text[text.length - 1] === '\n';
|
|
107
|
-
}
|
|
108
|
-
return oldStderrWrite.call(process.stderr, chunk, ...args);
|
|
109
|
-
};
|
|
108
|
+
});
|
|
110
109
|
|
|
111
110
|
break;
|
|
112
111
|
}
|
|
@@ -123,8 +122,8 @@ class TTYReporter {
|
|
|
123
122
|
}
|
|
124
123
|
return this.red(this.italic(JSON.stringify(value)));
|
|
125
124
|
}
|
|
126
|
-
out(text) {
|
|
127
|
-
if (this.depth < 2 + this.technicalDepth) {
|
|
125
|
+
out(text, noIndent) {
|
|
126
|
+
if (this.depth < 2 + this.technicalDepth || noIndent) {
|
|
128
127
|
this.output.write(text + '\n');
|
|
129
128
|
} else {
|
|
130
129
|
this.output.write(stringRep(this.depth - 1 - this.technicalDepth, ' ') + text + '\n');
|
|
@@ -273,6 +272,45 @@ class TTYReporter {
|
|
|
273
272
|
case 'comment':
|
|
274
273
|
!this.failureOnly && this.out(this.blue(this.italic(event.name || 'empty comment')));
|
|
275
274
|
break;
|
|
275
|
+
case 'console-log':
|
|
276
|
+
case 'console-info':
|
|
277
|
+
case 'console-warn':
|
|
278
|
+
{
|
|
279
|
+
const lines = event.name.split(/\r?\n/),
|
|
280
|
+
type = /\-(\w+)$/.exec(event.type)[1],
|
|
281
|
+
prefix = this.stdoutPaint(type + ':') + ' ';
|
|
282
|
+
for (const line of lines) {
|
|
283
|
+
this.out(prefix + line, true);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
case 'console-error':
|
|
288
|
+
{
|
|
289
|
+
const lines = event.name.split(/\r?\n/),
|
|
290
|
+
prefix = this.stderrPaint('error:') + ' ';
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
this.out(prefix + line, true);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
case 'stdout':
|
|
297
|
+
{
|
|
298
|
+
const lines = event.name.split(/\r?\n/),
|
|
299
|
+
prefix = this.stdoutPaint('stdout:') + ' ';
|
|
300
|
+
for (const line of lines) {
|
|
301
|
+
this.out(prefix + line, true);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
case 'stderr':
|
|
306
|
+
{
|
|
307
|
+
const lines = event.name.split(/\r?\n/),
|
|
308
|
+
prefix = this.stderrPaint('stderr:') + ' ';
|
|
309
|
+
for (const line of lines) {
|
|
310
|
+
this.out(prefix + line, true);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
break;
|
|
276
314
|
case 'bail-out':
|
|
277
315
|
{
|
|
278
316
|
text = 'Bail out!';
|
package/src/TapReporter.js
CHANGED
|
@@ -15,7 +15,9 @@ const styles = {
|
|
|
15
15
|
'font-weight: bold; color: white; background-color: green; padding: 0.5em 1em;',
|
|
16
16
|
'summary-result-failure':
|
|
17
17
|
'font-weight: bold; color: white; background-color: red; padding: 0.5em 1em;',
|
|
18
|
-
'bail-out': 'color: white; background-color: red; font-weight: bold; padding: 0.5em 1em;'
|
|
18
|
+
'bail-out': 'color: white; background-color: red; font-weight: bold; padding: 0.5em 1em;',
|
|
19
|
+
stdout: 'color: gray; font-style: italic;',
|
|
20
|
+
stderr: 'color: darkred; font-style: italic;'
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
const logger = (text, style) => {
|
|
@@ -36,7 +38,7 @@ const formatValue = value => {
|
|
|
36
38
|
return JSON.stringify(value);
|
|
37
39
|
};
|
|
38
40
|
|
|
39
|
-
class TapReporter {
|
|
41
|
+
export class TapReporter {
|
|
40
42
|
constructor({write, useJson = false, renumberAsserts = false, hasColors = true} = {}) {
|
|
41
43
|
this.write = write || (hasColors ? logger : console.log.bind(console));
|
|
42
44
|
this.renumberAsserts = renumberAsserts;
|
|
@@ -63,6 +65,24 @@ class TapReporter {
|
|
|
63
65
|
this.open();
|
|
64
66
|
this.write('# ' + event.name);
|
|
65
67
|
break;
|
|
68
|
+
case 'console-log':
|
|
69
|
+
case 'console-info':
|
|
70
|
+
case 'console-warn':
|
|
71
|
+
this.open();
|
|
72
|
+
this.write('# ' + /\-(\w+)$/.exec(event.type)[1] + ': ' + event.name, 'stdout');
|
|
73
|
+
break;
|
|
74
|
+
case 'console-error':
|
|
75
|
+
this.open();
|
|
76
|
+
this.write('# error: ' + event.name, 'stderr');
|
|
77
|
+
break;
|
|
78
|
+
case 'stdout':
|
|
79
|
+
this.open();
|
|
80
|
+
this.write('# stdout: ' + event.name, 'stdout');
|
|
81
|
+
break;
|
|
82
|
+
case 'stderr':
|
|
83
|
+
this.open();
|
|
84
|
+
this.write('# stderr: ' + event.name, 'stderr');
|
|
85
|
+
break;
|
|
66
86
|
case 'end':
|
|
67
87
|
--this.depth;
|
|
68
88
|
event.name &&
|
package/src/bun/TestWorker.js
CHANGED
|
@@ -3,7 +3,7 @@ import {sep} from 'node:path';
|
|
|
3
3
|
import {StopTest} from '../State.js';
|
|
4
4
|
import EventServer from '../utils/EventServer.js';
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const srcName = new URL('../', import.meta.url),
|
|
7
7
|
baseName = Bun.pathToFileURL(Bun.cwd + sep);
|
|
8
8
|
|
|
9
9
|
export default class TestWorker extends EventServer {
|
|
@@ -47,7 +47,7 @@ export default class TestWorker extends EventServer {
|
|
|
47
47
|
});
|
|
48
48
|
this.close(id);
|
|
49
49
|
});
|
|
50
|
-
worker.postMessage({testName: testName.href,
|
|
50
|
+
worker.postMessage({testName: testName.href, srcName: srcName.href, options: this.options});
|
|
51
51
|
return id;
|
|
52
52
|
}
|
|
53
53
|
destroyTask(id) {
|
package/src/bun/worker.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {format} from 'node:util';
|
|
2
|
+
|
|
1
3
|
const sanitizeMsg = msg => {
|
|
2
4
|
if (msg.type !== 'end') return msg;
|
|
3
5
|
const state = {};
|
|
@@ -8,11 +10,32 @@ const sanitizeMsg = msg => {
|
|
|
8
10
|
return {...msg, data: state};
|
|
9
11
|
};
|
|
10
12
|
|
|
13
|
+
const consoleVerbs = {log: 1, info: 1, warn: 1, error: 1};
|
|
14
|
+
|
|
11
15
|
addEventListener('message', async event => {
|
|
12
16
|
const msg = event.data;
|
|
13
17
|
try {
|
|
14
|
-
const {setReporter} = await import(msg.
|
|
18
|
+
const {setReporter} = await import(new URL('test.js', msg.srcName));
|
|
15
19
|
setReporter(msg => postMessage(sanitizeMsg(msg)));
|
|
20
|
+
|
|
21
|
+
if (!msg.options.dontCaptureConsole) {
|
|
22
|
+
const console = globalThis.console;
|
|
23
|
+
globalThis.console = new Proxy(console, {
|
|
24
|
+
get(target, property, receiver) {
|
|
25
|
+
const prop = Reflect.get(target, property, receiver);
|
|
26
|
+
if (typeof prop === 'function') {
|
|
27
|
+
if (consoleVerbs[property] === 1) {
|
|
28
|
+
const type = 'console-' + property;
|
|
29
|
+
return (...args) => {
|
|
30
|
+
postMessage({type, name: format(...args)});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return prop;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
await import(msg.testName);
|
|
17
40
|
} catch (error) {
|
|
18
41
|
postMessage({type: 'test', test: 0, time: 0});
|
package/src/deno/TestWorker.js
CHANGED
|
@@ -4,7 +4,7 @@ import {sep} from 'node:path';
|
|
|
4
4
|
import {StopTest} from '../State.js';
|
|
5
5
|
import EventServer from '../utils/EventServer.js';
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const srcName = new URL('../', import.meta.url),
|
|
8
8
|
baseName = pathToFileURL(Deno.cwd() + sep);
|
|
9
9
|
|
|
10
10
|
export default class TestWorker extends EventServer {
|
|
@@ -41,7 +41,7 @@ export default class TestWorker extends EventServer {
|
|
|
41
41
|
});
|
|
42
42
|
this.close(id);
|
|
43
43
|
});
|
|
44
|
-
worker.postMessage({testName: testName.href,
|
|
44
|
+
worker.postMessage({testName: testName.href, srcName: srcName.href, options: this.options});
|
|
45
45
|
return id;
|
|
46
46
|
}
|
|
47
47
|
destroyTask(id) {
|
package/src/deno/worker.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {format} from 'node:util';
|
|
2
|
+
|
|
1
3
|
const sanitizeMsg = msg => {
|
|
2
4
|
if (msg.type !== 'end') return msg;
|
|
3
5
|
const state = {};
|
|
@@ -8,11 +10,32 @@ const sanitizeMsg = msg => {
|
|
|
8
10
|
return {...msg, data: state};
|
|
9
11
|
};
|
|
10
12
|
|
|
13
|
+
const consoleVerbs = {log: 1, info: 1, warn: 1, error: 1};
|
|
14
|
+
|
|
11
15
|
addEventListener('message', async event => {
|
|
12
16
|
const msg = event.data;
|
|
13
17
|
try {
|
|
14
|
-
const {setReporter} = await import(msg.
|
|
18
|
+
const {setReporter} = await import(new URL('test.js', msg.srcName));
|
|
15
19
|
setReporter(msg => postMessage(sanitizeMsg(msg)));
|
|
20
|
+
|
|
21
|
+
if (!msg.options.dontCaptureConsole) {
|
|
22
|
+
const console = globalThis.console;
|
|
23
|
+
globalThis.console = new Proxy(console, {
|
|
24
|
+
get(target, property, receiver) {
|
|
25
|
+
const prop = Reflect.get(target, property, receiver);
|
|
26
|
+
if (typeof prop === 'function') {
|
|
27
|
+
if (consoleVerbs[property] === 1) {
|
|
28
|
+
const type = 'console-' + property;
|
|
29
|
+
return (...args) => {
|
|
30
|
+
postMessage({type, name: format(...args)});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return prop;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
await import(msg.testName);
|
|
17
40
|
} catch (error) {
|
|
18
41
|
postMessage({type: 'test', test: 0, time: 0});
|
package/src/node/TestWorker.js
CHANGED
|
@@ -6,7 +6,7 @@ import {Worker} from 'node:worker_threads';
|
|
|
6
6
|
import {StopTest} from '../State.js';
|
|
7
7
|
import EventServer from '../utils/EventServer.js';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const srcName = new URL('../', import.meta.url),
|
|
10
10
|
baseName = pathToFileURL(process.cwd() + sep);
|
|
11
11
|
|
|
12
12
|
export default class TestWorker extends EventServer {
|
|
@@ -49,7 +49,7 @@ export default class TestWorker extends EventServer {
|
|
|
49
49
|
});
|
|
50
50
|
this.close(id);
|
|
51
51
|
});
|
|
52
|
-
worker.postMessage({testName: testName.href,
|
|
52
|
+
worker.postMessage({testName: testName.href, srcName: srcName.href, options: this.options});
|
|
53
53
|
return id;
|
|
54
54
|
}
|
|
55
55
|
destroyTask(id) {
|
package/src/node/worker.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {parentPort} from 'node:worker_threads';
|
|
2
|
+
import {format} from 'node:util';
|
|
2
3
|
|
|
3
4
|
const sanitizeMsg = msg => {
|
|
4
5
|
if (msg.type !== 'end') return msg;
|
|
@@ -10,10 +11,31 @@ const sanitizeMsg = msg => {
|
|
|
10
11
|
return {...msg, data: state};
|
|
11
12
|
};
|
|
12
13
|
|
|
14
|
+
const consoleVerbs = {log: 1, info: 1, warn: 1, error: 1};
|
|
15
|
+
|
|
13
16
|
parentPort.on('message', async msg => {
|
|
14
17
|
try {
|
|
15
|
-
const {setReporter} = await import(msg.
|
|
18
|
+
const {setReporter} = await import(new URL('test.js', msg.srcName));
|
|
16
19
|
setReporter(msg => parentPort.postMessage(sanitizeMsg(msg)));
|
|
20
|
+
|
|
21
|
+
if (!msg.options.dontCaptureConsole) {
|
|
22
|
+
const console = globalThis.console;
|
|
23
|
+
globalThis.console = new Proxy(console, {
|
|
24
|
+
get(target, property, receiver) {
|
|
25
|
+
const prop = Reflect.get(target, property, receiver);
|
|
26
|
+
if (typeof prop === 'function') {
|
|
27
|
+
if (consoleVerbs[property] === 1) {
|
|
28
|
+
const type = 'console-' + property;
|
|
29
|
+
return (...args) => {
|
|
30
|
+
parentPort.postMessage({type, name: format(...args)});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return prop;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
17
39
|
await import(msg.testName);
|
|
18
40
|
} catch (error) {
|
|
19
41
|
parentPort.postMessage({type: 'test', test: 0, time: 0});
|
package/src/utils/EventServer.js
CHANGED
|
@@ -11,8 +11,10 @@ export default class EventServer {
|
|
|
11
11
|
this.passThroughId = null;
|
|
12
12
|
this.backlog = {};
|
|
13
13
|
this.closed = {};
|
|
14
|
+
this.finalized = {};
|
|
14
15
|
}
|
|
15
16
|
report(id, event) {
|
|
17
|
+
if (this.finalized[id] === 1) return this.reporter(event);
|
|
16
18
|
if (this.passThroughId === null) this.passThroughId = id;
|
|
17
19
|
if (this.passThroughId === id) return this.reporter(event);
|
|
18
20
|
const events = this.backlog[id];
|
|
@@ -24,6 +26,7 @@ export default class EventServer {
|
|
|
24
26
|
}
|
|
25
27
|
close(id) {
|
|
26
28
|
this.destroyTask(id);
|
|
29
|
+
this.finalized[id] = 1;
|
|
27
30
|
--this.totalTasks;
|
|
28
31
|
if (this.fileQueue.length) {
|
|
29
32
|
++this.totalTasks;
|
|
@@ -54,7 +57,16 @@ export default class EventServer {
|
|
|
54
57
|
} else {
|
|
55
58
|
this.closed[id] = 1;
|
|
56
59
|
}
|
|
57
|
-
!this.totalTasks
|
|
60
|
+
if (!this.totalTasks) {
|
|
61
|
+
Object.keys(this.backlog).forEach(id => {
|
|
62
|
+
this.finalized[id] = 1;
|
|
63
|
+
const events = this.backlog[id];
|
|
64
|
+
events.forEach(event => this.reporter(event));
|
|
65
|
+
});
|
|
66
|
+
this.closed = {};
|
|
67
|
+
this.backlog = {};
|
|
68
|
+
this.done && this.done();
|
|
69
|
+
}
|
|
58
70
|
}
|
|
59
71
|
createTask(fileName) {
|
|
60
72
|
if (this.totalTasks < this.numberOfTasks) {
|