supertape 6.7.4 → 6.8.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,14 @@
1
+ 2021.09.24, v6.8.0
2
+
3
+ fix:
4
+ - (supertape) check that no assertions called after t.end()
5
+
6
+ feature:
7
+ - (supertape) add support of check assertions count
8
+ - (@supertape/operator-stub) add calledBefore, calledAfter
9
+ - (@supertape/operator-stub) notCalled: add additional check: called with args
10
+
11
+
1
12
  2021.09.20, v6.7.4
2
13
 
3
14
  fix:
package/README.md CHANGED
@@ -46,6 +46,8 @@ Options
46
46
  -v, --version output version information and exit
47
47
  -f, --format use a specific output format - default: progress-bar/tap on CI
48
48
  -r, --require require module
49
+ --check-scopes check that messages contains scope: 'scope: message'
50
+ --check-assertions-count check that assertion count is no more then 1
49
51
  --no-check-duplicates do not check messages for duplicates
50
52
  ```
51
53
 
@@ -53,7 +55,8 @@ Options
53
55
 
54
56
  - `SUPERTAPE_TIMEOUT` - timeout for long running processes;
55
57
  - `SUPERTAPE_CHECK_DUPLICATES` - toggle check duplicates;
56
- - `SUPERTAPE_CHECK_SCOPES` - check that test message has a scope: `scope: subject`
58
+ - `SUPERTAPE_CHECK_SCOPES` - check that test message has a scope: `scope: subject`;
59
+ - `SUPERTAPE_CHECK_ASSERTIONS_COUNT` - check that assertion count is no more then 1;
57
60
 
58
61
  ```js
