supertape 6.7.4 → 6.9.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 +29 -0
- package/README.md +4 -1
- package/help.json +1 -0
- package/lib/cli.js +6 -0
- package/lib/operators.mjs +56 -3
- package/lib/run-tests.js +36 -25
- package/lib/supertape.js +6 -0
- package/lib/validator.js +19 -11
- package/package.json +1 -1
package/ChangeLog
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
2021.09.25, v6.9.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- (supertape) fail when couple t.end() operators found
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
2021.09.25, v6.8.2
|
|
8
|
+
|
|
9
|
+
feature:
|
|
10
|
+
- (supertape) check that no assertions called after t.end() in async operators
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
2021.09.24, v6.8.1
|
|
14
|
+
|
|
15
|
+
fix:
|
|
16
|
+
- (supertape) ability to disable check-assertions-count per test
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
2021.09.24, v6.8.0
|
|
20
|
+
|
|
21
|
+
fix:
|
|
22
|
+
- (supertape) check that no assertions called after t.end()
|
|
23
|
+
|
|
24
|
+
feature:
|
|
25
|
+
- (supertape) add support of check assertions count
|
|
26
|
+
- (@supertape/operator-stub) add calledBefore, calledAfter
|
|
27
|
+
- (@supertape/operator-stub) notCalled: add additional check: called with args
|
|
28
|
+
|
|
29
|
+
|
|
1
30
|
2021.09.20, v6.7.4
|
|
2
31
|
|
|
3
32
|
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') => ({
|
|
@@ -165,16 +164,68 @@ const initOperator = (runnerState) => (name) => {
|
|
|
165
164
|
|
|
166
165
|
if (isAsync(fn))
|
|
167
166
|
return async (...a) => {
|
|
167
|
+
const [valid, end] = validateEnd({
|
|
168
|
+
name,
|
|
169
|
+
operators,
|
|
170
|
+
runnerState,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (!valid)
|
|
174
|
+
return end;
|
|
175
|
+
|
|
168
176
|
const testState = await fn(...a);
|
|
169
177
|
return run(name, runnerState, testState);
|
|
170
178
|
};
|
|
171
179
|
|
|
172
180
|
return (...a) => {
|
|
181
|
+
const [valid, end] = validateEnd({
|
|
182
|
+
name,
|
|
183
|
+
operators,
|
|
184
|
+
runnerState,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (!valid)
|
|
188
|
+
return end;
|
|
189
|
+
|
|
173
190
|
const testState = fn(...a);
|
|
174
191
|
return run(name, runnerState, testState);
|
|
175
192
|
};
|
|
176
193
|
};
|
|
177
194
|
|
|
195
|
+
const VALID = true;
|
|
196
|
+
const INVALID = false;
|
|
197
|
+
|
|
198
|
+
function validateEnd({name, operators, runnerState}) {
|
|
199
|
+
const {
|
|
200
|
+
isEnded,
|
|
201
|
+
incAssertionsCount,
|
|
202
|
+
} = runnerState;
|
|
203
|
+
|
|
204
|
+
incAssertionsCount();
|
|
205
|
+
|
|
206
|
+
if (name === 'end' && isEnded())
|
|
207
|
+
return [INVALID, run(
|
|
208
|
+
'fail',
|
|
209
|
+
runnerState,
|
|
210
|
+
operators.fail(`Cannot use a couple 't.end()' operators in one test`),
|
|
211
|
+
)];
|
|
212
|
+
|
|
213
|
+
if (name === 'end') {
|
|
214
|
+
isEnded(true);
|
|
215
|
+
return [INVALID, end];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (isEnded()) {
|
|
219
|
+
return [INVALID, run(
|
|
220
|
+
'fail',
|
|
221
|
+
runnerState,
|
|
222
|
+
operators.fail(`Cannot run assertions after 't.end()' called`),
|
|
223
|
+
)];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return [VALID];
|
|
227
|
+
}
|
|
228
|
+
|
|
178
229
|
const validate = (a) => {
|
|
179
230
|
if (isFn(a))
|
|
180
231
|
return fail('looks like operator returns function, it will always fail');
|
|
@@ -223,13 +274,15 @@ function run(name, {formatter, count, incCount, incPassed, incFailed}, testState
|
|
|
223
274
|
});
|
|
224
275
|
}
|
|
225
276
|
|
|
226
|
-
export const initOperators = ({formatter, count, incCount, incPassed, incFailed, extensions}) => {
|
|
277
|
+
export const initOperators = ({formatter, count, incCount, incPassed, incFailed, incAssertionsCount, isEnded, extensions}) => {
|
|
227
278
|
const operator = initOperator({
|
|
228
279
|
formatter,
|
|
229
280
|
count,
|
|
230
281
|
incCount,
|
|
231
282
|
incPassed,
|
|
232
283
|
incFailed,
|
|
284
|
+
isEnded,
|
|
285
|
+
incAssertionsCount,
|
|
233
286
|
});
|
|
234
287
|
|
|
235
288
|
const extendedOperators = {};
|
|
@@ -251,7 +304,7 @@ export const initOperators = ({formatter, count, incCount, incPassed, incFailed,
|
|
|
251
304
|
comment: comment({formatter}),
|
|
252
305
|
match: operator('match'),
|
|
253
306
|
notMatch: operator('notMatch'),
|
|
254
|
-
end,
|
|
307
|
+
end: operator('end'),
|
|
255
308
|
|
|
256
309
|
...extendedOperators,
|
|
257
310
|
};
|
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 =
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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 (
|
|
151
|
-
|
|
152
|
-
|
|
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,19 @@ 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 (!isEnabled(filtered, 'checkAssertionsCount'))
|
|
94
|
+
return [];
|
|
95
|
+
|
|
96
|
+
if (assertionsCount > 1)
|
|
97
|
+
return [`Only one assertion per test allowed, looks like you have more`, at];
|
|
98
|
+
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
|
|
94
102
|
function checkScopes(msg, filtered) {
|
|
95
103
|
const [message, at] = filtered[0];
|
|
96
104
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supertape",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.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",
|