vest 5.0.0-dev-781e21 → 5.0.0-dev-ec989a
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/LICENSE +2 -2
- package/README.md +2 -57
- package/dist/cjs/classnames.development.js +37 -17
- package/dist/cjs/classnames.production.js +1 -1
- package/dist/cjs/enforce/compose.development.js +1 -54
- package/dist/cjs/enforce/compose.production.js +1 -1
- package/dist/cjs/enforce/compounds.development.js +18 -84
- package/dist/cjs/enforce/compounds.production.js +1 -1
- package/dist/cjs/enforce/schema.development.js +18 -84
- package/dist/cjs/enforce/schema.production.js +1 -1
- package/dist/cjs/parser.development.js +30 -11
- package/dist/cjs/parser.production.js +1 -1
- package/dist/cjs/promisify.development.js +21 -9
- package/dist/cjs/promisify.production.js +1 -1
- package/dist/cjs/vest.development.js +1324 -1294
- package/dist/cjs/vest.production.js +1 -1
- package/dist/es/classnames.development.js +39 -19
- package/dist/es/classnames.production.js +1 -1
- package/dist/es/enforce/compose.development.js +1 -58
- package/dist/es/enforce/compose.production.js +1 -1
- package/dist/es/enforce/compounds.development.js +2 -90
- package/dist/es/enforce/compounds.production.js +1 -1
- package/dist/es/enforce/schema.development.js +2 -88
- package/dist/es/enforce/schema.production.js +1 -1
- package/dist/es/parser.development.js +31 -10
- package/dist/es/parser.production.js +1 -1
- package/dist/es/promisify.development.js +22 -10
- package/dist/es/promisify.production.js +1 -1
- package/dist/es/vest.development.js +1321 -1286
- package/dist/es/vest.production.js +1 -1
- package/dist/umd/classnames.development.js +40 -20
- package/dist/umd/classnames.production.js +1 -1
- package/dist/umd/enforce/compose.development.js +6 -60
- package/dist/umd/enforce/compose.production.js +1 -1
- package/dist/umd/enforce/compounds.development.js +29 -94
- package/dist/umd/enforce/compounds.production.js +1 -1
- package/dist/umd/enforce/schema.development.js +29 -94
- package/dist/umd/enforce/schema.production.js +1 -1
- package/dist/umd/parser.development.js +33 -14
- package/dist/umd/parser.production.js +1 -1
- package/dist/umd/promisify.development.js +24 -12
- package/dist/umd/promisify.production.js +1 -1
- package/dist/umd/vest.development.js +1327 -1298
- package/dist/umd/vest.production.js +1 -1
- package/package.json +144 -147
- package/testUtils/TVestMock.ts +7 -0
- package/testUtils/__tests__/partition.test.ts +4 -4
- package/testUtils/asVestTest.ts +9 -0
- package/testUtils/mockThrowError.ts +4 -2
- package/testUtils/suiteDummy.ts +4 -1
- package/testUtils/testDummy.ts +12 -10
- package/testUtils/testPromise.ts +3 -0
- package/types/classnames.d.ts +141 -12
- package/types/classnames.d.ts.map +1 -0
- package/types/enforce/compose.d.ts +2 -126
- package/types/enforce/compose.d.ts.map +1 -0
- package/types/enforce/compounds.d.ts +2 -136
- package/types/enforce/compounds.d.ts.map +1 -0
- package/types/enforce/schema.d.ts +2 -144
- package/types/enforce/schema.d.ts.map +1 -0
- package/types/parser.d.ts +147 -18
- package/types/parser.d.ts.map +1 -0
- package/types/promisify.d.ts +139 -43
- package/types/promisify.d.ts.map +1 -0
- package/types/vest.d.ts +257 -242
- package/types/vest.d.ts.map +1 -0
- package/CHANGELOG.md +0 -87
- package/testUtils/expandStateRef.ts +0 -8
- package/testUtils/runCreateRef.ts +0 -10
- package/testUtils/testObjects.ts +0 -6
- package/tsconfig.json +0 -8
|
@@ -1,444 +1,133 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var n4s = require('n4s');
|
|
4
|
+
var vestRuntime = require('vest-runtime');
|
|
6
5
|
var vestUtils = require('vest-utils');
|
|
7
|
-
var context
|
|
8
|
-
|
|
9
|
-
function shouldUseErrorAsMessage(message, error) {
|
|
10
|
-
// kind of cheating with this safe guard, but it does the job
|
|
11
|
-
return vestUtils.isUndefined(message) && vestUtils.isStringValue(error);
|
|
12
|
-
}
|
|
6
|
+
var context = require('context');
|
|
13
7
|
|
|
14
|
-
var
|
|
15
|
-
(function (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
IsolateTypes[IsolateTypes["SKIP_WHEN"] = 3] = "SKIP_WHEN";
|
|
20
|
-
IsolateTypes[IsolateTypes["OMIT_WHEN"] = 4] = "OMIT_WHEN";
|
|
21
|
-
IsolateTypes[IsolateTypes["GROUP"] = 5] = "GROUP";
|
|
22
|
-
})(IsolateTypes || (IsolateTypes = {}));
|
|
23
|
-
|
|
24
|
-
var Modes;
|
|
25
|
-
(function (Modes) {
|
|
26
|
-
Modes[Modes["ALL"] = 0] = "ALL";
|
|
27
|
-
Modes[Modes["EAGER"] = 1] = "EAGER";
|
|
28
|
-
})(Modes || (Modes = {}));
|
|
8
|
+
var OptionalFieldTypes;
|
|
9
|
+
(function (OptionalFieldTypes) {
|
|
10
|
+
OptionalFieldTypes[OptionalFieldTypes["CUSTOM_LOGIC"] = 0] = "CUSTOM_LOGIC";
|
|
11
|
+
OptionalFieldTypes[OptionalFieldTypes["AUTO"] = 1] = "AUTO";
|
|
12
|
+
})(OptionalFieldTypes || (OptionalFieldTypes = {}));
|
|
29
13
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
14
|
+
// @vx-allow use-use
|
|
15
|
+
function optional(optionals) {
|
|
16
|
+
const suiteRoot = vestRuntime.VestRuntime.useAvailableRoot();
|
|
17
|
+
// There are two types of optional field declarations:
|
|
18
|
+
// 1 AUTO: Vest will automatically determine whether the field should be omitted
|
|
19
|
+
// Based on the current run. Vest will ommit "auto" added fields without any
|
|
20
|
+
// configuration if their tests did not run at all in the suite.
|
|
21
|
+
//
|
|
22
|
+
// 2 Custom logic: Vest will determine whether they should fail based on the custom
|
|
23
|
+
// logic supplied by the user.
|
|
24
|
+
// AUTO case (field name)
|
|
25
|
+
if (vestUtils.isArray(optionals) || vestUtils.isStringValue(optionals)) {
|
|
26
|
+
vestUtils.asArray(optionals).forEach(optionalField => {
|
|
27
|
+
suiteRoot.setOptionalField(optionalField, () => ({
|
|
28
|
+
type: OptionalFieldTypes.AUTO,
|
|
29
|
+
applied: false,
|
|
30
|
+
rule: null,
|
|
31
|
+
}));
|
|
32
|
+
});
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
else {
|
|
35
|
+
// CUSTOM_LOGIC case (function or boolean)
|
|
36
|
+
for (const field in optionals) {
|
|
37
|
+
const value = optionals[field];
|
|
38
|
+
suiteRoot.setOptionalField(field, () => ({
|
|
39
|
+
type: OptionalFieldTypes.CUSTOM_LOGIC,
|
|
40
|
+
rule: value,
|
|
41
|
+
applied: value === true,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
49
44
|
}
|
|
50
45
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
current: {},
|
|
58
|
-
prev: {}
|
|
59
|
-
},
|
|
60
|
-
path: path,
|
|
61
|
-
type: type
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
var context = context$1.createCascade(function (ctxRef, parentContext) {
|
|
66
|
-
return parentContext
|
|
67
|
-
? null
|
|
68
|
-
: vestUtils.assign({
|
|
69
|
-
exclusion: {
|
|
70
|
-
tests: {},
|
|
71
|
-
groups: {}
|
|
72
|
-
},
|
|
73
|
-
inclusion: {},
|
|
74
|
-
isolate: generateIsolate(IsolateTypes.DEFAULT),
|
|
75
|
-
mode: [Modes.ALL]
|
|
76
|
-
}, ctxRef);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// STATE REF
|
|
80
|
-
function useStateRef() {
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
82
|
-
return context.useX().stateRef; // I should revisit this
|
|
83
|
-
}
|
|
84
|
-
// STATE KEYS
|
|
85
|
-
function useSuiteId() {
|
|
86
|
-
return useStateRef().suiteId()[0];
|
|
87
|
-
}
|
|
88
|
-
function useSuiteName() {
|
|
89
|
-
return useStateRef().suiteName()[0];
|
|
90
|
-
}
|
|
91
|
-
function useTestCallbacks() {
|
|
92
|
-
return useStateRef().testCallbacks();
|
|
93
|
-
}
|
|
94
|
-
// OPTIONAL FIELDS
|
|
95
|
-
function useOptionalFields() {
|
|
96
|
-
return useStateRef().optionalFields();
|
|
97
|
-
}
|
|
98
|
-
function useSetOptionalField(fieldName, setter) {
|
|
99
|
-
var _a = useOptionalFields(), setOptionalFields = _a[1];
|
|
100
|
-
setOptionalFields(function (prev) {
|
|
101
|
-
var _a;
|
|
102
|
-
return vestUtils.assign(prev, (_a = {},
|
|
103
|
-
_a[fieldName] = vestUtils.assign({}, prev[fieldName], setter(prev[fieldName])),
|
|
104
|
-
_a));
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
function useOptionalField(fieldName) {
|
|
108
|
-
var _a;
|
|
109
|
-
var optionalFields = useOptionalFields()[0];
|
|
110
|
-
return (_a = optionalFields[fieldName]) !== null && _a !== void 0 ? _a : {};
|
|
111
|
-
}
|
|
112
|
-
function useTestObjects() {
|
|
113
|
-
return useStateRef().testObjects();
|
|
114
|
-
}
|
|
115
|
-
// STATE ACTIONS
|
|
116
|
-
function useRefreshTestObjects() {
|
|
117
|
-
useSetTests(function (tests) { return tests; });
|
|
118
|
-
}
|
|
119
|
-
function useSetTests(handler) {
|
|
120
|
-
var _a = useTestObjects(), testObjects = _a[1];
|
|
121
|
-
testObjects(function (_a) {
|
|
122
|
-
var current = _a.current, prev = _a.prev;
|
|
123
|
-
return ({
|
|
124
|
-
prev: prev,
|
|
125
|
-
current: vestUtils.asArray(handler(current))
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
// Derived state
|
|
130
|
-
function useAllIncomplete() {
|
|
131
|
-
return useTestsFlat().filter(function (test) { return test.isPending(); });
|
|
132
|
-
}
|
|
133
|
-
var flatCache = vestUtils.cache();
|
|
134
|
-
function useTestsFlat() {
|
|
135
|
-
var current = useTestObjects()[0].current;
|
|
136
|
-
return flatCache([current], function () { return vestUtils.nestedArray.flatten(current); });
|
|
137
|
-
}
|
|
138
|
-
function useEachTestObject(handler) {
|
|
139
|
-
var testObjects = useTestsFlat();
|
|
140
|
-
testObjects.forEach(handler);
|
|
46
|
+
function useIsOptionalFiedApplied(fieldName) {
|
|
47
|
+
var _a, _b, _c;
|
|
48
|
+
if (!fieldName) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return ((_c = (_b = (_a = vestRuntime.VestRuntime.useAvailableRoot()) === null || _a === void 0 ? void 0 : _a.getOptionalField(fieldName)) === null || _b === void 0 ? void 0 : _b.applied) !== null && _c !== void 0 ? _c : false);
|
|
141
52
|
}
|
|
142
53
|
|
|
143
|
-
var
|
|
144
|
-
(function (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.fieldName = fieldName;
|
|
156
|
-
this.testFn = testFn;
|
|
157
|
-
if (groupName) {
|
|
158
|
-
this.groupName = groupName;
|
|
159
|
-
}
|
|
160
|
-
if (message) {
|
|
161
|
-
this.message = message;
|
|
162
|
-
}
|
|
163
|
-
if (key) {
|
|
164
|
-
this.key = key;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
VestTest.prototype.run = function () {
|
|
168
|
-
var result;
|
|
169
|
-
try {
|
|
170
|
-
result = this.testFn();
|
|
171
|
-
}
|
|
172
|
-
catch (error) {
|
|
173
|
-
if (shouldUseErrorAsMessage(this.message, error)) {
|
|
174
|
-
this.message = error;
|
|
175
|
-
}
|
|
176
|
-
result = false;
|
|
177
|
-
}
|
|
178
|
-
if (result === false) {
|
|
179
|
-
this.fail();
|
|
180
|
-
}
|
|
181
|
-
return result;
|
|
182
|
-
};
|
|
183
|
-
VestTest.prototype.setStatus = function (status) {
|
|
184
|
-
if (this.isFinalStatus() && status !== STATUS_OMITTED) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
this.status = status;
|
|
188
|
-
};
|
|
189
|
-
VestTest.prototype.warns = function () {
|
|
190
|
-
return this.severity === TestSeverity.Warning;
|
|
191
|
-
};
|
|
192
|
-
VestTest.prototype.setPending = function () {
|
|
193
|
-
this.setStatus(STATUS_PENDING);
|
|
194
|
-
};
|
|
195
|
-
VestTest.prototype.fail = function () {
|
|
196
|
-
this.setStatus(this.warns() ? STATUS_WARNING : STATUS_FAILED);
|
|
197
|
-
};
|
|
198
|
-
VestTest.prototype.done = function () {
|
|
199
|
-
if (this.isFinalStatus()) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
this.setStatus(STATUS_PASSING);
|
|
203
|
-
};
|
|
204
|
-
VestTest.prototype.warn = function () {
|
|
205
|
-
this.severity = TestSeverity.Warning;
|
|
206
|
-
};
|
|
207
|
-
VestTest.prototype.isFinalStatus = function () {
|
|
208
|
-
return this.hasFailures() || this.isCanceled() || this.isPassing();
|
|
209
|
-
};
|
|
210
|
-
VestTest.prototype.skip = function (force) {
|
|
211
|
-
if (this.isPending() && !force) {
|
|
212
|
-
// Without this condition, the test will be marked as skipped even if it is pending.
|
|
213
|
-
// This means that it will not be counted in "allIncomplete" and its done callbacks
|
|
214
|
-
// will not be called, or will be called prematurely.
|
|
215
|
-
// What this mostly say is that when we have a pending test for one field, and we then
|
|
216
|
-
// start typing in a different field - the pending test will be canceled, which
|
|
217
|
-
// is usually an unwanted behavior.
|
|
218
|
-
// The only scenario in which we DO want to cancel the async test regardless
|
|
219
|
-
// is when we specifically skip a test with `skipWhen`, which is handled by the
|
|
220
|
-
// "force" boolean flag.
|
|
221
|
-
// I am not a fan of this flag, but it gets the job done.
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
this.setStatus(STATUS_SKIPPED);
|
|
225
|
-
};
|
|
226
|
-
VestTest.prototype.cancel = function () {
|
|
227
|
-
this.setStatus(STATUS_CANCELED);
|
|
228
|
-
useRefreshTestObjects();
|
|
229
|
-
};
|
|
230
|
-
VestTest.prototype.reset = function () {
|
|
231
|
-
this.status = STATUS_UNTESTED;
|
|
232
|
-
useRefreshTestObjects();
|
|
233
|
-
};
|
|
234
|
-
VestTest.prototype.omit = function () {
|
|
235
|
-
this.setStatus(STATUS_OMITTED);
|
|
236
|
-
};
|
|
237
|
-
VestTest.prototype.valueOf = function () {
|
|
238
|
-
return !this.isFailing();
|
|
239
|
-
};
|
|
240
|
-
VestTest.prototype.isPending = function () {
|
|
241
|
-
return this.statusEquals(STATUS_PENDING);
|
|
242
|
-
};
|
|
243
|
-
VestTest.prototype.isOmitted = function () {
|
|
244
|
-
return this.statusEquals(STATUS_OMITTED);
|
|
245
|
-
};
|
|
246
|
-
VestTest.prototype.isUntested = function () {
|
|
247
|
-
return this.statusEquals(STATUS_UNTESTED);
|
|
248
|
-
};
|
|
249
|
-
VestTest.prototype.isFailing = function () {
|
|
250
|
-
return this.statusEquals(STATUS_FAILED);
|
|
251
|
-
};
|
|
252
|
-
VestTest.prototype.isCanceled = function () {
|
|
253
|
-
return this.statusEquals(STATUS_CANCELED);
|
|
254
|
-
};
|
|
255
|
-
VestTest.prototype.isSkipped = function () {
|
|
256
|
-
return this.statusEquals(STATUS_SKIPPED);
|
|
257
|
-
};
|
|
258
|
-
VestTest.prototype.isPassing = function () {
|
|
259
|
-
return this.statusEquals(STATUS_PASSING);
|
|
260
|
-
};
|
|
261
|
-
VestTest.prototype.isWarning = function () {
|
|
262
|
-
return this.statusEquals(STATUS_WARNING);
|
|
263
|
-
};
|
|
264
|
-
VestTest.prototype.hasFailures = function () {
|
|
265
|
-
return this.isFailing() || this.isWarning();
|
|
266
|
-
};
|
|
267
|
-
VestTest.prototype.isNonActionable = function () {
|
|
268
|
-
return this.isSkipped() || this.isOmitted() || this.isCanceled();
|
|
269
|
-
};
|
|
270
|
-
VestTest.prototype.isTested = function () {
|
|
271
|
-
return this.hasFailures() || this.isPassing();
|
|
272
|
-
};
|
|
273
|
-
VestTest.prototype.awaitsResolution = function () {
|
|
274
|
-
// Is the test in a state where it can still be run, or complete running
|
|
275
|
-
// and its final status is indeterminate?
|
|
276
|
-
return this.isSkipped() || this.isUntested() || this.isPending();
|
|
277
|
-
};
|
|
278
|
-
VestTest.prototype.statusEquals = function (status) {
|
|
279
|
-
return this.status === status;
|
|
280
|
-
};
|
|
281
|
-
return VestTest;
|
|
282
|
-
}());
|
|
283
|
-
var STATUS_UNTESTED = 'UNTESTED';
|
|
284
|
-
var STATUS_SKIPPED = 'SKIPPED';
|
|
285
|
-
var STATUS_FAILED = 'FAILED';
|
|
286
|
-
var STATUS_WARNING = 'WARNING';
|
|
287
|
-
var STATUS_PASSING = 'PASSING';
|
|
288
|
-
var STATUS_PENDING = 'PENDING';
|
|
289
|
-
var STATUS_CANCELED = 'CANCELED';
|
|
290
|
-
var STATUS_OMITTED = 'OMITTED';
|
|
54
|
+
var Events;
|
|
55
|
+
(function (Events) {
|
|
56
|
+
Events["TEST_RUN_STARTED"] = "test_run_started";
|
|
57
|
+
Events["TEST_COMPLETED"] = "test_completed";
|
|
58
|
+
Events["ALL_RUNNING_TESTS_FINISHED"] = "all_running_tests_finished";
|
|
59
|
+
Events["REMOVE_FIELD"] = "remove_field";
|
|
60
|
+
Events["RESET_FIELD"] = "reset_field";
|
|
61
|
+
Events["RESET_SUITE"] = "reset_suite";
|
|
62
|
+
Events["SUITE_RUN_STARTED"] = "suite_run_started";
|
|
63
|
+
Events["SUITE_CALLBACK_RUN_FINISHED"] = "SUITE_CALLBACK_RUN_FINISHED";
|
|
64
|
+
Events["DONE_TEST_OMISSION_PASS"] = "DONE_TEST_OMISSION_PASS";
|
|
65
|
+
})(Events || (Events = {}));
|
|
291
66
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Registers a new key in the state, takes the initial value (may be a function that returns the initial value), returns a function.
|
|
304
|
-
*
|
|
305
|
-
* @example
|
|
306
|
-
*
|
|
307
|
-
* const useColor = state.registerStateKey("blue");
|
|
308
|
-
*
|
|
309
|
-
* let [color, setColor] = useColor(); // -> ["blue", Function]
|
|
310
|
-
*
|
|
311
|
-
* setColor("green");
|
|
312
|
-
*
|
|
313
|
-
* useColor()[0]; -> "green"
|
|
314
|
-
*/
|
|
315
|
-
function registerStateKey(initialState, onUpdate) {
|
|
316
|
-
var key = registrations.length;
|
|
317
|
-
registrations.push([initialState, onUpdate]);
|
|
318
|
-
return initKey(key, initialState);
|
|
319
|
-
}
|
|
320
|
-
function reset() {
|
|
321
|
-
var prev = current();
|
|
322
|
-
state.references = [];
|
|
323
|
-
registrations.forEach(function (_a, index) {
|
|
324
|
-
var initialValue = _a[0];
|
|
325
|
-
return initKey(index, initialValue, prev[index]);
|
|
67
|
+
class IsolateSuite extends vestRuntime.Isolate {
|
|
68
|
+
constructor() {
|
|
69
|
+
super(...arguments);
|
|
70
|
+
this.optional = {};
|
|
71
|
+
}
|
|
72
|
+
setOptionalField(fieldName, setter) {
|
|
73
|
+
const current = this.optional;
|
|
74
|
+
const currentField = current[fieldName];
|
|
75
|
+
Object.assign(current, {
|
|
76
|
+
[fieldName]: Object.assign({}, currentField, setter(currentField)),
|
|
326
77
|
});
|
|
327
78
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return function useStateKey() {
|
|
332
|
-
return [
|
|
333
|
-
current()[key],
|
|
334
|
-
function (nextState) {
|
|
335
|
-
return set(key, vestUtils.optionalFunctionValue(nextState, current()[key]));
|
|
336
|
-
},
|
|
337
|
-
];
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
function current() {
|
|
341
|
-
return state.references;
|
|
79
|
+
getOptionalField(fieldName) {
|
|
80
|
+
var _a;
|
|
81
|
+
return (_a = this.optional[fieldName]) !== null && _a !== void 0 ? _a : {};
|
|
342
82
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
state.references[index] = value;
|
|
346
|
-
var _a = registrations[index], onUpdate = _a[1];
|
|
347
|
-
if (vestUtils.isFunction(onUpdate)) {
|
|
348
|
-
onUpdate(value, prevValue);
|
|
349
|
-
}
|
|
350
|
-
if (vestUtils.isFunction(onStateChange)) {
|
|
351
|
-
onStateChange();
|
|
352
|
-
}
|
|
83
|
+
getOptionalFields() {
|
|
84
|
+
return this.optional;
|
|
353
85
|
}
|
|
354
86
|
}
|
|
355
87
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
doneCallbacks: []
|
|
365
|
-
}); }),
|
|
366
|
-
testObjects: state.registerStateKey(function (prev) {
|
|
367
|
-
return {
|
|
368
|
-
prev: prev ? prev.current : [],
|
|
369
|
-
current: []
|
|
370
|
-
};
|
|
371
|
-
})
|
|
88
|
+
const suiteResultCache = vestUtils.cache();
|
|
89
|
+
function useCreateVestState({ suiteName, } = {}) {
|
|
90
|
+
const stateRef = {
|
|
91
|
+
doneCallbacks: vestUtils.tinyState.createTinyState(() => []),
|
|
92
|
+
fieldCallbacks: vestUtils.tinyState.createTinyState(() => ({})),
|
|
93
|
+
suiteId: vestUtils.seq(),
|
|
94
|
+
suiteName,
|
|
95
|
+
suiteResultCache,
|
|
372
96
|
};
|
|
97
|
+
return vestRuntime.VestRuntime.createRef(stateRef);
|
|
373
98
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
* @returns {Isolate} The current isolate layer
|
|
377
|
-
*/
|
|
378
|
-
function useIsolate() {
|
|
379
|
-
return context.useX().isolate;
|
|
99
|
+
function useX() {
|
|
100
|
+
return vestRuntime.VestRuntime.useXAppData();
|
|
380
101
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
*/
|
|
384
|
-
function useCurrentPath() {
|
|
385
|
-
var isolate = useIsolate();
|
|
386
|
-
return isolate.path.concat(isolate.cursor.current());
|
|
102
|
+
function useDoneCallbacks() {
|
|
103
|
+
return useX().doneCallbacks();
|
|
387
104
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
*/
|
|
391
|
-
function useCursor() {
|
|
392
|
-
return useIsolate().cursor;
|
|
105
|
+
function useFieldCallbacks() {
|
|
106
|
+
return useX().fieldCallbacks();
|
|
393
107
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
var prev = useTestObjects()[0].prev;
|
|
397
|
-
return vestUtils.asArray(vestUtils.nestedArray.getCurrent(prev, useCurrentPath())).reduce(function (prevKeys, testObject) {
|
|
398
|
-
if (!(testObject instanceof VestTest)) {
|
|
399
|
-
return prevKeys;
|
|
400
|
-
}
|
|
401
|
-
if (vestUtils.isNullish(testObject.key)) {
|
|
402
|
-
return prevKeys;
|
|
403
|
-
}
|
|
404
|
-
prevKeys[testObject.key] = testObject;
|
|
405
|
-
return prevKeys;
|
|
406
|
-
}, {});
|
|
108
|
+
function useSuiteName() {
|
|
109
|
+
return useX().suiteName;
|
|
407
110
|
}
|
|
408
|
-
function
|
|
409
|
-
|
|
410
|
-
return prev[key];
|
|
111
|
+
function useSuiteId() {
|
|
112
|
+
return useX().suiteId;
|
|
411
113
|
}
|
|
412
|
-
function
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
current[key] = testObject;
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
vestUtils.deferThrow("Encountered the same test key \"".concat(key, "\" twice. This may lead to tests overriding each other's results, or to tests being unexpectedly omitted."));
|
|
419
|
-
}
|
|
114
|
+
function useSuiteResultCache(action) {
|
|
115
|
+
const suiteResultCache = useX().suiteResultCache;
|
|
116
|
+
return suiteResultCache([useSuiteId()], action);
|
|
420
117
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
vestUtils.invariant(vestUtils.isFunction(callback));
|
|
425
|
-
// Generate a new Isolate layer, with its own cursor
|
|
426
|
-
var isolate = generateIsolate(type, useCurrentPath());
|
|
427
|
-
var output = context.run({ isolate: isolate }, function () {
|
|
428
|
-
isolate.keys.prev = usePrevKeys();
|
|
429
|
-
useSetTests(function (tests) { return vestUtils.nestedArray.setValueAtPath(tests, isolate.path, []); });
|
|
430
|
-
var res = callback();
|
|
431
|
-
return res;
|
|
432
|
-
});
|
|
433
|
-
// Move the parent cursor forward once we're done
|
|
434
|
-
useCursor().next();
|
|
435
|
-
return output;
|
|
118
|
+
function useExpireSuiteResultCache() {
|
|
119
|
+
const suiteResultCache = useX().suiteResultCache;
|
|
120
|
+
suiteResultCache.invalidate([useSuiteId()]);
|
|
436
121
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
122
|
+
function useResetCallbacks() {
|
|
123
|
+
const [, , resetDoneCallbacks] = useDoneCallbacks();
|
|
124
|
+
const [, , resetFieldCallbacks] = useFieldCallbacks();
|
|
125
|
+
resetDoneCallbacks();
|
|
126
|
+
resetFieldCallbacks();
|
|
127
|
+
}
|
|
128
|
+
function useResetSuite() {
|
|
129
|
+
useResetCallbacks();
|
|
130
|
+
vestRuntime.VestRuntime.reset();
|
|
442
131
|
}
|
|
443
132
|
|
|
444
133
|
var Severity;
|
|
@@ -456,195 +145,159 @@ function countKeyBySeverity(severity) {
|
|
|
456
145
|
? SeverityCount.ERROR_COUNT
|
|
457
146
|
: SeverityCount.WARN_COUNT;
|
|
458
147
|
}
|
|
148
|
+
var TestSeverity;
|
|
149
|
+
(function (TestSeverity) {
|
|
150
|
+
TestSeverity["Error"] = "error";
|
|
151
|
+
TestSeverity["Warning"] = "warning";
|
|
152
|
+
})(TestSeverity || (TestSeverity = {}));
|
|
153
|
+
|
|
154
|
+
var ErrorStrings;
|
|
155
|
+
(function (ErrorStrings) {
|
|
156
|
+
ErrorStrings["HOOK_CALLED_OUTSIDE"] = "hook called outside of a running suite.";
|
|
157
|
+
ErrorStrings["EXPECTED_VEST_TEST"] = "Expected value to be an instance of IsolateTest";
|
|
158
|
+
ErrorStrings["FIELD_NAME_REQUIRED"] = "Field name must be passed";
|
|
159
|
+
ErrorStrings["SUITE_MUST_BE_INITIALIZED_WITH_FUNCTION"] = "Suite must be initialized with a function";
|
|
160
|
+
ErrorStrings["PROMISIFY_REQUIRE_FUNCTION"] = "Vest.Promisify must be called with a function";
|
|
161
|
+
ErrorStrings["PARSER_EXPECT_RESULT_OBJECT"] = "Vest parser: expected argument at position 0 to be Vest's result object.";
|
|
162
|
+
ErrorStrings["WARN_MUST_BE_CALLED_FROM_TEST"] = "Warn must be called from within the body of a test function";
|
|
163
|
+
ErrorStrings["EACH_CALLBACK_MUST_BE_A_FUNCTION"] = "Each must be called with a function";
|
|
164
|
+
ErrorStrings["INVALID_PARAM_PASSED_TO_FUNCTION"] = "Incompatible params passed to {fn_name} function. \"{param}\" must be of type {expected}";
|
|
165
|
+
ErrorStrings["TESTS_CALLED_IN_DIFFERENT_ORDER"] = "Vest Critical Error: Tests called in different order than previous run.\n expected: {fieldName}\n received: {prevName}\n This can happen on one of two reasons:\n 1. You're using if/else statements to conditionally select tests. Instead, use \"skipWhen\".\n 2. You are iterating over a list of tests, and their order changed. Use \"each\" and a custom key prop so that Vest retains their state.";
|
|
166
|
+
ErrorStrings["UNEXPECTED_TEST_REGISTRATION_ERROR"] = "Unexpected error encountered during test registration.\n Please report this issue to Vest's Github repository.\n Test Object: {testObject}.\n Error: {error}.";
|
|
167
|
+
ErrorStrings["UNEXPECTED_TEST_RUN_ERROR"] = "Unexpected error encountered during test run. Please report this issue to Vest's Github repository.\n Test Object: {testObject}.";
|
|
168
|
+
})(ErrorStrings || (ErrorStrings = {}));
|
|
459
169
|
|
|
460
|
-
function nonMatchingFieldName(
|
|
461
|
-
return !!fieldName && !matchingFieldName(
|
|
170
|
+
function nonMatchingFieldName(WithFieldName, fieldName) {
|
|
171
|
+
return !!fieldName && !matchingFieldName(WithFieldName, fieldName);
|
|
462
172
|
}
|
|
463
|
-
function matchingFieldName(
|
|
464
|
-
return !!(fieldName &&
|
|
173
|
+
function matchingFieldName(WithFieldName, fieldName) {
|
|
174
|
+
return !!(fieldName && WithFieldName.fieldName === fieldName);
|
|
465
175
|
}
|
|
466
176
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
177
|
+
function isSameProfileTest(testObject1, testObject2) {
|
|
178
|
+
return (matchingFieldName(testObject1, testObject2.fieldName) &&
|
|
179
|
+
testObject1.groupName === testObject2.groupName &&
|
|
180
|
+
testObject1.key === testObject2.key);
|
|
470
181
|
}
|
|
471
182
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
183
|
+
function cancelOverriddenPendingTest(prevRunTestObject, currentRunTestObject) {
|
|
184
|
+
if (currentRunTestObject !== prevRunTestObject &&
|
|
185
|
+
isSameProfileTest(prevRunTestObject, currentRunTestObject) &&
|
|
186
|
+
prevRunTestObject.isPending()) {
|
|
187
|
+
prevRunTestObject.cancel();
|
|
188
|
+
}
|
|
477
189
|
}
|
|
478
190
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
function hasFailuresByTestObjects(severityKey, fieldName) {
|
|
487
|
-
var testObjects = useTestsFlat();
|
|
488
|
-
return testObjects.some(function (testObject) {
|
|
489
|
-
return hasFailuresByTestObject(testObject, severityKey, fieldName);
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
function hasGroupFailuresByTestObjects(severityKey, groupName, fieldName) {
|
|
493
|
-
var testObjects = useTestsFlat();
|
|
494
|
-
return testObjects.some(function (testObject) {
|
|
495
|
-
if (nonMatchingGroupName(testObject, groupName)) {
|
|
496
|
-
return false;
|
|
497
|
-
}
|
|
498
|
-
return hasFailuresByTestObject(testObject, severityKey, fieldName);
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Determines whether a certain test profile has failures.
|
|
503
|
-
*/
|
|
504
|
-
function hasFailuresByTestObject(testObject, severityKey, fieldName) {
|
|
505
|
-
if (!testObject.hasFailures()) {
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
509
|
-
return false;
|
|
191
|
+
var _a, _b;
|
|
192
|
+
class SummaryBase {
|
|
193
|
+
constructor() {
|
|
194
|
+
this.errorCount = 0;
|
|
195
|
+
this.warnCount = 0;
|
|
196
|
+
this.testCount = 0;
|
|
510
197
|
}
|
|
511
|
-
|
|
512
|
-
|
|
198
|
+
}
|
|
199
|
+
class SuiteSummary extends SummaryBase {
|
|
200
|
+
constructor() {
|
|
201
|
+
super(...arguments);
|
|
202
|
+
this[_a] = [];
|
|
203
|
+
this[_b] = [];
|
|
204
|
+
this.groups = {};
|
|
205
|
+
this.tests = {};
|
|
206
|
+
this.valid = false;
|
|
513
207
|
}
|
|
514
|
-
return true;
|
|
515
208
|
}
|
|
209
|
+
_a = Severity.ERRORS, _b = Severity.WARNINGS;
|
|
516
210
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
* optional('field_name');
|
|
523
|
-
*
|
|
524
|
-
* optional({
|
|
525
|
-
* username: () => allowUsernameEmpty,
|
|
526
|
-
* });
|
|
527
|
-
*/
|
|
528
|
-
function optional(optionals) {
|
|
529
|
-
// There are two types of optional field declarations:
|
|
530
|
-
// 1. Delayed: A string, which is the name of the field to be optional.
|
|
531
|
-
// We will only determine whether to omit the test after the suite is done running
|
|
532
|
-
//
|
|
533
|
-
// 2. Immediate: Either a boolean or a function, which is used to determine
|
|
534
|
-
// if the field should be optional.
|
|
535
|
-
// Delayed case (field name)
|
|
536
|
-
if (vestUtils.isArray(optionals) || vestUtils.isStringValue(optionals)) {
|
|
537
|
-
vestUtils.asArray(optionals).forEach(function (optionalField) {
|
|
538
|
-
useSetOptionalField(optionalField, function () { return ({
|
|
539
|
-
type: OptionalFieldTypes.Delayed,
|
|
540
|
-
applied: false,
|
|
541
|
-
rule: null
|
|
542
|
-
}); });
|
|
543
|
-
});
|
|
211
|
+
class SummaryFailure {
|
|
212
|
+
constructor(fieldName, message, groupName) {
|
|
213
|
+
this.fieldName = fieldName;
|
|
214
|
+
this.message = message;
|
|
215
|
+
this.groupName = groupName;
|
|
544
216
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
var value = optionals[field];
|
|
548
|
-
useSetOptionalField(field, function () { return ({
|
|
549
|
-
type: OptionalFieldTypes.Immediate,
|
|
550
|
-
rule: value,
|
|
551
|
-
applied: vestUtils.optionalFunctionValue(value)
|
|
552
|
-
}); });
|
|
553
|
-
};
|
|
554
|
-
// Immediately case (function or boolean)
|
|
555
|
-
for (var field in optionals) {
|
|
556
|
-
_loop_1(field);
|
|
557
|
-
}
|
|
217
|
+
static fromTestObject(testObject) {
|
|
218
|
+
return new SummaryFailure(testObject.fieldName, testObject.message, testObject.groupName);
|
|
558
219
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (!fieldName) {
|
|
562
|
-
return false;
|
|
220
|
+
toString() {
|
|
221
|
+
return this.message || '';
|
|
563
222
|
}
|
|
564
|
-
return useOptionalField(fieldName).applied;
|
|
565
223
|
}
|
|
566
|
-
var OptionalFieldTypes;
|
|
567
|
-
(function (OptionalFieldTypes) {
|
|
568
|
-
OptionalFieldTypes[OptionalFieldTypes["Immediate"] = 0] = "Immediate";
|
|
569
|
-
OptionalFieldTypes[OptionalFieldTypes["Delayed"] = 1] = "Delayed";
|
|
570
|
-
})(OptionalFieldTypes || (OptionalFieldTypes = {}));
|
|
571
224
|
|
|
572
|
-
|
|
573
|
-
function
|
|
225
|
+
const nonMatchingGroupName = vestUtils.bindNot(matchingGroupName);
|
|
226
|
+
function matchingGroupName(testObject, groupName) {
|
|
227
|
+
return testObject.groupName === groupName;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function useShouldAddValidProperty(fieldName) {
|
|
574
231
|
// Is the field optional, and the optional condition is applied
|
|
575
|
-
if (
|
|
232
|
+
if (useIsOptionalFiedApplied(fieldName)) {
|
|
576
233
|
return true;
|
|
577
234
|
}
|
|
578
|
-
var testObjects = useTestsFlat();
|
|
579
235
|
// Are there no tests?
|
|
580
|
-
if (
|
|
236
|
+
if (TestWalker.hasNoTests()) {
|
|
581
237
|
return false;
|
|
582
238
|
}
|
|
583
|
-
// Does the field have any tests with errors?
|
|
239
|
+
// // Does the field have any tests with errors?
|
|
584
240
|
if (hasErrorsByTestObjects(fieldName)) {
|
|
585
241
|
return false;
|
|
586
242
|
}
|
|
587
243
|
// Does the given field have any pending tests that are not optional?
|
|
588
|
-
if (
|
|
244
|
+
if (useHasNonOptionalIncomplete(fieldName)) {
|
|
589
245
|
return false;
|
|
590
246
|
}
|
|
591
247
|
// Does the field have no missing tests?
|
|
592
|
-
return
|
|
248
|
+
return useNoMissingTests(fieldName);
|
|
593
249
|
}
|
|
594
|
-
function
|
|
595
|
-
if (
|
|
250
|
+
function useShouldAddValidPropertyInGroup(groupName, fieldName) {
|
|
251
|
+
if (useIsOptionalFiedApplied(fieldName)) {
|
|
596
252
|
return true;
|
|
597
253
|
}
|
|
598
254
|
if (hasGroupFailuresByTestObjects(Severity.ERRORS, groupName, fieldName)) {
|
|
599
255
|
return false;
|
|
600
256
|
}
|
|
601
257
|
// Do the given group/field have any pending tests that are not optional?
|
|
602
|
-
if (
|
|
258
|
+
if (useHasNonOptionalIncompleteByGroup(groupName, fieldName)) {
|
|
603
259
|
return false;
|
|
604
260
|
}
|
|
605
|
-
return
|
|
261
|
+
return useNoMissingTestsByGroup(groupName, fieldName);
|
|
606
262
|
}
|
|
607
263
|
// Does the given field have any pending tests that are not optional?
|
|
608
|
-
function
|
|
609
|
-
return
|
|
610
|
-
|
|
611
|
-
|
|
264
|
+
function useHasNonOptionalIncomplete(fieldName) {
|
|
265
|
+
return TestWalker.someIncompleteTests(testObject => {
|
|
266
|
+
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
return !useIsOptionalFiedApplied(fieldName);
|
|
270
|
+
});
|
|
612
271
|
}
|
|
613
272
|
// Do the given group/field have any pending tests that are not optional?
|
|
614
|
-
function
|
|
615
|
-
return
|
|
273
|
+
function useHasNonOptionalIncompleteByGroup(groupName, fieldName) {
|
|
274
|
+
return TestWalker.someIncompleteTests(testObject => {
|
|
616
275
|
if (nonMatchingGroupName(testObject, groupName)) {
|
|
617
276
|
return false;
|
|
618
277
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
return optionalFiedIsApplied(fieldName);
|
|
278
|
+
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
return !useIsOptionalFiedApplied(fieldName);
|
|
282
|
+
});
|
|
627
283
|
}
|
|
628
284
|
// Did all of the tests for the provided field run/omit?
|
|
629
285
|
// This makes sure that the fields are not skipped or pending.
|
|
630
|
-
function
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return noMissingTestsLogic(testObject, fieldName);
|
|
286
|
+
function useNoMissingTests(fieldName) {
|
|
287
|
+
return TestWalker.everyTest(testObject => {
|
|
288
|
+
return useNoMissingTestsLogic(testObject, fieldName);
|
|
634
289
|
});
|
|
635
290
|
}
|
|
636
291
|
// Does the group have no missing tests?
|
|
637
|
-
function
|
|
638
|
-
|
|
639
|
-
return testObjects.every(function (testObject) {
|
|
292
|
+
function useNoMissingTestsByGroup(groupName, fieldName) {
|
|
293
|
+
return TestWalker.everyTest(testObject => {
|
|
640
294
|
if (nonMatchingGroupName(testObject, groupName)) {
|
|
641
295
|
return true;
|
|
642
296
|
}
|
|
643
|
-
return
|
|
297
|
+
return useNoMissingTestsLogic(testObject, fieldName);
|
|
644
298
|
});
|
|
645
299
|
}
|
|
646
|
-
|
|
647
|
-
function noMissingTestsLogic(testObject, fieldName) {
|
|
300
|
+
function useNoMissingTestsLogic(testObject, fieldName) {
|
|
648
301
|
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
649
302
|
return true;
|
|
650
303
|
}
|
|
@@ -657,102 +310,108 @@ function noMissingTestsLogic(testObject, fieldName) {
|
|
|
657
310
|
* or if it is marked as optional, even if the optional check did not apply yet -
|
|
658
311
|
* but the test did not reach its final state.
|
|
659
312
|
*/
|
|
660
|
-
return (
|
|
313
|
+
return (testObject.isOmitted() ||
|
|
661
314
|
testObject.isTested() ||
|
|
662
|
-
testObject
|
|
315
|
+
useOptionalTestAwaitsResolution(testObject));
|
|
663
316
|
}
|
|
664
|
-
function
|
|
317
|
+
function useOptionalTestAwaitsResolution(testObject) {
|
|
665
318
|
// Does the test belong to an optional field,
|
|
666
319
|
// and the test itself is still in an indeterminate state?
|
|
667
|
-
|
|
668
|
-
|
|
320
|
+
var _a;
|
|
321
|
+
return (((_a = vestRuntime.VestRuntime.useAvailableRoot()) === null || _a === void 0 ? void 0 : _a.getOptionalField(testObject.fieldName).type) === OptionalFieldTypes.AUTO && testObject.awaitsResolution());
|
|
669
322
|
}
|
|
670
323
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
tests: {},
|
|
679
|
-
valid: false
|
|
324
|
+
function useProduceSuiteSummary() {
|
|
325
|
+
const summary = new SuiteSummary();
|
|
326
|
+
TestWalker.walkTests(testObject => {
|
|
327
|
+
summary.tests = useAppendToTest(summary.tests, testObject);
|
|
328
|
+
summary.groups = useAppendToGroup(summary.groups, testObject);
|
|
329
|
+
summary.errors = appendFailures(Severity.ERRORS, summary.errors, testObject);
|
|
330
|
+
summary.warnings = appendFailures(Severity.WARNINGS, summary.warnings, testObject);
|
|
680
331
|
});
|
|
681
|
-
|
|
682
|
-
appendToTest(summary.tests, testObject);
|
|
683
|
-
appendToGroup(summary.groups, testObject);
|
|
684
|
-
return summary;
|
|
685
|
-
}, summary);
|
|
686
|
-
summary.valid = shouldAddValidProperty();
|
|
332
|
+
summary.valid = useShouldAddValidProperty();
|
|
687
333
|
return countFailures(summary);
|
|
688
334
|
}
|
|
689
|
-
function
|
|
690
|
-
|
|
335
|
+
function appendFailures(key, failures, testObject) {
|
|
336
|
+
if (testObject.isOmitted()) {
|
|
337
|
+
return failures;
|
|
338
|
+
}
|
|
339
|
+
const shouldAppend = key === Severity.WARNINGS ? testObject.isWarning() : testObject.isFailing();
|
|
340
|
+
if (shouldAppend) {
|
|
341
|
+
return failures.concat(SummaryFailure.fromTestObject(testObject));
|
|
342
|
+
}
|
|
343
|
+
return failures;
|
|
344
|
+
}
|
|
345
|
+
function useAppendToTest(tests, testObject) {
|
|
346
|
+
const { fieldName } = testObject;
|
|
347
|
+
const newTests = Object.assign({}, tests);
|
|
348
|
+
newTests[fieldName] = appendTestObject(newTests[fieldName], testObject);
|
|
691
349
|
// If `valid` is false to begin with, keep it that way. Otherwise, assess.
|
|
692
|
-
|
|
693
|
-
|
|
350
|
+
newTests[fieldName].valid =
|
|
351
|
+
newTests[fieldName].valid === false
|
|
694
352
|
? false
|
|
695
|
-
:
|
|
353
|
+
: useShouldAddValidProperty(fieldName);
|
|
354
|
+
return newTests;
|
|
696
355
|
}
|
|
697
356
|
/**
|
|
698
357
|
* Appends to a group object if within a group
|
|
699
358
|
*/
|
|
700
|
-
function
|
|
701
|
-
|
|
359
|
+
function useAppendToGroup(groups, testObject) {
|
|
360
|
+
const { groupName, fieldName } = testObject;
|
|
702
361
|
if (!groupName) {
|
|
703
|
-
return;
|
|
362
|
+
return groups;
|
|
704
363
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
364
|
+
const newGroups = Object.assign({}, groups);
|
|
365
|
+
newGroups[groupName] = newGroups[groupName] || {};
|
|
366
|
+
newGroups[groupName][fieldName] = appendTestObject(newGroups[groupName][fieldName], testObject);
|
|
367
|
+
newGroups[groupName][fieldName].valid =
|
|
368
|
+
newGroups[groupName][fieldName].valid === false
|
|
709
369
|
? false
|
|
710
|
-
:
|
|
370
|
+
: useShouldAddValidPropertyInGroup(groupName, fieldName);
|
|
371
|
+
return newGroups;
|
|
711
372
|
}
|
|
712
373
|
/**
|
|
713
374
|
* Counts the failed tests and adds global counters
|
|
714
375
|
*/
|
|
715
376
|
function countFailures(summary) {
|
|
716
|
-
for (
|
|
377
|
+
for (const test in summary.tests) {
|
|
717
378
|
summary.errorCount += summary.tests[test].errorCount;
|
|
718
379
|
summary.warnCount += summary.tests[test].warnCount;
|
|
719
380
|
summary.testCount += summary.tests[test].testCount;
|
|
720
381
|
}
|
|
721
382
|
return summary;
|
|
722
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Appends the test to a results object.
|
|
386
|
+
* Overload is only needed to satisfy typescript. No use in breaking it down to multiple
|
|
387
|
+
* functions as it is really the same, with the difference of "valid" missing in groups
|
|
388
|
+
*/
|
|
723
389
|
function appendTestObject(summaryKey, testObject) {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
var testKey = summaryKey[fieldName];
|
|
390
|
+
const { message } = testObject;
|
|
391
|
+
const nextSummaryKey = vestUtils.defaultTo(summaryKey ? Object.assign({}, summaryKey) : null, baseTestStats);
|
|
727
392
|
if (testObject.isNonActionable())
|
|
728
|
-
return
|
|
729
|
-
|
|
393
|
+
return nextSummaryKey;
|
|
394
|
+
nextSummaryKey.testCount++;
|
|
730
395
|
if (testObject.isFailing()) {
|
|
731
396
|
incrementFailures(Severity.ERRORS);
|
|
732
397
|
}
|
|
733
398
|
else if (testObject.isWarning()) {
|
|
734
399
|
incrementFailures(Severity.WARNINGS);
|
|
735
400
|
}
|
|
736
|
-
return
|
|
401
|
+
return nextSummaryKey;
|
|
737
402
|
function incrementFailures(severity) {
|
|
738
|
-
|
|
739
|
-
|
|
403
|
+
const countKey = countKeyBySeverity(severity);
|
|
404
|
+
nextSummaryKey[countKey]++;
|
|
740
405
|
if (message) {
|
|
741
|
-
|
|
406
|
+
nextSummaryKey[severity] = (nextSummaryKey[severity] || []).concat(message);
|
|
742
407
|
}
|
|
743
408
|
}
|
|
744
409
|
}
|
|
745
|
-
function baseStats() {
|
|
746
|
-
return {
|
|
747
|
-
errorCount: 0,
|
|
748
|
-
warnCount: 0,
|
|
749
|
-
testCount: 0
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
410
|
function baseTestStats() {
|
|
753
|
-
return vestUtils.assign(
|
|
411
|
+
return vestUtils.assign(new SummaryBase(), {
|
|
754
412
|
errors: [],
|
|
755
|
-
warnings: []
|
|
413
|
+
warnings: [],
|
|
414
|
+
valid: true,
|
|
756
415
|
});
|
|
757
416
|
}
|
|
758
417
|
|
|
@@ -767,9 +426,9 @@ function getByFieldName(testGroup, severityKey, fieldName) {
|
|
|
767
426
|
return ((_a = testGroup === null || testGroup === void 0 ? void 0 : testGroup[fieldName]) === null || _a === void 0 ? void 0 : _a[severityKey]) || [];
|
|
768
427
|
}
|
|
769
428
|
function collectAll(testGroup, severityKey) {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
for (
|
|
429
|
+
const output = {};
|
|
430
|
+
const countKey = countKeyBySeverity(severityKey);
|
|
431
|
+
for (const field in testGroup) {
|
|
773
432
|
if (vestUtils.isPositive(testGroup[field][countKey])) {
|
|
774
433
|
// We will probably never get to the fallback array
|
|
775
434
|
// leaving it just in case the implementation changes
|
|
@@ -779,19 +438,37 @@ function collectAll(testGroup, severityKey) {
|
|
|
779
438
|
return output;
|
|
780
439
|
}
|
|
781
440
|
|
|
441
|
+
function bindSuiteSelectors(get) {
|
|
442
|
+
return {
|
|
443
|
+
getError: (...args) => get().getError(...args),
|
|
444
|
+
getErrors: (...args) => get().getErrors(...args),
|
|
445
|
+
getErrorsByGroup: (...args) => get().getErrorsByGroup(...args),
|
|
446
|
+
getWarning: (...args) => get().getWarning(...args),
|
|
447
|
+
getWarnings: (...args) => get().getWarnings(...args),
|
|
448
|
+
getWarningsByGroup: (...args) => get().getWarningsByGroup(...args),
|
|
449
|
+
hasErrors: (...args) => get().hasErrors(...args),
|
|
450
|
+
hasErrorsByGroup: (...args) => get().hasErrorsByGroup(...args),
|
|
451
|
+
hasWarnings: (...args) => get().hasWarnings(...args),
|
|
452
|
+
hasWarningsByGroup: (...args) => get().hasWarningsByGroup(...args),
|
|
453
|
+
isValid: (...args) => get().isValid(...args),
|
|
454
|
+
isValidByGroup: (...args) => get().isValidByGroup(...args),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
782
457
|
// eslint-disable-next-line max-lines-per-function, max-statements
|
|
783
458
|
function suiteSelectors(summary) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
459
|
+
const selectors = {
|
|
460
|
+
getError,
|
|
461
|
+
getErrors,
|
|
462
|
+
getErrorsByGroup,
|
|
463
|
+
getWarning,
|
|
464
|
+
getWarnings,
|
|
465
|
+
getWarningsByGroup,
|
|
466
|
+
hasErrors,
|
|
467
|
+
hasErrorsByGroup,
|
|
468
|
+
hasWarnings,
|
|
469
|
+
hasWarningsByGroup,
|
|
470
|
+
isValid,
|
|
471
|
+
isValidByGroup,
|
|
795
472
|
};
|
|
796
473
|
return selectors;
|
|
797
474
|
// Booleans
|
|
@@ -800,15 +477,15 @@ function suiteSelectors(summary) {
|
|
|
800
477
|
return fieldName ? Boolean((_a = summary.tests[fieldName]) === null || _a === void 0 ? void 0 : _a.valid) : summary.valid;
|
|
801
478
|
}
|
|
802
479
|
function isValidByGroup(groupName, fieldName) {
|
|
803
|
-
|
|
480
|
+
const group = summary.groups[groupName];
|
|
804
481
|
if (!group) {
|
|
805
482
|
return false;
|
|
806
483
|
}
|
|
807
484
|
if (fieldName) {
|
|
808
485
|
return isFieldValid(group, fieldName);
|
|
809
486
|
}
|
|
810
|
-
for (
|
|
811
|
-
if (!isFieldValid(group,
|
|
487
|
+
for (const fieldName in group) {
|
|
488
|
+
if (!isFieldValid(group, fieldName)) {
|
|
812
489
|
return false;
|
|
813
490
|
}
|
|
814
491
|
}
|
|
@@ -829,9 +506,15 @@ function suiteSelectors(summary) {
|
|
|
829
506
|
function getWarnings(fieldName) {
|
|
830
507
|
return getFailures(summary, Severity.WARNINGS, fieldName);
|
|
831
508
|
}
|
|
509
|
+
function getWarning(fieldName) {
|
|
510
|
+
return getFailure(Severity.WARNINGS, summary, fieldName);
|
|
511
|
+
}
|
|
832
512
|
function getErrors(fieldName) {
|
|
833
513
|
return getFailures(summary, Severity.ERRORS, fieldName);
|
|
834
514
|
}
|
|
515
|
+
function getError(fieldName) {
|
|
516
|
+
return getFailure(Severity.ERRORS, summary, fieldName);
|
|
517
|
+
}
|
|
835
518
|
function getErrorsByGroup(groupName, fieldName) {
|
|
836
519
|
return getFailuresByGroup(summary, Severity.ERRORS, groupName, fieldName);
|
|
837
520
|
}
|
|
@@ -839,8 +522,6 @@ function suiteSelectors(summary) {
|
|
|
839
522
|
return getFailuresByGroup(summary, Severity.WARNINGS, groupName, fieldName);
|
|
840
523
|
}
|
|
841
524
|
}
|
|
842
|
-
// Gathers all failures of a given severity
|
|
843
|
-
// With a fieldName, it will only gather failures for that field
|
|
844
525
|
function getFailures(summary, severityKey, fieldName) {
|
|
845
526
|
return gatherFailures(summary.tests, severityKey, fieldName);
|
|
846
527
|
}
|
|
@@ -858,14 +539,14 @@ function isFieldValid(testContainer, fieldName) {
|
|
|
858
539
|
// If a fieldName is provided, it will only check for failures within that field
|
|
859
540
|
function hasFailuresByGroup(summary, severityCount, groupName, fieldName) {
|
|
860
541
|
var _a, _b;
|
|
861
|
-
|
|
542
|
+
const group = summary.groups[groupName];
|
|
862
543
|
if (!group) {
|
|
863
544
|
return false;
|
|
864
545
|
}
|
|
865
546
|
if (fieldName) {
|
|
866
547
|
return vestUtils.isPositive((_a = group[fieldName]) === null || _a === void 0 ? void 0 : _a[severityCount]);
|
|
867
548
|
}
|
|
868
|
-
for (
|
|
549
|
+
for (const field in group) {
|
|
869
550
|
if (vestUtils.isPositive((_b = group[field]) === null || _b === void 0 ? void 0 : _b[severityCount])) {
|
|
870
551
|
return true;
|
|
871
552
|
}
|
|
@@ -876,309 +557,32 @@ function hasFailuresByGroup(summary, severityCount, groupName, fieldName) {
|
|
|
876
557
|
// If a fieldName is provided, it will only check for failures within that field
|
|
877
558
|
function hasFailures(summary, countKey, fieldName) {
|
|
878
559
|
var _a;
|
|
879
|
-
|
|
560
|
+
const failureCount = fieldName
|
|
880
561
|
? (_a = summary.tests[fieldName]) === null || _a === void 0 ? void 0 : _a[countKey]
|
|
881
562
|
: summary[countKey] || 0;
|
|
882
563
|
return vestUtils.isPositive(failureCount);
|
|
883
564
|
}
|
|
884
|
-
|
|
885
|
-
var cache$1 = vestUtils.cache(1);
|
|
886
|
-
function produceSuiteResult() {
|
|
887
|
-
var testObjects = useTestsFlat();
|
|
888
|
-
var ctxRef = { stateRef: useStateRef() };
|
|
889
|
-
return cache$1([testObjects], context.bind(ctxRef, function () {
|
|
890
|
-
var summary = genTestsSummary();
|
|
891
|
-
var suiteName = useSuiteName();
|
|
892
|
-
return vestUtils.assign(summary, suiteSelectors(summary), {
|
|
893
|
-
suiteName: suiteName
|
|
894
|
-
});
|
|
895
|
-
}));
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
/**
|
|
899
|
-
* Checks if a given field, or the suite as a whole still have remaining tests.
|
|
900
|
-
*/
|
|
901
|
-
function hasRemainingTests(fieldName) {
|
|
902
|
-
var allIncomplete = useAllIncomplete();
|
|
903
|
-
if (vestUtils.isEmpty(allIncomplete)) {
|
|
904
|
-
return false;
|
|
905
|
-
}
|
|
906
|
-
if (fieldName) {
|
|
907
|
-
return allIncomplete.some(function (testObject) {
|
|
908
|
-
return matchingFieldName(testObject, fieldName);
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
return true;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
var cache = vestUtils.cache(20);
|
|
915
|
-
function produceFullResult() {
|
|
916
|
-
var testObjects = useTestsFlat();
|
|
917
|
-
var ctxRef = { stateRef: useStateRef() };
|
|
918
|
-
return cache([testObjects], context.bind(ctxRef, function () {
|
|
919
|
-
return vestUtils.assign({}, produceSuiteResult(), {
|
|
920
|
-
done: context.bind(ctxRef, done)
|
|
921
|
-
});
|
|
922
|
-
}));
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* DONE is here and not in its own module to prevent circular dependency issues.
|
|
926
|
-
*/
|
|
927
|
-
function shouldSkipDoneRegistration(callback, fieldName, output) {
|
|
565
|
+
function getFailure(severity, summary, fieldName) {
|
|
928
566
|
var _a;
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
}
|
|
933
|
-
function shouldRunDoneCallback(fieldName) {
|
|
934
|
-
// is suite finished || field name exists, and test is finished;
|
|
935
|
-
return !!(!hasRemainingTests() ||
|
|
936
|
-
(fieldName && !hasRemainingTests(fieldName)));
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Registers done callbacks.
|
|
940
|
-
* @register {Object} Vest output object.
|
|
941
|
-
*/
|
|
942
|
-
var done = function done() {
|
|
943
|
-
var args = [];
|
|
944
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
945
|
-
args[_i] = arguments[_i];
|
|
946
|
-
}
|
|
947
|
-
var _a = args.reverse(), callback = _a[0], fieldName = _a[1];
|
|
948
|
-
var output = produceFullResult();
|
|
949
|
-
if (shouldSkipDoneRegistration(callback, fieldName, output)) {
|
|
950
|
-
return output;
|
|
951
|
-
}
|
|
952
|
-
var doneCallback = function () { return callback(produceSuiteResult()); };
|
|
953
|
-
if (shouldRunDoneCallback(fieldName)) {
|
|
954
|
-
doneCallback();
|
|
955
|
-
return output;
|
|
956
|
-
}
|
|
957
|
-
deferDoneCallback(doneCallback, fieldName);
|
|
958
|
-
return output;
|
|
959
|
-
};
|
|
960
|
-
function deferDoneCallback(doneCallback, fieldName) {
|
|
961
|
-
var _a = useTestCallbacks(), setTestCallbacks = _a[1];
|
|
962
|
-
setTestCallbacks(function (current) {
|
|
963
|
-
if (fieldName) {
|
|
964
|
-
current.fieldCallbacks[fieldName] = (current.fieldCallbacks[fieldName] || []).concat(doneCallback);
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
967
|
-
current.doneCallbacks.push(doneCallback);
|
|
968
|
-
}
|
|
969
|
-
return current;
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
/**
|
|
974
|
-
* This module gets triggered once the suite is done running its sync tests.
|
|
975
|
-
*
|
|
976
|
-
* It goes over all the tests in the state, and checks if they need to be omitted.
|
|
977
|
-
*/
|
|
978
|
-
function omitOptionalFields() {
|
|
979
|
-
var optionalFields = useOptionalFields()[0];
|
|
980
|
-
// If there are no optional fields, we don't need to do anything
|
|
981
|
-
if (vestUtils.isEmpty(optionalFields)) {
|
|
982
|
-
return;
|
|
983
|
-
}
|
|
984
|
-
// Create an object to store the fields that need to be omitted
|
|
985
|
-
var shouldOmit = {};
|
|
986
|
-
// iterate over each of the tests in the state
|
|
987
|
-
useTestsFlat().forEach(function (testObject) {
|
|
988
|
-
// If we already added the current field (not this test specifically)
|
|
989
|
-
// no need for further checks, go and omit the test
|
|
990
|
-
if (vestUtils.hasOwnProperty(shouldOmit, testObject.fieldName)) {
|
|
991
|
-
verifyAndOmit(testObject);
|
|
992
|
-
}
|
|
993
|
-
else {
|
|
994
|
-
// check if the field has an optional function
|
|
995
|
-
// if so, run it and verify/omit the test
|
|
996
|
-
runOptionalConfig(testObject);
|
|
997
|
-
}
|
|
998
|
-
});
|
|
999
|
-
// refresh the tests in the state so that the omitted fields are applied
|
|
1000
|
-
useRefreshTestObjects();
|
|
1001
|
-
function verifyAndOmit(testObject) {
|
|
1002
|
-
if (shouldOmit[testObject.fieldName]) {
|
|
1003
|
-
testObject.omit();
|
|
1004
|
-
useSetOptionalField(testObject.fieldName, function () { return ({
|
|
1005
|
-
applied: true
|
|
1006
|
-
}); });
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
function runOptionalConfig(testObject) {
|
|
1010
|
-
// Ge the optional configuration for the given field
|
|
1011
|
-
var optionalConfig = useOptionalField(testObject.fieldName);
|
|
1012
|
-
// If the optional was set to a function or a boolean, run it and verify/omit the test
|
|
1013
|
-
if (optionalConfig.type === OptionalFieldTypes.Immediate) {
|
|
1014
|
-
shouldOmit[testObject.fieldName] = vestUtils.optionalFunctionValue(optionalConfig.rule);
|
|
1015
|
-
verifyAndOmit(testObject);
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
/**
|
|
1021
|
-
* Removes test object from suite state
|
|
1022
|
-
*/
|
|
1023
|
-
function removeTestFromState (testObject) {
|
|
1024
|
-
useSetTests(function (tests) {
|
|
1025
|
-
return vestUtils.nestedArray.transform(tests, function (test) { return (testObject !== test ? test : null); });
|
|
1026
|
-
});
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
/**
|
|
1030
|
-
* Runs done callback per field when async tests are finished running.
|
|
1031
|
-
*/
|
|
1032
|
-
function runFieldCallbacks(fieldName) {
|
|
1033
|
-
var fieldCallbacks = useTestCallbacks()[0].fieldCallbacks;
|
|
1034
|
-
if (fieldName &&
|
|
1035
|
-
!hasRemainingTests(fieldName) &&
|
|
1036
|
-
vestUtils.isArray(fieldCallbacks[fieldName])) {
|
|
1037
|
-
vestUtils.callEach(fieldCallbacks[fieldName]);
|
|
567
|
+
const summaryKey = summary[severity];
|
|
568
|
+
if (!fieldName) {
|
|
569
|
+
return summaryKey[0];
|
|
1038
570
|
}
|
|
1039
|
-
|
|
1040
|
-
/**
|
|
1041
|
-
* Runs unlabelled done callback when async tests are finished running.
|
|
1042
|
-
*/
|
|
1043
|
-
function runDoneCallbacks() {
|
|
1044
|
-
var doneCallbacks = useTestCallbacks()[0].doneCallbacks;
|
|
1045
|
-
vestUtils.callEach(doneCallbacks);
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
// eslint-disable-next-line max-lines-per-function
|
|
1049
|
-
function initBus() {
|
|
1050
|
-
var vestBus = vestUtils.bus.createBus();
|
|
1051
|
-
// Report a the completion of a test. There may be other tests with the same
|
|
1052
|
-
// name that are still running, or not yet started.
|
|
1053
|
-
vestBus.on(Events.TEST_COMPLETED, function (testObject) {
|
|
1054
|
-
if (testObject.isCanceled()) {
|
|
1055
|
-
return;
|
|
1056
|
-
}
|
|
1057
|
-
testObject.done();
|
|
1058
|
-
runFieldCallbacks(testObject.fieldName);
|
|
1059
|
-
if (!hasRemainingTests()) {
|
|
1060
|
-
// When no more tests are running, emit the done event
|
|
1061
|
-
vestBus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
|
|
1062
|
-
}
|
|
1063
|
-
});
|
|
1064
|
-
// Report that the suite completed its synchronous test run.
|
|
1065
|
-
// Async operations may still be running.
|
|
1066
|
-
vestBus.on(Events.SUITE_CALLBACK_DONE_RUNNING, function () {
|
|
1067
|
-
// Remove tests that are optional and need to be omitted
|
|
1068
|
-
omitOptionalFields();
|
|
1069
|
-
});
|
|
1070
|
-
// Called when all the tests, including async, are done running
|
|
1071
|
-
vestBus.on(Events.ALL_RUNNING_TESTS_FINISHED, function () {
|
|
1072
|
-
runDoneCallbacks();
|
|
1073
|
-
});
|
|
1074
|
-
// Removes a certain field from the state.
|
|
1075
|
-
vestBus.on(Events.REMOVE_FIELD, function (fieldName) {
|
|
1076
|
-
useEachTestObject(function (testObject) {
|
|
1077
|
-
if (matchingFieldName(testObject, fieldName)) {
|
|
1078
|
-
testObject.cancel();
|
|
1079
|
-
removeTestFromState(testObject);
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
});
|
|
1083
|
-
// Resets a certain field in the state.
|
|
1084
|
-
vestBus.on(Events.RESET_FIELD, function (fieldName) {
|
|
1085
|
-
useEachTestObject(function (testObject) {
|
|
1086
|
-
if (matchingFieldName(testObject, fieldName)) {
|
|
1087
|
-
testObject.reset();
|
|
1088
|
-
}
|
|
1089
|
-
});
|
|
1090
|
-
});
|
|
1091
|
-
return vestBus;
|
|
1092
|
-
}
|
|
1093
|
-
function useBus() {
|
|
1094
|
-
var context$1 = context.useX();
|
|
1095
|
-
vestUtils.invariant(context$1.bus);
|
|
1096
|
-
return context$1.bus;
|
|
1097
|
-
}
|
|
1098
|
-
var Events;
|
|
1099
|
-
(function (Events) {
|
|
1100
|
-
Events["TEST_COMPLETED"] = "test_completed";
|
|
1101
|
-
Events["ALL_RUNNING_TESTS_FINISHED"] = "all_running_tests_finished";
|
|
1102
|
-
Events["REMOVE_FIELD"] = "remove_field";
|
|
1103
|
-
Events["RESET_FIELD"] = "reset_field";
|
|
1104
|
-
Events["SUITE_CALLBACK_DONE_RUNNING"] = "suite_callback_done_running";
|
|
1105
|
-
})(Events || (Events = {}));
|
|
1106
|
-
|
|
1107
|
-
// eslint-disable-next-line max-lines-per-function
|
|
1108
|
-
function create() {
|
|
1109
|
-
var args = [];
|
|
1110
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
1111
|
-
args[_i] = arguments[_i];
|
|
1112
|
-
}
|
|
1113
|
-
var _a = args.reverse(), suiteCallback = _a[0], suiteName = _a[1];
|
|
1114
|
-
vestUtils.invariant(vestUtils.isFunction(suiteCallback), 'vest.create: Expected callback to be a function.');
|
|
1115
|
-
// Event bus initialization
|
|
1116
|
-
var bus = initBus();
|
|
1117
|
-
// State initialization
|
|
1118
|
-
var state = createState();
|
|
1119
|
-
// State reference - this holds the actual state values
|
|
1120
|
-
var stateRef = createStateRef(state, { suiteId: vestUtils.seq(), suiteName: suiteName });
|
|
1121
|
-
// Create base context reference. All hooks will derive their data from this
|
|
1122
|
-
var ctxRef = { stateRef: stateRef, bus: bus };
|
|
1123
|
-
var suite = vestUtils.assign(
|
|
1124
|
-
// Bind the suite body to the context
|
|
1125
|
-
context.bind(ctxRef, function () {
|
|
1126
|
-
var args = [];
|
|
1127
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
1128
|
-
args[_i] = arguments[_i];
|
|
1129
|
-
}
|
|
1130
|
-
// Reset the state. Migrates current test objects to `prev` array.
|
|
1131
|
-
state.reset();
|
|
1132
|
-
// Create a top level isolate
|
|
1133
|
-
isolate({ type: IsolateTypes.SUITE }, function () {
|
|
1134
|
-
// Run the consumer's callback
|
|
1135
|
-
suiteCallback.apply(void 0, args);
|
|
1136
|
-
});
|
|
1137
|
-
// Report the suite is done registering tests
|
|
1138
|
-
// Async tests may still be running
|
|
1139
|
-
bus.emit(Events.SUITE_CALLBACK_DONE_RUNNING);
|
|
1140
|
-
// Return the result
|
|
1141
|
-
return produceFullResult();
|
|
1142
|
-
}), {
|
|
1143
|
-
get: context.bind(ctxRef, produceSuiteResult),
|
|
1144
|
-
remove: context.bind(ctxRef, function (fieldName) {
|
|
1145
|
-
bus.emit(Events.REMOVE_FIELD, fieldName);
|
|
1146
|
-
}),
|
|
1147
|
-
reset: state.reset,
|
|
1148
|
-
resetField: context.bind(ctxRef, function (fieldName) {
|
|
1149
|
-
bus.emit(Events.RESET_FIELD, fieldName);
|
|
1150
|
-
})
|
|
1151
|
-
});
|
|
1152
|
-
return suite;
|
|
571
|
+
return (_a = summaryKey.find((summaryFailure) => matchingFieldName(summaryFailure, fieldName))) === null || _a === void 0 ? void 0 : _a.message;
|
|
1153
572
|
}
|
|
1154
573
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
* enforce(item.value).isNotEmpty();
|
|
1165
|
-
* }, item.id)
|
|
1166
|
-
* })
|
|
1167
|
-
*/
|
|
1168
|
-
function each(list, callback) {
|
|
1169
|
-
vestUtils.invariant(vestUtils.isFunction(callback), 'each callback must be a function');
|
|
1170
|
-
isolate({ type: IsolateTypes.EACH }, function () {
|
|
1171
|
-
list.forEach(function (arg, index) {
|
|
1172
|
-
callback(arg, index);
|
|
1173
|
-
});
|
|
574
|
+
function useCreateSuiteResult() {
|
|
575
|
+
return useSuiteResultCache(() => {
|
|
576
|
+
// eslint-disable-next-line vest-internal/use-use
|
|
577
|
+
const summary = useProduceSuiteSummary();
|
|
578
|
+
// eslint-disable-next-line vest-internal/use-use
|
|
579
|
+
const suiteName = useSuiteName();
|
|
580
|
+
return Object.freeze(vestUtils.assign(summary, suiteSelectors(summary), {
|
|
581
|
+
suiteName,
|
|
582
|
+
}));
|
|
1174
583
|
});
|
|
1175
584
|
}
|
|
1176
585
|
|
|
1177
|
-
/**
|
|
1178
|
-
* Error message to display when a hook was called outside of context.
|
|
1179
|
-
*/
|
|
1180
|
-
var ERROR_HOOK_CALLED_OUTSIDE = 'hook called outside of a running suite.';
|
|
1181
|
-
|
|
1182
586
|
/**
|
|
1183
587
|
* Conditionally skips running tests within the callback.
|
|
1184
588
|
*
|
|
@@ -1188,20 +592,21 @@ var ERROR_HOOK_CALLED_OUTSIDE = 'hook called outside of a running suite.';
|
|
|
1188
592
|
* test('username', 'User already taken', async () => await doesUserExist(username)
|
|
1189
593
|
* });
|
|
1190
594
|
*/
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
595
|
+
// @vx-allow use-use
|
|
596
|
+
function skipWhen(condition, callback) {
|
|
597
|
+
vestRuntime.Isolate.create(() => {
|
|
598
|
+
SuiteContext.run({
|
|
1194
599
|
skipped:
|
|
1195
600
|
// Checking for nested conditional. If we're in a nested skipWhen,
|
|
1196
601
|
// we should skip the test if the parent conditional is true.
|
|
1197
|
-
|
|
602
|
+
useIsExcludedIndividually() ||
|
|
1198
603
|
// Otherwise, we should skip the test if the conditional is true.
|
|
1199
|
-
vestUtils.optionalFunctionValue(
|
|
1200
|
-
},
|
|
604
|
+
vestUtils.optionalFunctionValue(condition, vestUtils.optionalFunctionValue(useCreateSuiteResult)),
|
|
605
|
+
}, callback);
|
|
1201
606
|
});
|
|
1202
607
|
}
|
|
1203
|
-
function
|
|
1204
|
-
return
|
|
608
|
+
function useIsExcludedIndividually() {
|
|
609
|
+
return useSkipped();
|
|
1205
610
|
}
|
|
1206
611
|
|
|
1207
612
|
/**
|
|
@@ -1211,11 +616,12 @@ function isExcludedIndividually() {
|
|
|
1211
616
|
*
|
|
1212
617
|
* only('username');
|
|
1213
618
|
*/
|
|
619
|
+
// @vx-allow use-use
|
|
1214
620
|
function only(item) {
|
|
1215
|
-
return
|
|
621
|
+
return useAddTo(0 /* ExclusionGroup.ONLY */, 'tests', item);
|
|
1216
622
|
}
|
|
1217
|
-
only.group = function (item) {
|
|
1218
|
-
return
|
|
623
|
+
only.group = function group(item) {
|
|
624
|
+
return useAddTo(0 /* ExclusionGroup.ONLY */, 'groups', item);
|
|
1219
625
|
};
|
|
1220
626
|
/**
|
|
1221
627
|
* Adds a field or a list of fields into the exclusion list
|
|
@@ -1224,31 +630,31 @@ only.group = function (item) {
|
|
|
1224
630
|
*
|
|
1225
631
|
* skip('username');
|
|
1226
632
|
*/
|
|
633
|
+
// @vx-allow use-use
|
|
1227
634
|
function skip(item) {
|
|
1228
|
-
return
|
|
635
|
+
return useAddTo(1 /* ExclusionGroup.SKIP */, 'tests', item);
|
|
1229
636
|
}
|
|
1230
|
-
skip.group = function (item) {
|
|
1231
|
-
return
|
|
637
|
+
skip.group = function group(item) {
|
|
638
|
+
return useAddTo(1 /* ExclusionGroup.SKIP */, 'groups', item);
|
|
1232
639
|
};
|
|
1233
640
|
//Checks whether a certain test profile excluded by any of the exclusion groups.
|
|
1234
641
|
// eslint-disable-next-line complexity, max-statements
|
|
1235
|
-
function
|
|
1236
|
-
|
|
1237
|
-
if (
|
|
642
|
+
function useIsExcluded(testObject) {
|
|
643
|
+
const { fieldName, groupName } = testObject;
|
|
644
|
+
if (useIsExcludedIndividually())
|
|
1238
645
|
return true;
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
var testValue = keyTests[fieldName];
|
|
646
|
+
const exclusion = useExclusion();
|
|
647
|
+
const inclusion = useInclusion();
|
|
648
|
+
const keyTests = exclusion.tests;
|
|
649
|
+
const testValue = keyTests[fieldName];
|
|
1244
650
|
// if test is skipped
|
|
1245
651
|
// no need to proceed
|
|
1246
652
|
if (testValue === false)
|
|
1247
653
|
return true;
|
|
1248
|
-
|
|
654
|
+
const isTestIncluded = testValue === true;
|
|
1249
655
|
// If inside a group
|
|
1250
656
|
if (groupName) {
|
|
1251
|
-
if (
|
|
657
|
+
if (useIsGroupExcluded(groupName)) {
|
|
1252
658
|
return true; // field excluded by group
|
|
1253
659
|
// if group is `only`ed
|
|
1254
660
|
}
|
|
@@ -1261,7 +667,7 @@ function isExcluded(testObject) {
|
|
|
1261
667
|
return keyTests[fieldName] === false;
|
|
1262
668
|
}
|
|
1263
669
|
}
|
|
1264
|
-
if (
|
|
670
|
+
if (useIsTopLevelWhenThereIsAnIncludedGroup(groupName)) {
|
|
1265
671
|
return true;
|
|
1266
672
|
}
|
|
1267
673
|
// if field is only'ed
|
|
@@ -1270,8 +676,6 @@ function isExcluded(testObject) {
|
|
|
1270
676
|
// If there is _ANY_ `only`ed test (and we already know this one isn't) return true
|
|
1271
677
|
if (hasIncludedTests(keyTests)) {
|
|
1272
678
|
// Check if inclusion rules for this field (`include` hook)
|
|
1273
|
-
// TODO: Check if this may need to be moved outside of the condition.
|
|
1274
|
-
// What if there are no included tests? This shouldn't run then?
|
|
1275
679
|
return !vestUtils.optionalFunctionValue(inclusion[fieldName]);
|
|
1276
680
|
}
|
|
1277
681
|
// We're done here. This field is not excluded
|
|
@@ -1280,98 +684,760 @@ function isExcluded(testObject) {
|
|
|
1280
684
|
/**
|
|
1281
685
|
* Checks whether a given group is excluded from running.
|
|
1282
686
|
*/
|
|
1283
|
-
function
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
var groupPresent = vestUtils.hasOwnProperty(keyGroups, groupName);
|
|
687
|
+
function useIsGroupExcluded(groupName) {
|
|
688
|
+
const exclusion = useExclusion();
|
|
689
|
+
const keyGroups = exclusion.groups;
|
|
690
|
+
const groupPresent = vestUtils.hasOwnProperty(keyGroups, groupName);
|
|
1288
691
|
// When group is either only'ed or skipped
|
|
1289
692
|
if (groupPresent) {
|
|
1290
693
|
// Return true if group is skipped and false if only'ed
|
|
1291
694
|
return keyGroups[groupName] === false;
|
|
1292
695
|
}
|
|
1293
|
-
// Group is not present
|
|
1294
|
-
// Return whether other groups are included
|
|
1295
|
-
return
|
|
696
|
+
// Group is not present
|
|
697
|
+
// Return whether other groups are included
|
|
698
|
+
return useHasIncludedGroups();
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Adds fields to a specified exclusion group.
|
|
702
|
+
*/
|
|
703
|
+
function useAddTo(exclusionGroup, itemType, item) {
|
|
704
|
+
const exclusion = useExclusion(ErrorStrings.HOOK_CALLED_OUTSIDE);
|
|
705
|
+
if (!item) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
vestUtils.asArray(item).forEach((itemName) => {
|
|
709
|
+
if (!vestUtils.isStringValue(itemName)) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
exclusion[itemType][itemName] = exclusionGroup === 0 /* ExclusionGroup.ONLY */;
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Checks if context has included tests
|
|
717
|
+
*/
|
|
718
|
+
function hasIncludedTests(keyTests) {
|
|
719
|
+
for (const test in keyTests) {
|
|
720
|
+
if (keyTests[test] === true) {
|
|
721
|
+
return true; // excluded implicitly
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
// are we not in a group and there is an included group?
|
|
727
|
+
function useIsTopLevelWhenThereIsAnIncludedGroup(groupName) {
|
|
728
|
+
if (!useHasIncludedGroups()) {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
// Return whether there's an included group, and we're not inside a group
|
|
732
|
+
return !groupName;
|
|
733
|
+
}
|
|
734
|
+
function useHasIncludedGroups() {
|
|
735
|
+
const exclusion = useExclusion();
|
|
736
|
+
for (const group in exclusion.groups) {
|
|
737
|
+
if (exclusion.groups[group]) {
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Conditionally omits tests from the suite.
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
*
|
|
749
|
+
* omitWhen(res => res.hasErrors('username'), () => {
|
|
750
|
+
* test('username', 'User already taken', async () => await doesUserExist(username)
|
|
751
|
+
* });
|
|
752
|
+
*/
|
|
753
|
+
// @vx-allow use-use
|
|
754
|
+
function omitWhen(conditional, callback) {
|
|
755
|
+
vestRuntime.Isolate.create(() => {
|
|
756
|
+
SuiteContext.run({
|
|
757
|
+
omitted: useWithinActiveOmitWhen() ||
|
|
758
|
+
vestUtils.optionalFunctionValue(conditional, vestUtils.optionalFunctionValue(useCreateSuiteResult)),
|
|
759
|
+
}, callback);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
// Checks that we're currently in an active omitWhen block
|
|
763
|
+
function useWithinActiveOmitWhen() {
|
|
764
|
+
return useOmitted();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function useVerifyTestRun(testObject, collisionResult = testObject) {
|
|
768
|
+
if (useShouldSkipBasedOnMode(testObject)) {
|
|
769
|
+
return skipTestAndReturn(testObject);
|
|
770
|
+
}
|
|
771
|
+
if (useShouldOmit(testObject)) {
|
|
772
|
+
return omitTestAndReturn(testObject);
|
|
773
|
+
}
|
|
774
|
+
if (useIsExcluded(testObject)) {
|
|
775
|
+
return useForceSkipIfInSkipWhen(collisionResult);
|
|
776
|
+
}
|
|
777
|
+
return testObject;
|
|
778
|
+
}
|
|
779
|
+
function useShouldOmit(testObject) {
|
|
780
|
+
return (useWithinActiveOmitWhen() || useIsOptionalFiedApplied(testObject.fieldName));
|
|
781
|
+
}
|
|
782
|
+
function skipTestAndReturn(testNode) {
|
|
783
|
+
testNode.skip();
|
|
784
|
+
return testNode;
|
|
785
|
+
}
|
|
786
|
+
function omitTestAndReturn(testNode) {
|
|
787
|
+
testNode.omit();
|
|
788
|
+
return testNode;
|
|
789
|
+
}
|
|
790
|
+
function useForceSkipIfInSkipWhen(testNode) {
|
|
791
|
+
// We're forcing skipping the pending test
|
|
792
|
+
// if we're directly within a skipWhen block
|
|
793
|
+
// This mostly means that we're probably giving
|
|
794
|
+
// up on this async test intentionally.
|
|
795
|
+
testNode.skip(useIsExcludedIndividually());
|
|
796
|
+
return testNode;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// @vx-allow use-use
|
|
800
|
+
function IsolateTestReconciler(currentNode, historyNode) {
|
|
801
|
+
// Start by verifying params
|
|
802
|
+
if (!IsolateTest.is(currentNode)) {
|
|
803
|
+
// This is unreachable, since this function should only be called with IsolateTest nodes
|
|
804
|
+
return currentNode;
|
|
805
|
+
}
|
|
806
|
+
if (vestUtils.isNullish(historyNode)) {
|
|
807
|
+
return handleNoHistoryNode(currentNode);
|
|
808
|
+
}
|
|
809
|
+
if (!IsolateTest.is(historyNode)) {
|
|
810
|
+
return currentNode;
|
|
811
|
+
}
|
|
812
|
+
const reconcilerOutput = usePickNode(historyNode, currentNode);
|
|
813
|
+
cancelOverriddenPendingTestOnTestReRun(reconcilerOutput, currentNode, historyNode);
|
|
814
|
+
return reconcilerOutput;
|
|
815
|
+
}
|
|
816
|
+
// eslint-disable-next-line max-statements
|
|
817
|
+
function nodeReorderDetected(newNode, prevNode) {
|
|
818
|
+
return !!IsolateTest.is(prevNode) && !isSameProfileTest(prevNode, newNode);
|
|
819
|
+
}
|
|
820
|
+
function handleCollision(newNode, prevNode) {
|
|
821
|
+
if (newNode.usesKey()) {
|
|
822
|
+
return IsolateTest.cast(vestRuntime.Reconciler.handleIsolateNodeWithKey(newNode));
|
|
823
|
+
}
|
|
824
|
+
if (nodeReorderDetected(newNode, prevNode)) {
|
|
825
|
+
return onNodeReorder(newNode, prevNode);
|
|
826
|
+
}
|
|
827
|
+
if (!IsolateTest.is(prevNode)) {
|
|
828
|
+
// I believe we cannot actually reach this point.
|
|
829
|
+
// Because it should already be handled by nodeReorderDetected.
|
|
830
|
+
return newNode;
|
|
831
|
+
}
|
|
832
|
+
// FIXME: May-13-2023
|
|
833
|
+
// This may not be the most ideal solution.
|
|
834
|
+
// In short: if the node was omitted in the previous run,
|
|
835
|
+
// we want to re-evaluate it. The reason is that we may incorrectly
|
|
836
|
+
// identify it is "optional" because it was omitted in the previous run.
|
|
837
|
+
// There may be a better way to handle this. Need to revisit this.
|
|
838
|
+
if (prevNode.isOmitted()) {
|
|
839
|
+
return newNode;
|
|
840
|
+
}
|
|
841
|
+
return prevNode;
|
|
842
|
+
}
|
|
843
|
+
function onNodeReorder(newNode, prevNode) {
|
|
844
|
+
throwTestOrderError(newNode, prevNode);
|
|
845
|
+
vestRuntime.Reconciler.removeAllNextNodesInIsolate();
|
|
846
|
+
return newNode;
|
|
847
|
+
}
|
|
848
|
+
function usePickNode(historyNode, currentNode) {
|
|
849
|
+
const collisionResult = handleCollision(currentNode, historyNode);
|
|
850
|
+
return useVerifyTestRun(currentNode, collisionResult);
|
|
851
|
+
}
|
|
852
|
+
function handleNoHistoryNode(testNode) {
|
|
853
|
+
if (testNode.usesKey()) {
|
|
854
|
+
return IsolateTest.cast(vestRuntime.Reconciler.handleIsolateNodeWithKey(testNode));
|
|
855
|
+
}
|
|
856
|
+
return testNode;
|
|
857
|
+
}
|
|
858
|
+
function cancelOverriddenPendingTestOnTestReRun(nextNode, currentNode, prevTestObject) {
|
|
859
|
+
if (nextNode === currentNode && IsolateTest.is(currentNode)) {
|
|
860
|
+
cancelOverriddenPendingTest(prevTestObject, currentNode);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
function throwTestOrderError(newNode, prevNode) {
|
|
864
|
+
if (newNode.shouldAllowReorder()) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
vestUtils.deferThrow(vestUtils.text(ErrorStrings.TESTS_CALLED_IN_DIFFERENT_ORDER, {
|
|
868
|
+
fieldName: newNode.fieldName,
|
|
869
|
+
prevName: IsolateTest.is(prevNode) ? prevNode.fieldName : undefined,
|
|
870
|
+
}));
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
var TestStatus;
|
|
874
|
+
(function (TestStatus) {
|
|
875
|
+
TestStatus["UNTESTED"] = "UNTESTED";
|
|
876
|
+
TestStatus["SKIPPED"] = "SKIPPED";
|
|
877
|
+
TestStatus["FAILED"] = "FAILED";
|
|
878
|
+
TestStatus["WARNING"] = "WARNING";
|
|
879
|
+
TestStatus["PASSING"] = "PASSING";
|
|
880
|
+
TestStatus["PENDING"] = "PENDING";
|
|
881
|
+
TestStatus["CANCELED"] = "CANCELED";
|
|
882
|
+
TestStatus["OMITTED"] = "OMITTED";
|
|
883
|
+
})(TestStatus || (TestStatus = {}));
|
|
884
|
+
var TestAction;
|
|
885
|
+
(function (TestAction) {
|
|
886
|
+
TestAction["RESET"] = "RESET";
|
|
887
|
+
})(TestAction || (TestAction = {}));
|
|
888
|
+
function createTestStateMachine() {
|
|
889
|
+
return vestUtils.StateMachine(machine);
|
|
890
|
+
}
|
|
891
|
+
/* eslint-disable sort-keys */
|
|
892
|
+
const machine = {
|
|
893
|
+
initial: TestStatus.UNTESTED,
|
|
894
|
+
states: {
|
|
895
|
+
'*': {
|
|
896
|
+
[TestStatus.OMITTED]: TestStatus.OMITTED,
|
|
897
|
+
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
898
|
+
},
|
|
899
|
+
[TestStatus.UNTESTED]: {
|
|
900
|
+
[TestStatus.CANCELED]: TestStatus.CANCELED,
|
|
901
|
+
[TestStatus.FAILED]: TestStatus.FAILED,
|
|
902
|
+
[TestStatus.PASSING]: TestStatus.PASSING,
|
|
903
|
+
[TestStatus.PENDING]: TestStatus.PENDING,
|
|
904
|
+
[TestStatus.SKIPPED]: TestStatus.SKIPPED,
|
|
905
|
+
[TestStatus.WARNING]: TestStatus.WARNING,
|
|
906
|
+
},
|
|
907
|
+
[TestStatus.PENDING]: {
|
|
908
|
+
[TestStatus.CANCELED]: TestStatus.CANCELED,
|
|
909
|
+
[TestStatus.FAILED]: TestStatus.FAILED,
|
|
910
|
+
[TestStatus.PASSING]: TestStatus.PASSING,
|
|
911
|
+
[TestStatus.SKIPPED]: [
|
|
912
|
+
TestStatus.SKIPPED,
|
|
913
|
+
(force) => force === true,
|
|
914
|
+
],
|
|
915
|
+
[TestStatus.WARNING]: TestStatus.WARNING,
|
|
916
|
+
},
|
|
917
|
+
[TestStatus.SKIPPED]: {},
|
|
918
|
+
[TestStatus.FAILED]: {},
|
|
919
|
+
[TestStatus.WARNING]: {},
|
|
920
|
+
[TestStatus.PASSING]: {},
|
|
921
|
+
[TestStatus.CANCELED]: {},
|
|
922
|
+
[TestStatus.OMITTED]: {},
|
|
923
|
+
},
|
|
924
|
+
};
|
|
925
|
+
/* eslint-enable sort-keys */
|
|
926
|
+
|
|
927
|
+
function shouldUseErrorAsMessage(message, error) {
|
|
928
|
+
// kind of cheating with this safe guard, but it does the job
|
|
929
|
+
return vestUtils.isUndefined(message) && vestUtils.isStringValue(error);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
class IsolateTest extends vestRuntime.Isolate {
|
|
933
|
+
constructor({ fieldName, testFn, message, groupName, key = null, }) {
|
|
934
|
+
super();
|
|
935
|
+
this.children = null;
|
|
936
|
+
this.id = vestUtils.seq();
|
|
937
|
+
this.severity = TestSeverity.Error;
|
|
938
|
+
this.stateMachine = createTestStateMachine();
|
|
939
|
+
this.fieldName = fieldName;
|
|
940
|
+
this.testFn = testFn;
|
|
941
|
+
if (groupName) {
|
|
942
|
+
this.groupName = groupName;
|
|
943
|
+
}
|
|
944
|
+
if (message) {
|
|
945
|
+
this.message = message;
|
|
946
|
+
}
|
|
947
|
+
this.setKey(key);
|
|
948
|
+
}
|
|
949
|
+
static create(callback, data) {
|
|
950
|
+
return IsolateTest.cast(super.create(callback, data));
|
|
951
|
+
}
|
|
952
|
+
static cast(isolate) {
|
|
953
|
+
IsolateTest.isX(isolate);
|
|
954
|
+
return isolate;
|
|
955
|
+
}
|
|
956
|
+
get status() {
|
|
957
|
+
return this.stateMachine.getState();
|
|
958
|
+
}
|
|
959
|
+
setStatus(status, payload) {
|
|
960
|
+
this.stateMachine.transition(status, payload);
|
|
961
|
+
}
|
|
962
|
+
run() {
|
|
963
|
+
let result;
|
|
964
|
+
try {
|
|
965
|
+
result = this.testFn();
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
if (shouldUseErrorAsMessage(this.message, error)) {
|
|
969
|
+
this.message = error;
|
|
970
|
+
}
|
|
971
|
+
result = false;
|
|
972
|
+
}
|
|
973
|
+
if (result === false) {
|
|
974
|
+
this.fail();
|
|
975
|
+
}
|
|
976
|
+
return result;
|
|
977
|
+
}
|
|
978
|
+
// Selectors
|
|
979
|
+
warns() {
|
|
980
|
+
return this.severity === TestSeverity.Warning;
|
|
981
|
+
}
|
|
982
|
+
isPending() {
|
|
983
|
+
return this.statusEquals(TestStatus.PENDING);
|
|
984
|
+
}
|
|
985
|
+
isOmitted() {
|
|
986
|
+
return this.statusEquals(TestStatus.OMITTED);
|
|
987
|
+
}
|
|
988
|
+
isUntested() {
|
|
989
|
+
return this.statusEquals(TestStatus.UNTESTED);
|
|
990
|
+
}
|
|
991
|
+
isFailing() {
|
|
992
|
+
return this.statusEquals(TestStatus.FAILED);
|
|
993
|
+
}
|
|
994
|
+
isCanceled() {
|
|
995
|
+
return this.statusEquals(TestStatus.CANCELED);
|
|
996
|
+
}
|
|
997
|
+
isSkipped() {
|
|
998
|
+
return this.statusEquals(TestStatus.SKIPPED);
|
|
999
|
+
}
|
|
1000
|
+
isPassing() {
|
|
1001
|
+
return this.statusEquals(TestStatus.PASSING);
|
|
1002
|
+
}
|
|
1003
|
+
isWarning() {
|
|
1004
|
+
return this.statusEquals(TestStatus.WARNING);
|
|
1005
|
+
}
|
|
1006
|
+
hasFailures() {
|
|
1007
|
+
return this.isFailing() || this.isWarning();
|
|
1008
|
+
}
|
|
1009
|
+
isNonActionable() {
|
|
1010
|
+
return this.isSkipped() || this.isOmitted() || this.isCanceled();
|
|
1011
|
+
}
|
|
1012
|
+
isTested() {
|
|
1013
|
+
return this.hasFailures() || this.isPassing();
|
|
1014
|
+
}
|
|
1015
|
+
awaitsResolution() {
|
|
1016
|
+
// Is the test in a state where it can still be run, or complete running
|
|
1017
|
+
// and its final status is indeterminate?
|
|
1018
|
+
return this.isSkipped() || this.isUntested() || this.isPending();
|
|
1019
|
+
}
|
|
1020
|
+
statusEquals(status) {
|
|
1021
|
+
return this.status === status;
|
|
1022
|
+
}
|
|
1023
|
+
// State modifiers
|
|
1024
|
+
setPending() {
|
|
1025
|
+
this.setStatus(TestStatus.PENDING);
|
|
1026
|
+
}
|
|
1027
|
+
fail() {
|
|
1028
|
+
this.setStatus(this.warns() ? TestStatus.WARNING : TestStatus.FAILED);
|
|
1029
|
+
}
|
|
1030
|
+
pass() {
|
|
1031
|
+
this.setStatus(TestStatus.PASSING);
|
|
1032
|
+
}
|
|
1033
|
+
warn() {
|
|
1034
|
+
this.severity = TestSeverity.Warning;
|
|
1035
|
+
}
|
|
1036
|
+
skip(force) {
|
|
1037
|
+
// Without this force flag, the test will be marked as skipped even if it is pending.
|
|
1038
|
+
// This means that it will not be counted in "allIncomplete" and its done callbacks
|
|
1039
|
+
// will not be called, or will be called prematurely.
|
|
1040
|
+
// What this mostly say is that when we have a pending test for one field, and we then
|
|
1041
|
+
// start typing in a different field - the pending test will be canceled, which
|
|
1042
|
+
// is usually an unwanted behavior.
|
|
1043
|
+
// The only scenario in which we DO want to cancel the async test regardless
|
|
1044
|
+
// is when we specifically skip a test with `skipWhen`, which is handled by the
|
|
1045
|
+
// "force" boolean flag.
|
|
1046
|
+
// I am not a fan of this flag, but it gets the job done.
|
|
1047
|
+
this.setStatus(TestStatus.SKIPPED, force);
|
|
1048
|
+
}
|
|
1049
|
+
cancel() {
|
|
1050
|
+
this.setStatus(TestStatus.CANCELED);
|
|
1051
|
+
}
|
|
1052
|
+
reset() {
|
|
1053
|
+
this.stateMachine.transition(TestAction.RESET);
|
|
1054
|
+
}
|
|
1055
|
+
omit() {
|
|
1056
|
+
this.setStatus(TestStatus.OMITTED);
|
|
1057
|
+
}
|
|
1058
|
+
valueOf() {
|
|
1059
|
+
return !this.isFailing();
|
|
1060
|
+
}
|
|
1061
|
+
isAsyncTest() {
|
|
1062
|
+
return vestUtils.isPromise(this.asyncTest);
|
|
1063
|
+
}
|
|
1064
|
+
static is(value) {
|
|
1065
|
+
return value instanceof IsolateTest;
|
|
1066
|
+
}
|
|
1067
|
+
static isX(value) {
|
|
1068
|
+
vestUtils.invariant(this.is(value));
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
IsolateTest.reconciler = IsolateTestReconciler;
|
|
1072
|
+
|
|
1073
|
+
class TestWalker {
|
|
1074
|
+
static defaultRoot() {
|
|
1075
|
+
return vestRuntime.VestRuntime.useAvailableRoot();
|
|
1076
|
+
}
|
|
1077
|
+
static hasNoTests(root = TestWalker.defaultRoot()) {
|
|
1078
|
+
if (!root)
|
|
1079
|
+
return true;
|
|
1080
|
+
return !vestRuntime.Walker.has(root, IsolateTest.is);
|
|
1081
|
+
}
|
|
1082
|
+
static someIncompleteTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1083
|
+
if (!root)
|
|
1084
|
+
return false;
|
|
1085
|
+
return vestRuntime.Walker.some(root, isolate => {
|
|
1086
|
+
IsolateTest.isX(isolate);
|
|
1087
|
+
return isolate.isPending() && predicate(isolate);
|
|
1088
|
+
}, IsolateTest.is);
|
|
1089
|
+
}
|
|
1090
|
+
static someTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1091
|
+
if (!root)
|
|
1092
|
+
return false;
|
|
1093
|
+
return vestRuntime.Walker.some(root, isolate => {
|
|
1094
|
+
IsolateTest.isX(isolate);
|
|
1095
|
+
return predicate(isolate);
|
|
1096
|
+
}, IsolateTest.is);
|
|
1097
|
+
}
|
|
1098
|
+
static everyTest(predicate, root = TestWalker.defaultRoot()) {
|
|
1099
|
+
if (!root)
|
|
1100
|
+
return false;
|
|
1101
|
+
return vestRuntime.Walker.every(root, isolate => {
|
|
1102
|
+
IsolateTest.isX(isolate);
|
|
1103
|
+
return predicate(isolate);
|
|
1104
|
+
}, IsolateTest.is);
|
|
1105
|
+
}
|
|
1106
|
+
static walkTests(callback, root = TestWalker.defaultRoot()) {
|
|
1107
|
+
if (!root)
|
|
1108
|
+
return;
|
|
1109
|
+
vestRuntime.Walker.walk(root, (isolate, breakout) => {
|
|
1110
|
+
callback(IsolateTest.cast(isolate), breakout);
|
|
1111
|
+
}, IsolateTest.is);
|
|
1112
|
+
}
|
|
1113
|
+
static hasRemainingTests(fieldName) {
|
|
1114
|
+
return TestWalker.someIncompleteTests(testObject => {
|
|
1115
|
+
if (fieldName) {
|
|
1116
|
+
return matchingFieldName(testObject, fieldName);
|
|
1117
|
+
}
|
|
1118
|
+
return true;
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
static pluckTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1122
|
+
if (!root)
|
|
1123
|
+
return;
|
|
1124
|
+
vestRuntime.Walker.pluck(root, isolate => {
|
|
1125
|
+
IsolateTest.isX(isolate);
|
|
1126
|
+
return predicate(isolate);
|
|
1127
|
+
}, IsolateTest.is);
|
|
1128
|
+
}
|
|
1129
|
+
static resetField(fieldName) {
|
|
1130
|
+
TestWalker.walkTests(testObject => {
|
|
1131
|
+
if (matchingFieldName(testObject, fieldName)) {
|
|
1132
|
+
testObject.reset();
|
|
1133
|
+
}
|
|
1134
|
+
}, TestWalker.defaultRoot());
|
|
1135
|
+
}
|
|
1136
|
+
static removeTestByFieldName(fieldName, root = TestWalker.defaultRoot()) {
|
|
1137
|
+
TestWalker.pluckTests(testObject => {
|
|
1138
|
+
return matchingFieldName(testObject, fieldName);
|
|
1139
|
+
}, root);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Checks that a given test object matches the currently specified severity level
|
|
1145
|
+
*/
|
|
1146
|
+
function nonMatchingSeverityProfile(severity, testObject) {
|
|
1147
|
+
return vestUtils.either(severity === Severity.WARNINGS, testObject.warns());
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* The difference between this file and hasFailures is that hasFailures uses the static
|
|
1152
|
+
* summary object, while this one uses the actual validation state
|
|
1153
|
+
*/
|
|
1154
|
+
function hasErrorsByTestObjects(fieldName) {
|
|
1155
|
+
return hasFailuresByTestObjects(Severity.ERRORS, fieldName);
|
|
1156
|
+
}
|
|
1157
|
+
function hasFailuresByTestObjects(severityKey, fieldName) {
|
|
1158
|
+
return TestWalker.someTests(testObject => {
|
|
1159
|
+
return hasFailuresByTestObject(testObject, severityKey, fieldName);
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
function hasGroupFailuresByTestObjects(severityKey, groupName, fieldName) {
|
|
1163
|
+
return TestWalker.someTests(testObject => {
|
|
1164
|
+
if (nonMatchingGroupName(testObject, groupName)) {
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
return hasFailuresByTestObject(testObject, severityKey, fieldName);
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Determines whether a certain test profile has failures.
|
|
1172
|
+
*/
|
|
1173
|
+
function hasFailuresByTestObject(testObject, severityKey, fieldName) {
|
|
1174
|
+
if (!testObject.hasFailures()) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
if (nonMatchingSeverityProfile(severityKey, testObject)) {
|
|
1181
|
+
return false;
|
|
1182
|
+
}
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
exports.Modes = void 0;
|
|
1187
|
+
(function (Modes) {
|
|
1188
|
+
Modes["EAGER"] = "EAGER";
|
|
1189
|
+
Modes["ALL"] = "ALL";
|
|
1190
|
+
Modes["ONE"] = "ONE";
|
|
1191
|
+
})(exports.Modes || (exports.Modes = {}));
|
|
1192
|
+
/**
|
|
1193
|
+
* Sets the current execution mode for the current suite.
|
|
1194
|
+
*
|
|
1195
|
+
* Supported modes:
|
|
1196
|
+
* - `EAGER` - (default) Runs all tests, but stops on first failure for each given field.
|
|
1197
|
+
* - `ALL` - Runs all tests, regardless of failures.
|
|
1198
|
+
* - `ONE` - Stops suite execution on first failure of any field.
|
|
1199
|
+
*
|
|
1200
|
+
* @example
|
|
1201
|
+
* ```js
|
|
1202
|
+
* import {Modes, create} from 'vest';
|
|
1203
|
+
*
|
|
1204
|
+
* const suite = create('suite_name', () => {
|
|
1205
|
+
* vest.mode(Modes.ALL);
|
|
1206
|
+
*
|
|
1207
|
+
* // ...
|
|
1208
|
+
* });
|
|
1209
|
+
* ```
|
|
1210
|
+
* @param 'ALL' | 'EAGER' | 'ONE' mode - The mode to set.
|
|
1211
|
+
*/
|
|
1212
|
+
// @vx-allow use-use
|
|
1213
|
+
function mode(mode) {
|
|
1214
|
+
const [, setMode] = useMode();
|
|
1215
|
+
setMode(mode);
|
|
1216
|
+
}
|
|
1217
|
+
function useIsMode(mode) {
|
|
1218
|
+
const [currentMode] = useMode();
|
|
1219
|
+
return currentMode === mode;
|
|
1220
|
+
}
|
|
1221
|
+
function useIsEager() {
|
|
1222
|
+
return useIsMode(exports.Modes.EAGER);
|
|
1223
|
+
}
|
|
1224
|
+
function useIsOne() {
|
|
1225
|
+
return useIsMode(exports.Modes.ONE);
|
|
1226
|
+
}
|
|
1227
|
+
function useShouldSkipBasedOnMode(testObject) {
|
|
1228
|
+
if (useIsOne()) {
|
|
1229
|
+
return hasErrorsByTestObjects();
|
|
1230
|
+
}
|
|
1231
|
+
if (useIsEager()) {
|
|
1232
|
+
return hasErrorsByTestObjects(testObject.fieldName);
|
|
1233
|
+
}
|
|
1234
|
+
return false;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const SuiteContext = context.createCascade((ctxRef, parentContext) => {
|
|
1238
|
+
if (parentContext) {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
return vestUtils.assign({
|
|
1242
|
+
exclusion: {
|
|
1243
|
+
tests: {},
|
|
1244
|
+
groups: {},
|
|
1245
|
+
},
|
|
1246
|
+
inclusion: {},
|
|
1247
|
+
mode: vestUtils.tinyState.createTinyState(exports.Modes.EAGER),
|
|
1248
|
+
testMemoCache,
|
|
1249
|
+
}, ctxRef);
|
|
1250
|
+
});
|
|
1251
|
+
function useCurrentTest(msg) {
|
|
1252
|
+
return SuiteContext.useX(msg).currentTest;
|
|
1253
|
+
}
|
|
1254
|
+
function useGroupName() {
|
|
1255
|
+
return SuiteContext.useX().groupName;
|
|
1256
|
+
}
|
|
1257
|
+
function useExclusion(hookError) {
|
|
1258
|
+
return SuiteContext.useX(hookError).exclusion;
|
|
1259
|
+
}
|
|
1260
|
+
function useInclusion() {
|
|
1261
|
+
return SuiteContext.useX().inclusion;
|
|
1262
|
+
}
|
|
1263
|
+
function useMode() {
|
|
1264
|
+
return SuiteContext.useX().mode();
|
|
1265
|
+
}
|
|
1266
|
+
function useSkipped() {
|
|
1267
|
+
var _a;
|
|
1268
|
+
return (_a = SuiteContext.useX().skipped) !== null && _a !== void 0 ? _a : false;
|
|
1269
|
+
}
|
|
1270
|
+
function useOmitted() {
|
|
1271
|
+
var _a;
|
|
1272
|
+
return (_a = SuiteContext.useX().omitted) !== null && _a !== void 0 ? _a : false;
|
|
1273
|
+
}
|
|
1274
|
+
const testMemoCache = vestUtils.cache(10);
|
|
1275
|
+
function useTestMemoCache() {
|
|
1276
|
+
return SuiteContext.useX().testMemoCache;
|
|
1296
1277
|
}
|
|
1278
|
+
|
|
1297
1279
|
/**
|
|
1298
|
-
*
|
|
1280
|
+
* This module gets triggered once the suite is done running its sync tests.
|
|
1281
|
+
*
|
|
1282
|
+
* It goes over all the tests in the state, and checks if they need to be omitted.
|
|
1299
1283
|
*/
|
|
1300
|
-
function
|
|
1301
|
-
|
|
1302
|
-
|
|
1284
|
+
function useOmitOptionalFields() {
|
|
1285
|
+
const root = vestRuntime.VestRuntime.useAvailableRoot();
|
|
1286
|
+
const emit = vestRuntime.VestRuntime.useEmit();
|
|
1287
|
+
const optionalFields = root === null || root === void 0 ? void 0 : root.getOptionalFields();
|
|
1288
|
+
// If there are no optional fields, we don't need to do anything
|
|
1289
|
+
if (vestUtils.isEmpty(optionalFields)) {
|
|
1303
1290
|
return;
|
|
1304
1291
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1292
|
+
// Create an object to store the fields that need to be omitted
|
|
1293
|
+
const shouldOmit = new Set();
|
|
1294
|
+
// iterate over each of the tests in the state
|
|
1295
|
+
TestWalker.walkTests(testObject => {
|
|
1296
|
+
if (testObject.isPending()) {
|
|
1307
1297
|
return;
|
|
1308
1298
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1299
|
+
// If we already added the current field (not this test specifically)
|
|
1300
|
+
// no need for further checks, go and omit the test
|
|
1301
|
+
if (vestUtils.hasOwnProperty(shouldOmit, testObject.fieldName)) {
|
|
1302
|
+
verifyAndOmit(testObject);
|
|
1303
|
+
}
|
|
1304
|
+
else {
|
|
1305
|
+
// check if the field has an optional function
|
|
1306
|
+
// if so, run it and verify/omit the test
|
|
1307
|
+
runOptionalConfig(testObject);
|
|
1308
|
+
}
|
|
1311
1309
|
});
|
|
1310
|
+
emit(Events.DONE_TEST_OMISSION_PASS);
|
|
1311
|
+
function verifyAndOmit(testObject) {
|
|
1312
|
+
if (shouldOmit.has(testObject.fieldName)) {
|
|
1313
|
+
testObject.omit();
|
|
1314
|
+
root === null || root === void 0 ? void 0 : root.setOptionalField(testObject.fieldName, current => (Object.assign(Object.assign({}, current), { applied: true })));
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
function runOptionalConfig(testObject) {
|
|
1318
|
+
// Ge the optional configuration for the given field
|
|
1319
|
+
const optionalConfig = root === null || root === void 0 ? void 0 : root.getOptionalField(testObject.fieldName);
|
|
1320
|
+
if (vestUtils.isNullish(optionalConfig)) {
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
// If the optional was set to a function or a boolean, run it and verify/omit the test
|
|
1324
|
+
if (vestUtils.optionalFunctionValue(optionalConfig.rule) === true) {
|
|
1325
|
+
shouldOmit.add(testObject.fieldName);
|
|
1326
|
+
}
|
|
1327
|
+
verifyAndOmit(testObject);
|
|
1328
|
+
}
|
|
1312
1329
|
}
|
|
1330
|
+
|
|
1313
1331
|
/**
|
|
1314
|
-
*
|
|
1332
|
+
* Runs done callback per field when async tests are finished running.
|
|
1315
1333
|
*/
|
|
1316
|
-
function
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1334
|
+
function useRunFieldCallbacks(fieldName) {
|
|
1335
|
+
const [fieldCallbacks] = useFieldCallbacks();
|
|
1336
|
+
if (fieldName &&
|
|
1337
|
+
!TestWalker.hasRemainingTests(fieldName) &&
|
|
1338
|
+
vestUtils.isArray(fieldCallbacks[fieldName])) {
|
|
1339
|
+
vestUtils.callEach(fieldCallbacks[fieldName]);
|
|
1321
1340
|
}
|
|
1322
|
-
return false;
|
|
1323
1341
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
return !groupName;
|
|
1342
|
+
/**
|
|
1343
|
+
* Runs unlabelled done callback when async tests are finished running.
|
|
1344
|
+
*/
|
|
1345
|
+
function useRunDoneCallbacks() {
|
|
1346
|
+
const [doneCallbacks] = useDoneCallbacks();
|
|
1347
|
+
vestUtils.callEach(doneCallbacks);
|
|
1331
1348
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1349
|
+
|
|
1350
|
+
// eslint-disable-next-line max-statements
|
|
1351
|
+
function useInitVestBus() {
|
|
1352
|
+
const VestBus = vestRuntime.VestRuntime.useBus();
|
|
1353
|
+
// Report a the completion of a test. There may be other tests with the same
|
|
1354
|
+
// name that are still running, or not yet started.
|
|
1355
|
+
on(Events.TEST_COMPLETED, (testObject) => {
|
|
1356
|
+
if (testObject.isCanceled()) {
|
|
1357
|
+
return;
|
|
1338
1358
|
}
|
|
1359
|
+
useRunFieldCallbacks(testObject.fieldName);
|
|
1360
|
+
if (!TestWalker.hasRemainingTests()) {
|
|
1361
|
+
// When no more tests are running, emit the done event
|
|
1362
|
+
VestBus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
on(Events.TEST_RUN_STARTED, () => {
|
|
1366
|
+
/* Let's just invalidate the suite cache for now */
|
|
1367
|
+
});
|
|
1368
|
+
on(Events.DONE_TEST_OMISSION_PASS, () => {
|
|
1369
|
+
/* We NEED to refresh the cache here. Don't ask */
|
|
1370
|
+
});
|
|
1371
|
+
// Called when all the tests, including async, are done running
|
|
1372
|
+
on(Events.ALL_RUNNING_TESTS_FINISHED, () => {
|
|
1373
|
+
// Small optimization. We don't need to run this if there are no async tests
|
|
1374
|
+
// The reason is that we run this function immediately after the suite callback
|
|
1375
|
+
// is run, so if the suite is only comprised of sync tests, we don't need to
|
|
1376
|
+
// run this function twice since we know for a fact the state is up to date
|
|
1377
|
+
if (TestWalker.someTests(test => test.isAsyncTest())) {
|
|
1378
|
+
useOmitOptionalFields();
|
|
1379
|
+
}
|
|
1380
|
+
useRunDoneCallbacks();
|
|
1381
|
+
});
|
|
1382
|
+
on(Events.RESET_FIELD, (fieldName) => {
|
|
1383
|
+
TestWalker.resetField(fieldName);
|
|
1384
|
+
});
|
|
1385
|
+
on(Events.SUITE_RUN_STARTED, () => {
|
|
1386
|
+
useResetCallbacks();
|
|
1387
|
+
});
|
|
1388
|
+
on(Events.SUITE_CALLBACK_RUN_FINISHED, () => {
|
|
1389
|
+
useOmitOptionalFields();
|
|
1390
|
+
});
|
|
1391
|
+
on(Events.REMOVE_FIELD, (fieldName) => {
|
|
1392
|
+
TestWalker.removeTestByFieldName(fieldName);
|
|
1393
|
+
});
|
|
1394
|
+
on(Events.RESET_SUITE, () => {
|
|
1395
|
+
useResetSuite();
|
|
1396
|
+
});
|
|
1397
|
+
return VestBus;
|
|
1398
|
+
function on(event, cb) {
|
|
1399
|
+
VestBus.on(event, (...args) => {
|
|
1400
|
+
// This is more concise, but it might be an overkill
|
|
1401
|
+
// if we're adding events that don't need to invalidate the cache
|
|
1402
|
+
useExpireSuiteResultCache();
|
|
1403
|
+
cb(...args);
|
|
1404
|
+
});
|
|
1339
1405
|
}
|
|
1340
|
-
return false;
|
|
1341
1406
|
}
|
|
1342
1407
|
|
|
1343
1408
|
/**
|
|
1344
|
-
*
|
|
1409
|
+
* Conditionally includes a field for testing, based on specified criteria.
|
|
1410
|
+
*
|
|
1411
|
+
* @param {string} fieldName - The name of the field to include for testing.
|
|
1345
1412
|
*
|
|
1346
1413
|
* @example
|
|
1414
|
+
* include('confirm').when('password');
|
|
1415
|
+
* // Includes the "confirm" field for testing when the "password" field is included
|
|
1347
1416
|
*
|
|
1348
|
-
*
|
|
1349
|
-
*
|
|
1350
|
-
*
|
|
1417
|
+
* include('confirm').when(someValue);
|
|
1418
|
+
* // Includes the "confirm" field for testing when the value of `someValue` is true
|
|
1419
|
+
*
|
|
1420
|
+
* include('confirm').when(() => someValue);
|
|
1421
|
+
* // Includes the "confirm" field for testing when the callback function returns true
|
|
1422
|
+
*
|
|
1423
|
+
* include('username').when(result => result.hasErrors('username'));
|
|
1424
|
+
* // Includes the "username" field for testing when there are errors associated with it in the current suite result
|
|
1351
1425
|
*/
|
|
1352
|
-
|
|
1353
|
-
vestUtils.invariant(vestUtils.isStringValue(groupName), groupErrorMsg('name must be a string'));
|
|
1354
|
-
vestUtils.invariant(vestUtils.isFunction(tests), groupErrorMsg('callback must be a function'));
|
|
1355
|
-
// Running with the context applied
|
|
1356
|
-
isolate({ type: IsolateTypes.GROUP }, function () {
|
|
1357
|
-
context.run({ groupName: groupName }, tests);
|
|
1358
|
-
});
|
|
1359
|
-
}
|
|
1360
|
-
function groupErrorMsg(error) {
|
|
1361
|
-
return "Wrong arguments passed to group. Group ".concat(error, ".");
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1426
|
+
// @vx-allow use-use
|
|
1364
1427
|
function include(fieldName) {
|
|
1365
|
-
|
|
1366
|
-
|
|
1428
|
+
const inclusion = useInclusion();
|
|
1429
|
+
const exclusion = useExclusion();
|
|
1367
1430
|
vestUtils.invariant(vestUtils.isStringValue(fieldName));
|
|
1368
1431
|
inclusion[fieldName] = vestUtils.defaultTo(exclusion.tests[fieldName], true);
|
|
1369
|
-
return { when
|
|
1432
|
+
return { when };
|
|
1433
|
+
/**
|
|
1434
|
+
* Specifies the inclusion criteria for the field in `include` function.
|
|
1435
|
+
*/
|
|
1370
1436
|
function when(condition) {
|
|
1371
|
-
|
|
1372
|
-
|
|
1437
|
+
const inclusion = useInclusion();
|
|
1438
|
+
const exclusion = useExclusion();
|
|
1373
1439
|
// This callback will run as part of the "isExcluded" series of checks
|
|
1374
|
-
inclusion[fieldName] =
|
|
1440
|
+
inclusion[fieldName] = () => {
|
|
1375
1441
|
if (vestUtils.hasOwnProperty(exclusion.tests, fieldName)) {
|
|
1376
1442
|
// I suspect this code is technically unreachable because
|
|
1377
1443
|
// if there are any skip/only rules applied to the current
|
|
@@ -1381,123 +1447,66 @@ function include(fieldName) {
|
|
|
1381
1447
|
if (vestUtils.isStringValue(condition)) {
|
|
1382
1448
|
return Boolean(exclusion.tests[condition]);
|
|
1383
1449
|
}
|
|
1384
|
-
return vestUtils.optionalFunctionValue(condition, vestUtils.optionalFunctionValue(
|
|
1450
|
+
return vestUtils.optionalFunctionValue(condition, vestUtils.optionalFunctionValue(useCreateSuiteResult));
|
|
1385
1451
|
};
|
|
1386
1452
|
}
|
|
1387
1453
|
}
|
|
1388
1454
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
* enforce(data.username).isNotBlank();
|
|
1401
|
-
* });
|
|
1402
|
-
*
|
|
1403
|
-
* test('username', 'username is too short', () => {
|
|
1404
|
-
* enforce(data.username).longerThan(2);
|
|
1405
|
-
* });
|
|
1406
|
-
* });
|
|
1407
|
-
*/
|
|
1408
|
-
function eager() {
|
|
1409
|
-
setMode(Modes.EAGER);
|
|
1410
|
-
}
|
|
1411
|
-
function shouldSkipBasedOnMode(testObject) {
|
|
1412
|
-
return isEager() && hasErrorsByTestObjects(testObject.fieldName);
|
|
1413
|
-
}
|
|
1414
|
-
function isEager() {
|
|
1415
|
-
return isMode(Modes.EAGER);
|
|
1416
|
-
}
|
|
1417
|
-
function isMode(mode) {
|
|
1418
|
-
var currentMode = context.useX().mode;
|
|
1419
|
-
return currentMode[0] === mode;
|
|
1455
|
+
// eslint-disable-next-line max-statements
|
|
1456
|
+
function useAttemptRunTest(testObject) {
|
|
1457
|
+
useVerifyTestRun(testObject);
|
|
1458
|
+
if (testObject.isUntested()) {
|
|
1459
|
+
return useRunTest(testObject);
|
|
1460
|
+
}
|
|
1461
|
+
if (!testObject.isNonActionable()) {
|
|
1462
|
+
vestUtils.deferThrow(vestUtils.text(ErrorStrings.UNEXPECTED_TEST_REGISTRATION_ERROR, {
|
|
1463
|
+
testObject: JSON.stringify(testObject),
|
|
1464
|
+
}));
|
|
1465
|
+
}
|
|
1420
1466
|
}
|
|
1421
|
-
function
|
|
1422
|
-
|
|
1423
|
-
mode[0] = nextMode;
|
|
1467
|
+
function runSyncTest(testObject) {
|
|
1468
|
+
return SuiteContext.run({ currentTest: testObject }, () => testObject.run());
|
|
1424
1469
|
}
|
|
1425
|
-
|
|
1426
1470
|
/**
|
|
1427
|
-
*
|
|
1428
|
-
*
|
|
1429
|
-
* @example
|
|
1430
|
-
*
|
|
1431
|
-
* omitWhen(res => res.hasErrors('username'), () => {
|
|
1432
|
-
* test('username', 'User already taken', async () => await doesUserExist(username)
|
|
1433
|
-
* });
|
|
1471
|
+
* runs test, if async - adds to pending array
|
|
1434
1472
|
*/
|
|
1435
|
-
function
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
//
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
1458
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
1459
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
1460
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
1461
|
-
***************************************************************************** */
|
|
1462
|
-
|
|
1463
|
-
function __spreadArray(to, from, pack) {
|
|
1464
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
1465
|
-
if (ar || !(i in from)) {
|
|
1466
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
1467
|
-
ar[i] = from[i];
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
function isSameProfileTest(testObject1, testObject2) {
|
|
1474
|
-
return (testObject1.fieldName === testObject2.fieldName &&
|
|
1475
|
-
testObject1.groupName === testObject2.groupName);
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
function cancelOverriddenPendingTest(prevRunTestObject, currentRunTestObject) {
|
|
1479
|
-
if (currentRunTestObject !== prevRunTestObject &&
|
|
1480
|
-
isSameProfileTest(prevRunTestObject, currentRunTestObject) &&
|
|
1481
|
-
prevRunTestObject.isPending()) {
|
|
1482
|
-
prevRunTestObject.cancel();
|
|
1473
|
+
function useRunTest(testObject) {
|
|
1474
|
+
const VestBus = vestRuntime.VestRuntime.useBus();
|
|
1475
|
+
// Run test callback.
|
|
1476
|
+
// If a promise is returned, set as async and
|
|
1477
|
+
// Move to pending list.
|
|
1478
|
+
const result = runSyncTest(testObject);
|
|
1479
|
+
try {
|
|
1480
|
+
// try catch for safe property access
|
|
1481
|
+
// in case object is an enforce chain
|
|
1482
|
+
if (vestUtils.isPromise(result)) {
|
|
1483
|
+
testObject.asyncTest = result;
|
|
1484
|
+
useRunAsyncTest(testObject);
|
|
1485
|
+
}
|
|
1486
|
+
else {
|
|
1487
|
+
onTestCompleted(VestBus, testObject);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
catch (e) {
|
|
1491
|
+
throw new Error(vestUtils.text(ErrorStrings.UNEXPECTED_TEST_REGISTRATION_ERROR, {
|
|
1492
|
+
testObject: JSON.stringify(testObject),
|
|
1493
|
+
error: e,
|
|
1494
|
+
}));
|
|
1483
1495
|
}
|
|
1484
1496
|
}
|
|
1485
|
-
|
|
1486
1497
|
/**
|
|
1487
1498
|
* Runs async test.
|
|
1488
1499
|
*/
|
|
1489
|
-
function
|
|
1490
|
-
|
|
1500
|
+
function useRunAsyncTest(testObject) {
|
|
1501
|
+
const { asyncTest, message } = testObject;
|
|
1491
1502
|
if (!vestUtils.isPromise(asyncTest))
|
|
1492
1503
|
return;
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
useRefreshTestObjects();
|
|
1498
|
-
emit(Events.TEST_COMPLETED, testObject);
|
|
1504
|
+
testObject.setPending();
|
|
1505
|
+
const VestBus = vestRuntime.VestRuntime.useBus();
|
|
1506
|
+
const done = vestRuntime.VestRuntime.persist(() => {
|
|
1507
|
+
onTestCompleted(VestBus, testObject);
|
|
1499
1508
|
});
|
|
1500
|
-
|
|
1509
|
+
const fail = vestRuntime.VestRuntime.persist((rejectionMessage) => {
|
|
1501
1510
|
if (testObject.isCanceled()) {
|
|
1502
1511
|
return;
|
|
1503
1512
|
}
|
|
@@ -1507,252 +1516,273 @@ function runAsyncTest(testObject) {
|
|
|
1507
1516
|
testObject.fail();
|
|
1508
1517
|
done();
|
|
1509
1518
|
});
|
|
1510
|
-
|
|
1511
|
-
|
|
1519
|
+
asyncTest.then(done, fail);
|
|
1520
|
+
}
|
|
1521
|
+
function onTestCompleted(VestBus, testObject) {
|
|
1522
|
+
// Attempts passing if the test is not already failed.
|
|
1523
|
+
// or is not canceled/omitted.
|
|
1524
|
+
testObject.pass();
|
|
1525
|
+
VestBus.emit(Events.TEST_COMPLETED, testObject);
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// @vx-allow use-use
|
|
1529
|
+
function wrapTestMemo(test) {
|
|
1530
|
+
function memo(fieldName, ...args) {
|
|
1531
|
+
const [deps, testFn, msg] = args.reverse();
|
|
1532
|
+
// Implicit dependency for better specificity
|
|
1533
|
+
const dependencies = [
|
|
1534
|
+
useSuiteId(),
|
|
1535
|
+
fieldName,
|
|
1536
|
+
vestRuntime.VestRuntime.useCurrentCursor(),
|
|
1537
|
+
].concat(deps);
|
|
1538
|
+
return useGetTestFromCache(dependencies, cacheAction);
|
|
1539
|
+
function cacheAction() {
|
|
1540
|
+
return test(fieldName, msg, testFn);
|
|
1541
|
+
}
|
|
1512
1542
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1543
|
+
return memo;
|
|
1544
|
+
}
|
|
1545
|
+
function useGetTestFromCache(dependencies, cacheAction) {
|
|
1546
|
+
const cache = useTestMemoCache();
|
|
1547
|
+
const cached = cache.get(dependencies);
|
|
1548
|
+
if (vestUtils.isNull(cached)) {
|
|
1549
|
+
// cache miss
|
|
1550
|
+
return cache(dependencies, cacheAction);
|
|
1551
|
+
}
|
|
1552
|
+
const [, cachedValue] = cached;
|
|
1553
|
+
if (cachedValue.isCanceled()) {
|
|
1554
|
+
// cache hit, but test is canceled
|
|
1555
|
+
cache.invalidate(dependencies);
|
|
1556
|
+
return cache(dependencies, cacheAction);
|
|
1557
|
+
}
|
|
1558
|
+
IsolateTest.setNode(cachedValue);
|
|
1559
|
+
return cachedValue;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// @vx-allow use-use
|
|
1563
|
+
function vestTest(fieldName, ...args) {
|
|
1564
|
+
const [message, testFn, key] = (vestUtils.isFunction(args[1]) ? args : [undefined, ...args]);
|
|
1565
|
+
validateTestParams(fieldName, testFn);
|
|
1566
|
+
const groupName = useGroupName();
|
|
1567
|
+
const emit = vestRuntime.VestRuntime.useEmit();
|
|
1568
|
+
const testObjectInput = { fieldName, groupName, key, message, testFn };
|
|
1569
|
+
// This invalidates the suite cache.
|
|
1570
|
+
emit(Events.TEST_RUN_STARTED);
|
|
1571
|
+
return IsolateTest.create(useAttemptRunTest, testObjectInput);
|
|
1572
|
+
}
|
|
1573
|
+
const test = vestUtils.assign(vestTest, {
|
|
1574
|
+
memo: wrapTestMemo(vestTest),
|
|
1575
|
+
});
|
|
1576
|
+
function validateTestParams(fieldName, testFn) {
|
|
1577
|
+
const fnName = 'test';
|
|
1578
|
+
vestUtils.invariant(vestUtils.isStringValue(fieldName), vestUtils.text(ErrorStrings.INVALID_PARAM_PASSED_TO_FUNCTION, {
|
|
1579
|
+
fn_name: fnName,
|
|
1580
|
+
param: 'fieldName',
|
|
1581
|
+
expected: 'string',
|
|
1582
|
+
}));
|
|
1583
|
+
vestUtils.invariant(vestUtils.isFunction(testFn), vestUtils.text(ErrorStrings.INVALID_PARAM_PASSED_TO_FUNCTION, {
|
|
1584
|
+
fn_name: fnName,
|
|
1585
|
+
param: 'callback',
|
|
1586
|
+
expected: 'function',
|
|
1587
|
+
}));
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
function getTypedMethods() {
|
|
1591
|
+
return {
|
|
1592
|
+
group,
|
|
1593
|
+
include,
|
|
1594
|
+
omitWhen,
|
|
1595
|
+
only,
|
|
1596
|
+
optional,
|
|
1597
|
+
skip,
|
|
1598
|
+
skipWhen,
|
|
1599
|
+
test,
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
function useDeferDoneCallback(doneCallback, fieldName) {
|
|
1604
|
+
const [, setFieldCallbacks] = useFieldCallbacks();
|
|
1605
|
+
const [, setDoneCallbacks] = useDoneCallbacks();
|
|
1606
|
+
if (fieldName) {
|
|
1607
|
+
setFieldCallbacks(fieldCallbacks => vestUtils.assign(fieldCallbacks, {
|
|
1608
|
+
[fieldName]: (fieldCallbacks[fieldName] || []).concat(doneCallback),
|
|
1609
|
+
}));
|
|
1610
|
+
return;
|
|
1517
1611
|
}
|
|
1612
|
+
setDoneCallbacks(doneCallbacks => doneCallbacks.concat(doneCallback));
|
|
1518
1613
|
}
|
|
1519
1614
|
|
|
1520
1615
|
/**
|
|
1521
|
-
*
|
|
1616
|
+
* DONE is here and not in its own module to prevent circular dependency issues.
|
|
1522
1617
|
*/
|
|
1523
|
-
function
|
|
1524
|
-
|
|
1618
|
+
function shouldSkipDoneRegistration(callback, fieldName, output) {
|
|
1619
|
+
var _a;
|
|
1620
|
+
// If we do not have any test runs for the current field
|
|
1621
|
+
return !!(!vestUtils.isFunction(callback) ||
|
|
1622
|
+
(fieldName && vestUtils.numberEquals((_a = output.tests[fieldName]) === null || _a === void 0 ? void 0 : _a.testCount, 0)));
|
|
1525
1623
|
}
|
|
1526
1624
|
|
|
1625
|
+
function useSuiteRunResult() {
|
|
1626
|
+
return Object.freeze(vestUtils.assign({
|
|
1627
|
+
done: vestRuntime.VestRuntime.persist(done),
|
|
1628
|
+
}, useCreateSuiteResult()));
|
|
1629
|
+
}
|
|
1527
1630
|
/**
|
|
1528
|
-
* Registers
|
|
1631
|
+
* Registers done callbacks.
|
|
1632
|
+
* @register {Object} Vest output object.
|
|
1529
1633
|
*/
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
try {
|
|
1537
|
-
// try catch for safe property access
|
|
1538
|
-
// in case object is an enforce chain
|
|
1539
|
-
if (vestUtils.isPromise(result)) {
|
|
1540
|
-
testObject.asyncTest = result;
|
|
1541
|
-
testObject.setPending();
|
|
1542
|
-
runAsyncTest(testObject);
|
|
1543
|
-
}
|
|
1544
|
-
else {
|
|
1545
|
-
bus.emit(Events.TEST_COMPLETED, testObject);
|
|
1546
|
-
}
|
|
1634
|
+
// @vx-allow use-use
|
|
1635
|
+
function done(...args) {
|
|
1636
|
+
const [callback, fieldName] = args.reverse();
|
|
1637
|
+
const output = useSuiteRunResult();
|
|
1638
|
+
if (shouldSkipDoneRegistration(callback, fieldName, output)) {
|
|
1639
|
+
return output;
|
|
1547
1640
|
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1641
|
+
const useDoneCallback = () => callback(useCreateSuiteResult());
|
|
1642
|
+
if (!TestWalker.hasRemainingTests(fieldName)) {
|
|
1643
|
+
useDoneCallback();
|
|
1644
|
+
return output;
|
|
1550
1645
|
}
|
|
1646
|
+
useDeferDoneCallback(useDoneCallback, fieldName);
|
|
1647
|
+
return output;
|
|
1551
1648
|
}
|
|
1552
1649
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
* It is used to ensure that tests are not called in a different order than
|
|
1556
|
-
* they were called in the previous run.
|
|
1557
|
-
* If they are, it will throw a deferred error unless explicitly allowed.
|
|
1558
|
-
*
|
|
1559
|
-
* For now it seems pretty safe, and it covers most common use cases, but it can
|
|
1560
|
-
* be improved in the future both in terms of performance and scenarios it covers.
|
|
1561
|
-
*/
|
|
1562
|
-
// eslint-disable-next-line max-statements, max-lines-per-function
|
|
1563
|
-
function useTestAtCursor(newTestObject) {
|
|
1564
|
-
var testObjects = useTestObjects()[0];
|
|
1565
|
-
var prevTests = testObjects.prev;
|
|
1566
|
-
if (vestUtils.isEmpty(prevTests)) {
|
|
1567
|
-
useSetTestAtCursor(newTestObject);
|
|
1568
|
-
return newTestObject;
|
|
1569
|
-
}
|
|
1570
|
-
var prevTest = useGetTestAtCursor(prevTests);
|
|
1571
|
-
if (!vestUtils.isNullish(newTestObject.key)) {
|
|
1572
|
-
var nextTest_1 = handleKeyTest(newTestObject.key, newTestObject);
|
|
1573
|
-
useSetTestAtCursor(nextTest_1);
|
|
1574
|
-
return nextTest_1;
|
|
1575
|
-
}
|
|
1576
|
-
if (testReorderDetected(prevTest, newTestObject)) {
|
|
1577
|
-
throwTestOrderError(prevTest, newTestObject);
|
|
1578
|
-
removeAllNextTestsInIsolate();
|
|
1579
|
-
// Need to see if this has any effect at all.
|
|
1580
|
-
prevTest = null;
|
|
1581
|
-
}
|
|
1582
|
-
var nextTest = vestUtils.defaultTo(prevTest, newTestObject);
|
|
1583
|
-
useSetTestAtCursor(nextTest);
|
|
1584
|
-
return nextTest;
|
|
1585
|
-
}
|
|
1586
|
-
function removeAllNextTestsInIsolate() {
|
|
1587
|
-
var cursorAt = useCursor().current();
|
|
1588
|
-
// We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
|
|
1589
|
-
// since we're only touching the "prev" state. The reason we still use the setter function is
|
|
1590
|
-
// to prevent future headaches if we ever do need to rely on prev-state immutability.
|
|
1591
|
-
useSetTests(function (current) {
|
|
1592
|
-
current.splice(cursorAt);
|
|
1593
|
-
return current;
|
|
1594
|
-
});
|
|
1650
|
+
function validateSuiteCallback(suiteCallback) {
|
|
1651
|
+
vestUtils.invariant(vestUtils.isFunction(suiteCallback), ErrorStrings.SUITE_MUST_BE_INITIALIZED_WITH_FUNCTION);
|
|
1595
1652
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1653
|
+
|
|
1654
|
+
// @vx-allow use-use
|
|
1655
|
+
function createSuite(...args) {
|
|
1656
|
+
const [suiteCallback, suiteName] = args.reverse();
|
|
1657
|
+
validateSuiteCallback(suiteCallback);
|
|
1658
|
+
// Create a stateRef for the suite
|
|
1659
|
+
// It holds the suite's persisted values that may remain between runs.
|
|
1660
|
+
const stateRef = useCreateVestState({ suiteName });
|
|
1661
|
+
function suite(...args) {
|
|
1662
|
+
return SuiteContext.run({}, () => {
|
|
1663
|
+
// eslint-disable-next-line vest-internal/use-use
|
|
1664
|
+
const emit = vestRuntime.VestRuntime.useEmit();
|
|
1665
|
+
emit(Events.SUITE_RUN_STARTED);
|
|
1666
|
+
return IsolateSuite.create(useRunSuiteCallback(suiteCallback, ...args));
|
|
1667
|
+
}).output;
|
|
1668
|
+
}
|
|
1669
|
+
// Assign methods to the suite
|
|
1670
|
+
// We do this within the VestRuntime so that the suite methods
|
|
1671
|
+
// will be bound to the suite's stateRef and be able to access it.
|
|
1672
|
+
return vestRuntime.VestRuntime.Run(stateRef, () => {
|
|
1673
|
+
useInitVestBus();
|
|
1674
|
+
return vestUtils.assign(
|
|
1675
|
+
// We're also binding the suite to the stateRef, so that the suite
|
|
1676
|
+
// can access the stateRef when it's called.
|
|
1677
|
+
vestRuntime.VestRuntime.persist(suite), Object.assign(Object.assign({ get: vestRuntime.VestRuntime.persist(useCreateSuiteResult), remove: vestRuntime.VestRuntime.usePrepareEmitter(Events.REMOVE_FIELD), reset: vestRuntime.VestRuntime.usePrepareEmitter(Events.RESET_SUITE), resetField: vestRuntime.VestRuntime.usePrepareEmitter(Events.RESET_FIELD) }, bindSuiteSelectors(vestRuntime.VestRuntime.persist(useCreateSuiteResult))), getTypedMethods()));
|
|
1600
1678
|
});
|
|
1601
1679
|
}
|
|
1602
|
-
function
|
|
1603
|
-
|
|
1604
|
-
return
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
}
|
|
1609
|
-
function throwTestOrderError(prevTest, newTestObject) {
|
|
1610
|
-
if (shouldAllowReorder()) {
|
|
1611
|
-
return;
|
|
1612
|
-
}
|
|
1613
|
-
vestUtils.deferThrow("Vest Critical Error: Tests called in different order than previous run.\n expected: ".concat(prevTest.fieldName, "\n received: ").concat(newTestObject.fieldName, "\n This can happen on one of two reasons:\n 1. You're using if/else statements to conditionally select tests. Instead, use \"skipWhen\".\n 2. You are iterating over a list of tests, and their order changed. Use \"each\" and a custom key prop so that Vest retains their state."));
|
|
1614
|
-
}
|
|
1615
|
-
function handleKeyTest(key, newTestObject) {
|
|
1616
|
-
var prevTestByKey = usePrevTestByKey(key);
|
|
1617
|
-
var nextTest = newTestObject;
|
|
1618
|
-
if (prevTestByKey) {
|
|
1619
|
-
nextTest = prevTestByKey;
|
|
1620
|
-
}
|
|
1621
|
-
useRetainTestKey(key, nextTest);
|
|
1622
|
-
return nextTest;
|
|
1680
|
+
function useRunSuiteCallback(suiteCallback, ...args) {
|
|
1681
|
+
const emit = vestRuntime.VestRuntime.useEmit();
|
|
1682
|
+
return () => {
|
|
1683
|
+
suiteCallback(...args);
|
|
1684
|
+
emit(Events.SUITE_CALLBACK_RUN_FINISHED);
|
|
1685
|
+
return useSuiteRunResult();
|
|
1686
|
+
};
|
|
1623
1687
|
}
|
|
1624
1688
|
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
testObject.skip();
|
|
1630
|
-
useTestAtCursor(testObject);
|
|
1631
|
-
cursor.next();
|
|
1632
|
-
return testObject;
|
|
1633
|
-
}
|
|
1634
|
-
var prevRunTest = useTestAtCursor(testObject);
|
|
1635
|
-
if (inActiveOmitWhen() || optionalFiedIsApplied(testObject.fieldName)) {
|
|
1636
|
-
prevRunTest.omit();
|
|
1637
|
-
cursor.next();
|
|
1638
|
-
return prevRunTest;
|
|
1639
|
-
}
|
|
1640
|
-
if (isExcluded(testObject)) {
|
|
1641
|
-
// We're forcing skipping the pending test
|
|
1642
|
-
// if we're directly within a skipWhen block
|
|
1643
|
-
// This mostly means that we're probably giving
|
|
1644
|
-
// up on this async test intentionally.
|
|
1645
|
-
prevRunTest.skip(isExcludedIndividually());
|
|
1646
|
-
cursor.next();
|
|
1647
|
-
return prevRunTest;
|
|
1648
|
-
}
|
|
1649
|
-
cancelOverriddenPendingTest(prevRunTest, testObject);
|
|
1650
|
-
useSetTestAtCursor(testObject);
|
|
1651
|
-
registerTestObjectByTier(testObject);
|
|
1652
|
-
cursor.next();
|
|
1653
|
-
return testObject;
|
|
1654
|
-
}
|
|
1655
|
-
function registerTestObjectByTier(testObject) {
|
|
1656
|
-
if (testObject.isUntested()) {
|
|
1657
|
-
registerTest(testObject);
|
|
1658
|
-
}
|
|
1659
|
-
else if (vestUtils.isPromise(testObject.asyncTest)) {
|
|
1660
|
-
testObject.setPending();
|
|
1661
|
-
runAsyncTest(testObject);
|
|
1689
|
+
class IsolateEach extends vestRuntime.Isolate {
|
|
1690
|
+
constructor() {
|
|
1691
|
+
super(...arguments);
|
|
1692
|
+
this.allowReorder = true;
|
|
1662
1693
|
}
|
|
1663
1694
|
}
|
|
1664
1695
|
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
cache.invalidate(dependencies);
|
|
1686
|
-
return cache(dependencies, function () { return test(fieldName, msg, testFn); });
|
|
1687
|
-
}
|
|
1688
|
-
return registerPrevRunTest(cached[1]);
|
|
1689
|
-
}
|
|
1690
|
-
return memo;
|
|
1696
|
+
/**
|
|
1697
|
+
* Iterates over an array of items, allowing to run tests individually per item.
|
|
1698
|
+
*
|
|
1699
|
+
* Requires setting a "key" property on each item tested.
|
|
1700
|
+
*
|
|
1701
|
+
* @example
|
|
1702
|
+
*
|
|
1703
|
+
* each(itemsArray, (item) => {
|
|
1704
|
+
* test(item.name, 'Item value must not be empty', () => {
|
|
1705
|
+
* enforce(item.value).isNotEmpty();
|
|
1706
|
+
* }, item.id)
|
|
1707
|
+
* })
|
|
1708
|
+
*/
|
|
1709
|
+
function each(list, callback) {
|
|
1710
|
+
vestUtils.invariant(vestUtils.isFunction(callback), ErrorStrings.EACH_CALLBACK_MUST_BE_A_FUNCTION);
|
|
1711
|
+
IsolateEach.create(() => {
|
|
1712
|
+
list.forEach((arg, index) => {
|
|
1713
|
+
callback(arg, index);
|
|
1714
|
+
});
|
|
1715
|
+
});
|
|
1691
1716
|
}
|
|
1692
1717
|
|
|
1693
|
-
function
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
args[_i - 1] = arguments[_i];
|
|
1697
|
-
}
|
|
1698
|
-
var _a = (vestUtils.isFunction(args[1]) ? args : __spreadArray([undefined], args, true)), message = _a[0], testFn = _a[1], key = _a[2];
|
|
1699
|
-
vestUtils.invariant(vestUtils.isStringValue(fieldName), incompatibleParamsError('fieldName', 'string'));
|
|
1700
|
-
vestUtils.invariant(vestUtils.isFunction(testFn), incompatibleParamsError('Test callback', 'function'));
|
|
1701
|
-
var context$1 = context.useX();
|
|
1702
|
-
var testObject = new VestTest(fieldName, testFn, {
|
|
1703
|
-
message: message,
|
|
1704
|
-
groupName: context$1.groupName,
|
|
1705
|
-
key: key
|
|
1718
|
+
function group(groupName, callback) {
|
|
1719
|
+
return vestRuntime.Isolate.create(() => {
|
|
1720
|
+
SuiteContext.run({ groupName }, callback);
|
|
1706
1721
|
});
|
|
1707
|
-
return registerPrevRunTest(testObject);
|
|
1708
1722
|
}
|
|
1723
|
+
|
|
1709
1724
|
/**
|
|
1710
|
-
*
|
|
1725
|
+
* Creates a static suite for server-side validation.
|
|
1726
|
+
*
|
|
1727
|
+
* @param {Function} validationFn - The validation function that defines the suite's tests.
|
|
1728
|
+
* @returns {Function} - A function that runs the validations defined in the suite.
|
|
1711
1729
|
*
|
|
1712
1730
|
* @example
|
|
1731
|
+
* import { staticSuite, test, enforce } from 'vest';
|
|
1713
1732
|
*
|
|
1714
|
-
*
|
|
1715
|
-
*
|
|
1733
|
+
* const suite = staticSuite(data => {
|
|
1734
|
+
* test('username', 'username is required', () => {
|
|
1735
|
+
* enforce(data.username).isNotEmpty();
|
|
1736
|
+
* });
|
|
1716
1737
|
* });
|
|
1738
|
+
*
|
|
1739
|
+
* suite(data);
|
|
1717
1740
|
*/
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
});
|
|
1721
|
-
function incompatibleParamsError(name, expected) {
|
|
1722
|
-
return "Incompatible params passed to test function. ".concat(name, " must be a ").concat(expected);
|
|
1741
|
+
function staticSuite(suiteCallback) {
|
|
1742
|
+
return vestUtils.assign((...args) => createSuite(suiteCallback)(...args), Object.assign({}, getTypedMethods()));
|
|
1723
1743
|
}
|
|
1724
1744
|
|
|
1725
|
-
|
|
1726
|
-
;
|
|
1745
|
+
const ERROR_OUTSIDE_OF_TEST = ErrorStrings.WARN_MUST_BE_CALLED_FROM_TEST;
|
|
1727
1746
|
/**
|
|
1728
|
-
* Sets a
|
|
1747
|
+
* Sets the severity level of a test to `warn`, allowing it to fail without marking the suite as invalid.
|
|
1748
|
+
* Use this function within the body of a test to create warn-only tests.
|
|
1749
|
+
*
|
|
1750
|
+
* @returns {void}
|
|
1751
|
+
*
|
|
1752
|
+
* @example
|
|
1753
|
+
* test('password', 'Your password strength is: WEAK', () => {
|
|
1754
|
+
* warn();
|
|
1755
|
+
*
|
|
1756
|
+
* enforce(data.password).matches(/0-9/);
|
|
1757
|
+
* });
|
|
1758
|
+
*
|
|
1759
|
+
* @limitations
|
|
1760
|
+
* - The `warn` function should only be used within the body of a `test` function.
|
|
1761
|
+
* - When using `warn()` in an async test, it should be called in the synchronous portion of the test, not after an `await` call or in the Promise body.
|
|
1762
|
+
* - It is recommended to call `warn()` at the top of the test function.
|
|
1729
1763
|
*/
|
|
1764
|
+
// @vx-allow use-use
|
|
1730
1765
|
function warn() {
|
|
1731
|
-
|
|
1732
|
-
vestUtils.invariant(
|
|
1733
|
-
|
|
1766
|
+
const currentTest = useCurrentTest(ErrorStrings.HOOK_CALLED_OUTSIDE);
|
|
1767
|
+
vestUtils.invariant(currentTest, ERROR_OUTSIDE_OF_TEST);
|
|
1768
|
+
currentTest.warn();
|
|
1734
1769
|
}
|
|
1735
1770
|
|
|
1736
|
-
var VERSION = "5.0.0-dev-781e21";
|
|
1737
|
-
|
|
1738
1771
|
Object.defineProperty(exports, 'enforce', {
|
|
1739
1772
|
enumerable: true,
|
|
1740
|
-
get: function () {
|
|
1741
|
-
return n4s.enforce;
|
|
1742
|
-
}
|
|
1773
|
+
get: function () { return n4s.enforce; }
|
|
1743
1774
|
});
|
|
1744
|
-
exports.
|
|
1745
|
-
exports.context = context;
|
|
1746
|
-
exports.create = create;
|
|
1775
|
+
exports.create = createSuite;
|
|
1747
1776
|
exports.each = each;
|
|
1748
|
-
exports.eager = eager;
|
|
1749
1777
|
exports.group = group;
|
|
1750
1778
|
exports.include = include;
|
|
1779
|
+
exports.mode = mode;
|
|
1751
1780
|
exports.omitWhen = omitWhen;
|
|
1752
1781
|
exports.only = only;
|
|
1753
1782
|
exports.optional = optional;
|
|
1754
1783
|
exports.skip = skip;
|
|
1755
1784
|
exports.skipWhen = skipWhen;
|
|
1785
|
+
exports.staticSuite = staticSuite;
|
|
1756
1786
|
exports.suiteSelectors = suiteSelectors;
|
|
1757
1787
|
exports.test = test;
|
|
1758
1788
|
exports.warn = warn;
|