59
62
  test('tape: error', (t) => {
package/help.json CHANGED
@@ -4,5 +4,6 @@
4
4
  "-f, --format ": "use a specific output format - default: progress-bar/tap on CI",
5
5
  "-r, --require ": "require module",
6
6
  "--check-scopes ": "check that messages contains scope: 'scope: message'",
7
+ "--check-assertions-count ": "check that assertion count is no more then 1",
7
8
  "--no-check-duplicates ": "do not check messages for duplicates"
8
9
  }
package/lib/cli.js CHANGED
@@ -33,6 +33,7 @@ const filesCount = fullstore(0);
33
33
  const {
34
34
  SUPERTAPE_CHECK_DUPLICATES = '1',
35
35
  SUPERTAPE_CHECK_SCOPES = '0',
36
+ SUPERTAPE_CHECK_ASSERTIONS_COUNT = '0',
36
37
  } = process.env;
37
38
 
38
39
  module.exports = async ({argv, cwd, stdout, stderr, exit}) => {
@@ -89,6 +90,7 @@ const yargsOptions = {
89
90
  'help',
90
91
  'check-duplicates',
91
92
  'check-scopes',
93
+ 'check-assertions-count',
92
94
  ],
93
95
  alias: {
94
96
  version: 'v',
@@ -97,12 +99,14 @@ const yargsOptions = {
97
99
  require: 'r',
98
100
  checkDuplicates: 'd',
99
101
  checkScopes: 's',
102
+ checkAssertionsCount: 'a',
100
103
  },
101
104
  default: {
102
105
  format: 'progress-bar',
103
106
  require: [],
104
107
  checkDuplicates: SUPERTAPE_CHECK_DUPLICATES !== '0',
105
108
  checkScopes: SUPERTAPE_CHECK_SCOPES === '1',
109
+ checkAssertionsCount: SUPERTAPE_CHECK_ASSERTIONS_COUNT === '1',
106
110
  },
107
111
  };
108
112
 
@@ -148,6 +152,7 @@ async function cli({argv, cwd, stdout, isStop}) {
148
152
  format,
149
153
  checkDuplicates,
150
154
  checkScopes,
155
+ checkAssertionsCount,
151
156
  } = args;
152
157
 
153
158
  supertape.init({
@@ -157,6 +162,7 @@ async function cli({argv, cwd, stdout, isStop}) {
157
162
  isStop,
158
163
  checkDuplicates,
159
164
  checkScopes,
165
+ checkAssertionsCount,
160
166
  });
161
167
 
162
168
  supertape.createStream().pipe(stdout);
package/lib/operators.mjs CHANGED
@@ -14,7 +14,6 @@ const isFn = (a) => typeof a === 'function';
14
14
  const isStr = (a) => typeof a === 'string';
15
15
  const isObj = (a) => typeof a === 'object';
16
16
 
17
- // backward compatibility or maybe formatters support
18
17
  const end = () => {};
19
18
 
20
19
  const ok = (actual, message = 'should be truthy') => ({
@@ -170,6 +169,21 @@ const initOperator = (runnerState) => (name) => {
170
169
  };
171
170
 
172
171
  return (...a) => {
172
+ if (name === 'end') {
173
+ runnerState.isEnded(true);
174
+ return end;
175
+ }
176
+
177
+ runnerState.incAssertionsCount();
178
+
179
+ if (runnerState.isEnded()) {
180
+ return run(
181
+ 'fail',
182
+ runnerState,
183
+ operators.fail(`Cannot run assertions after 't.end()' called`),
184
+ );
185
+ }
186
+
173
187
  const testState = fn(...a);
174
188
  return run(name, runnerState, testState);
175
189
  };
@@ -223,13 +237,15 @@ function run(name, {formatter, count, incCount, incPassed, incFailed}, testState
223
237
  });
224
238
  }
225
239
 
226
- export const initOperators = ({formatter, count, incCount, incPassed, incFailed, extensions}) => {
240
+ export const initOperators = ({formatter, count, incCount, incPassed, incFailed, incAssertionsCount, isEnded, extensions}) => {
227
241
  const operator = initOperator({
228
242
  formatter,
229
243
  count,
230
244
  incCount,
231
245
  incPassed,
232
246
  incFailed,
247
+ isEnded,
248
+ incAssertionsCount,
233
249
  });
234
250
 
235
251
  const extendedOperators = {};
@@ -251,7 +267,7 @@ export const initOperators = ({formatter, count, incCount, incPassed, incFailed,
251
267
  comment: comment({formatter}),
252
268
  match: operator('match'),
253
269
  notMatch: operator('notMatch'),
254
- end,
270
+ end: operator('end'),
255
271
 
256
272
  ...extendedOperators,
257
273
  };
package/lib/run-tests.js CHANGED
@@ -3,24 +3,16 @@
3
3
  const fullstore = require('fullstore');
4
4
  const wraptile = require('wraptile');
5
5
  const tryToCatch = require('try-to-catch');
6
- const once = require('once');
7
6
  const isDebug = require('./is-debug');
8
7
 
9
8
  const {createValidator} = require('./validator');
10
9
 
11
10
  const inc = wraptile((store) => store(store() + 1));
12
-
13
11
  const isOnly = ({only}) => only;
14
-
15
12
  const isSkip = ({skip}) => skip;
16
-
17
13
  const notSkip = ({skip}) => !skip;
18
14
 
19
- const getInitOperators = once(async () => {
20
- const {initOperators} = await import('./operators.mjs');
21
-
22
- return initOperators;
23
- });
15
+ const getInitOperators = async () => await import('./operators.mjs');
24
16
 
25
17
  const {
26
18
  SUPERTAPE_TIMEOUT = 3000,
@@ -83,7 +75,7 @@ async function runTests(tests, {formatter, operators, skiped, isStop}) {
83
75
  tests,
84
76
  });
85
77
 
86
- for (const {fn, message, extensions, at} of tests) {
78
+ for (const {fn, message, extensions, at, validations} of tests) {
87
79
  if (wasStop())
88
80
  break;
89
81
 
@@ -104,6 +96,7 @@ async function runTests(tests, {formatter, operators, skiped, isStop}) {
104
96
  incFailed,
105
97
  incPassed,
106
98
  getValidationMessage,
99
+ validations,
107
100
 
108
101
  extensions: {
109
102
  ...operators,
@@ -127,12 +120,18 @@ async function runTests(tests, {formatter, operators, skiped, isStop}) {
127
120
  };
128
121
  }
129
122
 
130
- async function runOneTest({message, at, fn, extensions, formatter, count, total, failed, incCount, incPassed, incFailed, getValidationMessage}) {
123
+ async function runOneTest({message, at, fn, extensions, formatter, count, total, failed, incCount, incPassed, incFailed, getValidationMessage, validations}) {
124
+ const isReturn = fullstore(false);
125
+ const assertionsCount = fullstore(0);
126
+ const isEnded = fullstore(false);
127
+ const incAssertionsCount = inc(assertionsCount);
128
+
131
129
  formatter.emit('test', {
132
130
  test: message,
133
131
  });
134
132
 
135
- const initOperators = await getInitOperators();
133
+ const {initOperators} = await getInitOperators();
134
+ const {checkIfEnded} = validations;
136
135
 
137
136
  const t = initOperators({
138
137
  formatter,
@@ -140,16 +139,35 @@ async function runOneTest({message, at, fn, extensions, formatter, count, total,
140
139
  incCount,
141
140
  incPassed,
142
141
  incFailed,
142
+ assertionsCount,
143
+ incAssertionsCount,
144
+ isEnded,
143
145
  extensions,
146
+ checkIfEnded,
144
147
  });
145
148
 
146
- const [timer, stopTimer] = timeout(SUPERTAPE_TIMEOUT, ['timeout']);
147
- const [error] = await Promise.race([tryToCatch(fn, t), timer]);
148
- stopTimer();
149
+ if (!isReturn()) {
150
+ const [timer, stopTimer] = timeout(SUPERTAPE_TIMEOUT, ['timeout']);
151
+ const [error] = await Promise.race([tryToCatch(fn, t), timer]);
152
+ stopTimer();
153
+ isEnded(false);
154
+
155
+ if (error) {
156
+ t.fail(error, at);
157
+ t.end();
158
+ isReturn(true);
159
+ }
160
+ }
149
161
 
150
- if (error) {
151
- t.fail(error, at);
152
- t.end();
162
+ if (!isReturn()) {
163
+ const [validationMessage, atLine] = getValidationMessage(message, {
164
+ assertionsCount: assertionsCount(),
165
+ });
166
+
167
+ if (atLine) {
168
+ t.fail(validationMessage, atLine);
169
+ t.end();
170
+ }
153
171
  }
154
172
 
155
173
  formatter.emit('test:end', {
@@ -158,11 +176,4 @@ async function runOneTest({message, at, fn, extensions, formatter, count, total,
158
176
  test: message,
159
177
  failed: failed(),
160
178
  });
161
-
162
- const [validationMessage, atLine] = getValidationMessage(message);
163
-
164
- if (atLine) {
165
- t.fail(validationMessage, atLine);
166
- t.end();
167
- }
168
179
  }
package/lib/supertape.js CHANGED
@@ -35,6 +35,8 @@ const defaultOptions = {
35
35
  getOperators,
36
36
  isStop: () => false,
37
37
  checkDuplicates: true,
38
+ checkIfEnded: true,
39
+ checkAssertionsCount: false,
38
40
  checkScopes: false,
39
41
  };
40
42
 
@@ -111,6 +113,8 @@ function test(message, fn, options = {}) {
111
113
  isStop,
112
114
  checkDuplicates,
113
115
  checkScopes,
116
+ checkAssertionsCount,
117
+ checkIfEnded,
114
118
  } = {
115
119
  ...defaultOptions,
116
120
  ...initedOptions,
@@ -120,6 +124,8 @@ function test(message, fn, options = {}) {
120
124
  const validations = {
121
125
  checkDuplicates,
122
126
  checkScopes,
127
+ checkAssertionsCount,
128
+ checkIfEnded,
123
129
  };
124
130
 
125
131
  setValidations(validations);
package/lib/validator.js CHANGED
@@ -14,11 +14,13 @@ const processedList = new Set();
14
14
  const validations = {
15
15
  checkDuplicates: true,
16
16
  checkScopes: false,
17
+ checkAssertionsCount: true,
17
18
  };
18
19
 
19
20
  const validators = {
20
21
  checkDuplicates,
21
22
  checkScopes,
23
+ checkAssertionsCount,
22
24
  };
23
25
 
24
26
  const {
@@ -33,16 +35,17 @@ const findByMessage = (msg, tests) => {
33
35
  return filtered;
34
36
  };
35
37
 
36
- module.exports.setValidations = ({checkDuplicates, checkScopes}) => {
38
+ module.exports.setValidations = ({checkDuplicates, checkScopes, checkAssertionsCount}) => {
37
39
  assign(validations, {
38
40
  checkDuplicates,
39
41
  checkScopes,
42
+ checkAssertionsCount,
40
43
  });
41
44
  };
42
45
 
43
46
  const isValidationEnabled = (a) => values(a).filter(Boolean).length;
44
47
 
45
- module.exports.createValidator = ({tests}) => (msg) => {
48
+ module.exports.createValidator = ({tests}) => (msg, options) => {
46
49
  if (!isValidationEnabled(validations))
47
50
  return [];
48
51
 
@@ -55,7 +58,7 @@ module.exports.createValidator = ({tests}) => (msg) => {
55
58
  if (!filtered.length)
56
59
  throw Error('☝️Looks like message cannot be find in tests, this should never happen');
57
60
 
58
- const [message, at] = validators[name](msg, filtered);
61
+ const [message, at] = validators[name](msg, filtered, options);
59
62
 
60
63
  if (at)
61
64
  return [message, at];
@@ -65,14 +68,6 @@ module.exports.createValidator = ({tests}) => (msg) => {
65
68
  };
66
69
 
67
70
  module.exports.getAt = () => {
68
- const {
69
- checkDuplicates,
70
- checkScopes,
71
- } = validations;
72
-
73
- if (!checkDuplicates && !checkScopes)
74
- return '';
75
-
76
71
  return getFileName();
77
72
  };
78
73
 
@@ -91,6 +86,16 @@ function getFileName() {
91
86
  return '';
92
87
  }
93
88
 
89
+ function checkAssertionsCount(msg, filtered, options) {
90
+ const {assertionsCount} = options;
91
+ const [, at] = filtered[0];
92
+
93
+ if (assertionsCount > 1)
94
+ return [`Only one assertion per test allowed, looks like you have more`, at];
95
+
96
+ return [];
97
+ }
98
+
94
99
  function checkScopes(msg, filtered) {
95
100
  const [message, at] = filtered[0];
96
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supertape",
3
- "version": "6.7.4",
3
+ "version": "6.8.0",
4
4
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
5
5
  "description": "tape compatible test runner with superpowers",
6
6
  "homepage": "http://github.com/coderaiser/supertape",