tape-six 1.4.5 → 1.5.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 CHANGED
@@ -380,6 +380,7 @@ Test output can be controlled by flags. See [Supported flags](https://github.com
380
380
 
381
381
  The most recent releases:
382
382
 
383
+ - 1.5.0 _Internal refactoring (moved state to reporters), added type identification of values in the DOM and TTY reporters, multiple minor fixes._
383
384
  - 1.4.5 _Internal: added flags support for custom test runners._
384
385
  - 1.4.4 _Refreshed the lock file._
385
386
  - 1.4.3 _Updated dev dependencies + a minor bugfix._
package/bin/tape6-bun.js CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  } from '../src/utils/config.js';
10
10
 
11
11
  import {getReporter, setReporter} from '../src/test.js';
12
- import State, {StopTest} from '../src/State.js';
13
12
  import {selectTimer} from '../src/utils/timer.js';
14
13
 
15
14
  import TestWorker from '../src/bun/TestWorker.js';
@@ -52,7 +51,7 @@ const config = () => {
52
51
  const arg = Bun.argv[i];
53
52
  if (arg == '-f' || arg == '--flags') {
54
53
  if (++i < Bun.argv.length) {
55
- flags = Bun.argv[i];
54
+ flags += Bun.argv[i];
56
55
  }
57
56
  continue;
58
57
  }
@@ -101,11 +100,11 @@ const init = async () => {
101
100
  if (!currentReporter) {
102
101
  const reporterType = getReporterType(),
103
102
  reporterFile = reporters[reporterType] || reporters.tty,
104
- CustomReporter = (await import('../src/' + reporterFile)).default,
103
+ CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
105
104
  customOptions =
106
105
  reporterType === 'tap' ? {useJson: true, hasColors: !options.monochrome} : options,
107
106
  customReporter = new CustomReporter(customOptions);
108
- setReporter(customReporter.report.bind(customReporter));
107
+ setReporter(customReporter);
109
108
  }
110
109
 
111
110
  if (files.length) {
@@ -115,14 +114,6 @@ const init = async () => {
115
114
  }
116
115
  };
117
116
 
118
- const safeEmit = rootState => event => {
119
- try {
120
- rootState.emit(event);
121
- } catch (error) {
122
- if (!(error instanceof StopTest)) throw error;
123
- }
124
- };
125
-
126
117
  const main = async () => {
127
118
  config();
128
119
  await init();
@@ -132,25 +123,25 @@ const main = async () => {
132
123
  console.error('UNHANDLED ERROR:', origin, error)
133
124
  );
134
125
 
135
- const rootState = new State(null, {callback: getReporter(), failOnce: options.failOnce}),
136
- worker = new TestWorker(safeEmit(rootState), parallel, options);
126
+ const reporter = getReporter(),
127
+ worker = new TestWorker(reporter, parallel, options);
137
128
 
138
- rootState.emit({type: 'test', test: 0, time: rootState.timer.now()});
129
+ reporter.report({type: 'test', test: 0});
139
130
 
140
131
  await new Promise(resolve => {
141
132
  worker.done = () => resolve();
142
133
  worker.execute(files);
143
134
  });
144
135
 
145
- rootState.emit({
136
+ const hasFailed = reporter.state && reporter.state.failed > 0;
137
+
138
+ reporter.report({
146
139
  type: 'end',
147
140
  test: 0,
148
- time: rootState.timer.now(),
149
- fail: rootState.failed > 0,
150
- data: rootState
141
+ fail: hasFailed
151
142
  });
152
143
 
153
- process.exit(rootState.failed > 0 ? 1 : 0);
144
+ process.exit(hasFailed ? 1 : 0);
154
145
  };
155
146
 
156
147
  main().catch(error => console.error('ERROR:', error));
package/bin/tape6-deno.js CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  } from '../src/utils/config.js';
10
10
 
11
11
  import {getReporter, setReporter} from '../src/test.js';
12
- import State, {StopTest} from '../src/State.js';
13
12
  import {selectTimer} from '../src/utils/timer.js';
14
13
 
15
14
  import TestWorker from '../src/deno/TestWorker.js';
@@ -52,7 +51,7 @@ const config = () => {
52
51
  const arg = Deno.args[i];
53
52
  if (arg == '-f' || arg == '--flags') {
54
53
  if (++i < Deno.args.length) {
55
- flags = Deno.args[i];
54
+ flags += Deno.args[i];
56
55
  }
57
56
  continue;
58
57
  }
@@ -101,11 +100,11 @@ const init = async () => {
101
100
  if (!currentReporter) {
102
101
  const reporterType = getReporterType(),
103
102
  reporterFile = reporters[reporterType] || reporters.tty,
104
- CustomReporter = (await import('../src/' + reporterFile)).default,
103
+ CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
105
104
  customOptions =
106
105
  reporterType === 'tap' ? {useJson: true, hasColors: !options.monochrome} : options,
107
106
  customReporter = new CustomReporter(customOptions);
108
- setReporter(customReporter.report.bind(customReporter));
107
+ setReporter(customReporter);
109
108
  }
110
109
 
111
110
  if (files.length) {
@@ -115,14 +114,6 @@ const init = async () => {
115
114
  }
116
115
  };
117
116
 
118
- const safeEmit = rootState => event => {
119
- try {
120
- rootState.emit(event);
121
- } catch (error) {
122
- if (!(error instanceof StopTest)) throw error;
123
- }
124
- };
125
-
126
117
  const main = async () => {
127
118
  config();
128
119
  await init();
@@ -133,25 +124,25 @@ const main = async () => {
133
124
  event.preventDefault();
134
125
  });
135
126
 
136
- const rootState = new State(null, {callback: getReporter(), failOnce: options.failOnce}),
137
- worker = new TestWorker(safeEmit(rootState), parallel, options);
127
+ const reporter = getReporter(),
128
+ worker = new TestWorker(reporter, parallel, options);
138
129
 
139
- rootState.emit({type: 'test', test: 0, time: rootState.timer.now()});
130
+ reporter.report({type: 'test', test: 0});
140
131
 
141
132
  await new Promise(resolve => {
142
133
  worker.done = () => resolve();
143
134
  worker.execute(files);
144
135
  });
145
136
 
146
- rootState.emit({
137
+ const hasFailed = reporter.state && reporter.state.failed > 0;
138
+
139
+ reporter.report({
147
140
  type: 'end',
148
141
  test: 0,
149
- time: rootState.timer.now(),
150
- fail: rootState.failed > 0,
151
- data: rootState
142
+ fail: hasFailed
152
143
  });
153
144
 
154
- Deno.exit(rootState.failed > 0 ? 1 : 0);
145
+ Deno.exit(hasFailed ? 1 : 0);
155
146
  };
156
147
 
157
148
  main().catch(error => console.error('ERROR:', error));
package/bin/tape6-node.js CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  } from '../src/utils/config.js';
11
11
 
12
12
  import {getReporter, setReporter} from '../src/test.js';
13
- import State, {StopTest} from '../src/State.js';
14
13
  import {selectTimer} from '../src/utils/timer.js';
15
14
 
16
15
  import TestWorker from '../src/node/TestWorker.js';
@@ -53,7 +52,7 @@ const config = () => {
53
52
  const arg = process.argv[i];
54
53
  if (arg == '-f' || arg == '--flags') {
55
54
  if (++i < process.argv.length) {
56
- flags = process.argv[i];
55
+ flags += process.argv[i];
57
56
  }
58
57
  continue;
59
58
  }
@@ -102,11 +101,11 @@ const init = async () => {
102
101
  if (!currentReporter) {
103
102
  const reporterType = getReporterType(),
104
103
  reporterFile = reporters[reporterType] || reporters.tty,
105
- CustomReporter = (await import('../src/' + reporterFile)).default,
104
+ CustomReporter = (await import('../src/reporters/' + reporterFile)).default,
106
105
  customOptions =
107
106
  reporterType === 'tap' ? {useJson: true, hasColors: !options.monochrome} : options,
108
107
  customReporter = new CustomReporter(customOptions);
109
- setReporter(customReporter.report.bind(customReporter));
108
+ setReporter(customReporter);
110
109
  }
111
110
 
112
111
  if (files.length) {
@@ -116,14 +115,6 @@ const init = async () => {
116
115
  }
117
116
  };
118
117
 
119
- const safeEmit = rootState => event => {
120
- try {
121
- rootState.emit(event);
122
- } catch (error) {
123
- if (!(error instanceof StopTest)) throw error;
124
- }
125
- };
126
-
127
118
  const main = async () => {
128
119
  config();
129
120
  await init();
@@ -133,25 +124,25 @@ const main = async () => {
133
124
  console.error('UNHANDLED ERROR:', origin, error)
134
125
  );
135
126
 
136
- const rootState = new State(null, {callback: getReporter(), failOnce: options.failOnce}),
137
- worker = new TestWorker(safeEmit(rootState), parallel, options);
127
+ const reporter = getReporter(),
128
+ worker = new TestWorker(reporter, parallel, options);
138
129
 
139
- rootState.emit({type: 'test', test: 0, time: rootState.timer.now()});
130
+ reporter.report({type: 'test', test: 0});
140
131
 
141
132
  await new Promise(resolve => {
142
133
  worker.done = () => resolve();
143
134
  worker.execute(files);
144
135
  });
145
136
 
146
- rootState.emit({
137
+ const hasFailed = reporter.state && reporter.state.failed > 0;
138
+
139
+ reporter.report({
147
140
  type: 'end',
148
141
  test: 0,
149
- time: rootState.timer.now(),
150
- fail: rootState.failed > 0,
151
- data: rootState
142
+ fail: hasFailed
152
143
  });
153
144
 
154
- process.exit(rootState.failed > 0 ? 1 : 0);
145
+ process.exit(hasFailed ? 1 : 0);
155
146
  };
156
147
 
157
148
  main().catch(error => console.error('ERROR:', error));
package/index.js CHANGED
@@ -10,9 +10,9 @@ import {
10
10
  getConfiguredFlag,
11
11
  registerNotifyCallback
12
12
  } from './src/test.js';
13
+ import {selectTimer} from './src/utils/timer.js';
13
14
  import defer from './src/utils/defer.js';
14
- import State from './src/State.js';
15
- import TapReporter from './src/TapReporter.js';
15
+ import TapReporter from './src/reporters/TapReporter.js';
16
16
 
17
17
  const optionNames = {
18
18
  f: 'failureOnly',
@@ -71,53 +71,47 @@ const init = async () => {
71
71
  const id =
72
72
  window.__tape6_id || new URLSearchParams(window.location.search.substring(1)).get('id');
73
73
  if (typeof window.__tape6_reporter == 'function') {
74
- reporter = event => window.__tape6_reporter(id, event);
74
+ const reportTo = event => window.__tape6_reporter(id, event),
75
+ {ProxyReporter} = await import('./src/reporters/ProxyReporter.js');
76
+ reporter = new ProxyReporter({...options, reportTo});
75
77
  } else if (window.parent && typeof window.parent.__tape6_reporter == 'function') {
76
- reporter = event => window.parent.__tape6_reporter(id, event);
78
+ const reportTo = event => window.parent.__tape6_reporter(id, event),
79
+ {ProxyReporter} = await import('./src/reporters/ProxyReporter.js');
80
+ reporter = new ProxyReporter({...options, reportTo});
77
81
  } else if (options.useJsonL) {
78
- const {JSONLReporter} = await import('./src/JSONLReporter.js'),
79
- jsonlReporter = new JSONLReporter({...options, originalConsole});
80
- reporter = jsonlReporter.report.bind(jsonlReporter);
82
+ const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
83
+ reporter = new JSONLReporter({...options, originalConsole});
81
84
  }
82
85
  } else if (isDeno) {
83
86
  if (Deno.env.get('TAPE6_JSONL')) {
84
- const {JSONLReporter} = await import('./src/JSONLReporter.js'),
85
- jsonlReporter = new JSONLReporter({...options, originalConsole});
86
- reporter = jsonlReporter.report.bind(jsonlReporter);
87
+ const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
88
+ reporter = new JSONLReporter({...options, originalConsole});
87
89
  } else if (!Deno.env.get('TAPE6_TAP')) {
88
- const {TTYReporter} = await import('./src/TTYReporter.js'),
89
- ttyReporter = new TTYReporter({...options, originalConsole});
90
- reporter = ttyReporter.report.bind(ttyReporter);
90
+ const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
91
+ reporter = new TTYReporter({...options, originalConsole});
91
92
  }
92
93
  } else if (isBun) {
93
94
  if (Bun.env.TAPE6_JSONL) {
94
- const {JSONLReporter} = await import('./src/JSONLReporter.js'),
95
- jsonlReporter = new JSONLReporter({...options, originalConsole});
96
- reporter = jsonlReporter.report.bind(jsonlReporter);
95
+ const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
96
+ reporter = new JSONLReporter({...options, originalConsole});
97
97
  } else if (!Bun.env.TAPE6_TAP) {
98
- const {TTYReporter} = await import('./src/TTYReporter.js'),
99
- ttyReporter = new TTYReporter({...options, originalConsole});
100
- reporter = ttyReporter.report.bind(ttyReporter);
98
+ const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
99
+ reporter = new TTYReporter({...options, originalConsole});
101
100
  }
102
101
  } else if (isNode) {
103
102
  if (process.env.TAPE6_JSONL) {
104
- const {JSONLReporter} = await import('./src/JSONLReporter.js'),
105
- jsonlReporter = new JSONLReporter({...options, originalConsole});
106
- reporter = jsonlReporter.report.bind(jsonlReporter);
103
+ const {JSONLReporter} = await import('./src/reporters/JSONLReporter.js');
104
+ reporter = new JSONLReporter({...options, originalConsole});
107
105
  } else if (!process.env.TAPE6_TAP) {
108
- const {TTYReporter} = await import('./src/TTYReporter.js'),
109
- ttyReporter = new TTYReporter({...options, originalConsole});
110
- reporter = ttyReporter.report.bind(ttyReporter);
106
+ const {TTYReporter} = await import('./src/reporters/TTYReporter.js');
107
+ reporter = new TTYReporter({...options, originalConsole});
111
108
  }
112
109
  }
113
- if (!reporter) {
114
- const tapReporter = new TapReporter({
115
- useJson: true,
116
- hasColors: !options.monochrome,
117
- originalConsole
118
- });
119
- reporter = tapReporter.report.bind(tapReporter);
120
- }
110
+ reporter ||= new TapReporter({
111
+ useJson: true,
112
+ hasColors: !options.monochrome,
113
+ originalConsole
114
+ });
121
115
  setReporter(reporter);
122
116
  }
123
117
 
@@ -144,44 +138,43 @@ const init = async () => {
144
138
  let settings = null;
145
139
 
146
140
  const testCallback = async () => {
141
+ await selectTimer();
147
142
  if (!settings) settings = await init();
148
143
 
149
- const {reporter, options, testFileName} = settings,
150
- rootState = new State(null, {callback: reporter, failOnce: options.failOnce});
144
+ const {reporter, testFileName} = settings;
151
145
 
152
- rootState.emit({
146
+ reporter.report({
153
147
  type: 'test',
154
148
  test: 0,
155
- name: testFileName ? 'FILE: /' + testFileName : '',
156
- time: rootState.timer.now()
149
+ name: testFileName ? 'FILE: /' + testFileName : ''
157
150
  });
158
151
 
159
152
  for (;;) {
160
153
  const tests = getTests();
161
154
  if (!tests.length) break;
162
155
  clearTests();
163
- const canContinue = await runTests(rootState, tests);
156
+ const canContinue = await runTests(tests);
164
157
  if (!canContinue) break;
165
158
  await new Promise(resolve => defer(resolve));
166
159
  }
167
160
 
168
- rootState.emit({
161
+ const runHasFailed = reporter.state && reporter.state.failed > 0;
162
+
163
+ reporter.report({
169
164
  type: 'end',
170
165
  test: 0,
171
166
  name: testFileName ? 'FILE: /' + testFileName : '',
172
- time: rootState.timer.now(),
173
- fail: rootState.failed > 0,
174
- data: rootState
167
+ fail: runHasFailed
175
168
  });
176
169
 
177
170
  if (typeof Deno == 'object') {
178
- rootState.failed > 0 && Deno.exit(1);
171
+ runHasFailed && Deno.exit(1);
179
172
  } else if (typeof Bun == 'object') {
180
- rootState.failed > 0 && process.exit(1);
173
+ runHasFailed && process.exit(1);
181
174
  } else if (typeof process == 'object' && process.versions?.node) {
182
- rootState.failed > 0 && process.exit(1);
175
+ runHasFailed && process.exit(1);
183
176
  } else if (typeof __tape6_reportResults == 'function') {
184
- __tape6_reportResults(rootState.failed > 0 ? 'failure' : 'success');
177
+ __tape6_reportResults(runHasFailed ? 'failure' : 'success');
185
178
  }
186
179
 
187
180
  registerNotifyCallback(testCallback); // register self again
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tape-six",
3
- "version": "1.4.5",
3
+ "version": "1.5.0",
4
4
  "description": "TAP the test harness for the modern JavaScript (ES6).",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/OK.js CHANGED
@@ -6,7 +6,7 @@ const listVariables = (code, self) => {
6
6
  const vars =
7
7
  code
8
8
  .replace(
9
- /(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*\b|\b[a-zA-Z_$][a-zA-Z_$\d]*:|\b(?:function|return|if|else|switch|case|while|for|do|break|continue|var|try|catch|finally|throw|with|debugger|default|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|window|document)\b|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g,
9
+ /(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*\b|\b[a-zA-Z_$][a-zA-Z_$\d]*:|\b(?:function|return|if|else|switch|case|while|for|do|break|continue|var|try|catch|finally|throw|with|debugger|default|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|window|document|const|let|async|await)\b|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g,
10
10
  ''
11
11
  )
12
12
  .match(/(\b[a-z_$][a-z_$\d]*\b)/gi) || [];
@@ -31,11 +31,11 @@ Tester.prototype.OK = function OK(condition, msg, options) {
31
31
  msg = undefined;
32
32
  }
33
33
  const {self = 't'} = options || {};
34
- return `(${self}.state.emit({
34
+ return `(${self}.reporter.report({
35
35
  name: ${JSON.stringify(msg || condition)},
36
36
  test: ${self}.testNumber,
37
37
  marker: new Error(),
38
- time: ${self}.state.timer.now(),
38
+ time: ${self}.timer.now(),
39
39
  operator: 'ok',
40
40
  fail: !(${condition}),
41
41
  data: {
package/src/State.js CHANGED
@@ -4,6 +4,8 @@ export class StopTest extends Error {}
4
4
 
5
5
  export const signature = 'tape6-!@#$%^&*';
6
6
 
7
+ export const isStopTest = error => error instanceof StopTest || error[signature] === signature;
8
+
7
9
  const replacer =
8
10
  (seen = new Set()) =>
9
11
  (_, value) => {
@@ -56,19 +58,20 @@ const serialize = object => {
56
58
  });
57
59
  };
58
60
 
59
- class State {
60
- constructor(parent, {callback, skip, todo, failOnce}) {
61
+ export class State {
62
+ constructor(parent, {name, test, time, skip, todo, failOnce, timer}) {
61
63
  this.parent = parent;
64
+ this.name = name || '';
65
+ this.test = test || 0;
62
66
  parent = parent || {};
63
- this.callback = callback || parent.callback;
64
67
  this.skip = skip || parent.skip;
65
68
  this.todo = todo || parent.todo;
66
69
  this.failOnce = failOnce || parent.failOnce;
67
70
  this.offset = parent.asserts || 0;
68
- this.timer = parent.timer || getTimer();
69
71
  this.asserts = this.skipped = this.failed = 0;
70
72
  this.stopTest = false;
71
- this.startTime = this.time = this.timer.now();
73
+ this.timer = timer || parent.timer || getTimer();
74
+ this.startTime = this.time = time || this.timer.now();
72
75
  }
73
76
 
74
77
  updateParent() {
@@ -78,23 +81,27 @@ class State {
78
81
  this.parent.failed += this.failed;
79
82
  }
80
83
 
81
- emit(event) {
84
+ preprocess(event) {
82
85
  event = {...event, skip: event.skip || this.skip, todo: event.todo || this.todo};
83
86
  !event.type && (event.type = 'assert');
84
87
 
88
+ if (typeof event.time !== 'number' || !event.time) {
89
+ event.time = this.timer.now();
90
+ delete event.diffTime;
91
+ }
92
+
93
+ if (event.type === 'test') return event;
94
+
85
95
  const isFailed = event.fail && !event.todo && !event.skip;
86
96
 
87
- switch (event.type) {
88
- case 'assert':
89
- ++this.asserts;
90
- event.skip && ++this.skipped;
91
- isFailed && ++this.failed;
92
- event.id = this.asserts + this.offset;
93
- !event.hasOwnProperty('diffTime') && (event.diffTime = event.time - this.time);
94
- break;
95
- case 'end':
96
- !event.hasOwnProperty('diffTime') && (event.diffTime = event.time - this.startTime);
97
- break;
97
+ if (event.type === 'assert') {
98
+ ++this.asserts;
99
+ event.skip && ++this.skipped;
100
+ isFailed && ++this.failed;
101
+ event.id = this.asserts + this.offset;
102
+ typeof event.diffTime !== 'number' && (event.diffTime = event.time - this.time);
103
+ } else {
104
+ typeof event.diffTime !== 'number' && (event.diffTime = event.time - this.startTime);
98
105
  }
99
106
 
100
107
  if (
@@ -141,16 +148,23 @@ class State {
141
148
  event.stopTest = true;
142
149
  }
143
150
 
144
- this.callback(event);
151
+ return event;
152
+ }
145
153
 
154
+ postprocess(event) {
146
155
  switch (event.type) {
147
156
  case 'assert':
148
- if (event.stopTest && event.operator !== 'exception')
149
- throw new StopTest('failOnce is activated');
157
+ if (event.stopTest && event.operator !== 'exception') {
158
+ const stopTest = new StopTest('failOnce is activated');
159
+ stopTest[signature] = signature;
160
+ throw stopTest;
161
+ }
150
162
  this.time = this.timer.now();
151
163
  break;
152
164
  case 'bail-out':
153
- throw new StopTest('bailOut is activated');
165
+ const stopTest = new StopTest('bailOut is activated');
166
+ stopTest[signature] = signature;
167
+ throw stopTest;
154
168
  }
155
169
  }
156
170