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