vest 5.0.0-dev-9c596e → 5.0.0-dev-ae6b14
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/dist/cjs/classnames.development.js +1 -2
- package/dist/cjs/classnames.production.js +1 -1
- package/dist/cjs/enforce/compose.development.js +1 -5
- package/dist/cjs/enforce/compose.production.js +1 -1
- package/dist/cjs/enforce/compounds.development.js +3 -6
- package/dist/cjs/enforce/compounds.production.js +1 -1
- package/dist/cjs/enforce/schema.development.js +3 -6
- package/dist/cjs/enforce/schema.production.js +1 -1
- package/dist/cjs/parser.development.js +1 -4
- package/dist/cjs/parser.production.js +1 -1
- package/dist/cjs/promisify.development.js +1 -2
- package/dist/cjs/promisify.production.js +1 -1
- package/dist/cjs/vest.development.js +516 -682
- package/dist/cjs/vest.production.js +1 -1
- package/dist/es/classnames.development.js +1 -2
- package/dist/es/classnames.production.js +1 -1
- package/dist/es/parser.development.js +1 -2
- package/dist/es/parser.production.js +1 -1
- package/dist/es/promisify.development.js +1 -2
- package/dist/es/promisify.production.js +1 -1
- package/dist/es/vest.development.js +512 -676
- package/dist/es/vest.production.js +1 -1
- package/dist/umd/classnames.development.js +1 -2
- package/dist/umd/classnames.production.js +1 -1
- package/dist/umd/enforce/compose.development.js +1 -7
- package/dist/umd/enforce/compose.production.js +1 -1
- package/dist/umd/enforce/compounds.development.js +3 -6
- package/dist/umd/enforce/compounds.production.js +1 -1
- package/dist/umd/enforce/schema.development.js +3 -6
- package/dist/umd/enforce/schema.production.js +1 -1
- package/dist/umd/parser.development.js +1 -4
- package/dist/umd/parser.production.js +1 -1
- package/dist/umd/promisify.development.js +1 -2
- package/dist/umd/promisify.production.js +1 -1
- package/dist/umd/vest.development.js +520 -687
- package/dist/umd/vest.production.js +1 -1
- package/package.json +137 -136
- package/testUtils/TVestMock.ts +1 -1
- package/testUtils/asVestTest.ts +9 -0
- package/types/classnames.d.ts +82 -4
- package/types/classnames.d.ts.map +1 -1
- package/types/parser.d.ts +82 -4
- package/types/parser.d.ts.map +1 -1
- package/types/promisify.d.ts +82 -4
- package/types/promisify.d.ts.map +1 -1
- package/types/vest.d.ts +152 -140
- package/types/vest.d.ts.map +1 -1
|
@@ -1,29 +1,60 @@
|
|
|
1
1
|
export { enforce } from 'n4s';
|
|
2
|
-
import {
|
|
2
|
+
import { isArray, isStringValue, asArray, cache, tinyState, seq, assign, bindNot, either, defaultTo, isPositive, optionalFunctionValue, hasOwnProperty, isNullish, deferThrow, text, StateMachine, isUndefined, isPromise, invariant, isEmpty, callEach, isNull, isFunction, numberEquals } from 'vest-utils';
|
|
3
|
+
import { VestRuntime, Isolate, Reconciler, Walker } from 'vestjs-runtime';
|
|
3
4
|
import { createCascade } from 'context';
|
|
4
5
|
|
|
5
6
|
var OptionalFieldTypes;
|
|
6
7
|
(function (OptionalFieldTypes) {
|
|
7
|
-
OptionalFieldTypes[OptionalFieldTypes["
|
|
8
|
-
OptionalFieldTypes[OptionalFieldTypes["
|
|
8
|
+
OptionalFieldTypes[OptionalFieldTypes["CUSTOM_LOGIC"] = 0] = "CUSTOM_LOGIC";
|
|
9
|
+
OptionalFieldTypes[OptionalFieldTypes["AUTO"] = 1] = "AUTO";
|
|
9
10
|
})(OptionalFieldTypes || (OptionalFieldTypes = {}));
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
// @vx-allow use-use
|
|
13
|
+
function optional(optionals) {
|
|
14
|
+
const suiteRoot = VestRuntime.useAvailableRoot();
|
|
15
|
+
// There are two types of optional field declarations:
|
|
16
|
+
// 1 AUTO: Vest will automatically determine whether the field should be omitted
|
|
17
|
+
// Based on the current run. Vest will ommit "auto" added fields without any
|
|
18
|
+
// configuration if their tests did not run at all in the suite.
|
|
19
|
+
//
|
|
20
|
+
// 2 Custom logic: Vest will determine whether they should fail based on the custom
|
|
21
|
+
// logic supplied by the user.
|
|
22
|
+
// AUTO case (field name)
|
|
23
|
+
if (isArray(optionals) || isStringValue(optionals)) {
|
|
24
|
+
asArray(optionals).forEach(optionalField => {
|
|
25
|
+
suiteRoot.setOptionalField(optionalField, () => ({
|
|
26
|
+
type: OptionalFieldTypes.AUTO,
|
|
27
|
+
applied: false,
|
|
28
|
+
rule: null,
|
|
29
|
+
}));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// CUSTOM_LOGIC case (function or boolean)
|
|
34
|
+
for (const field in optionals) {
|
|
35
|
+
const value = optionals[field];
|
|
36
|
+
suiteRoot.setOptionalField(field, () => ({
|
|
37
|
+
type: OptionalFieldTypes.CUSTOM_LOGIC,
|
|
38
|
+
rule: value,
|
|
39
|
+
applied: value === true,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function useIsOptionalFiedApplied(fieldName) {
|
|
45
|
+
var _a, _b, _c;
|
|
46
|
+
if (!fieldName) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return ((_c = (_b = (_a = 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);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var Modes;
|
|
53
|
+
(function (Modes) {
|
|
54
|
+
Modes["EAGER"] = "EAGER";
|
|
55
|
+
Modes["ALL"] = "ALL";
|
|
56
|
+
Modes["ONE"] = "ONE";
|
|
57
|
+
})(Modes || (Modes = {}));
|
|
27
58
|
|
|
28
59
|
var Events;
|
|
29
60
|
(function (Events) {
|
|
@@ -34,230 +65,133 @@ var Events;
|
|
|
34
65
|
Events["RESET_FIELD"] = "reset_field";
|
|
35
66
|
Events["RESET_SUITE"] = "reset_suite";
|
|
36
67
|
Events["SUITE_RUN_STARTED"] = "suite_run_started";
|
|
68
|
+
Events["SUITE_CALLBACK_RUN_FINISHED"] = "SUITE_CALLBACK_RUN_FINISHED";
|
|
69
|
+
Events["DONE_TEST_OMISSION_PASS"] = "DONE_TEST_OMISSION_PASS";
|
|
37
70
|
})(Events || (Events = {}));
|
|
38
71
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
let broke = false;
|
|
45
|
-
for (const isolate of startNode.children) {
|
|
46
|
-
if (broke) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (isNullish(visitOnly) || optionalFunctionValue(visitOnly, isolate)) {
|
|
50
|
-
callback(isolate, breakout);
|
|
51
|
-
}
|
|
52
|
-
if (broke) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
walk(isolate, (child, innerBreakout) => {
|
|
56
|
-
callback(child, () => {
|
|
57
|
-
innerBreakout();
|
|
58
|
-
breakout();
|
|
59
|
-
});
|
|
60
|
-
}, visitOnly);
|
|
61
|
-
}
|
|
62
|
-
function breakout() {
|
|
63
|
-
broke = true;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function some(startNode, predicate, visitOnly) {
|
|
67
|
-
let hasMatch = false;
|
|
68
|
-
walk(startNode, (node, breakout) => {
|
|
69
|
-
if (predicate(node)) {
|
|
70
|
-
breakout();
|
|
71
|
-
hasMatch = true;
|
|
72
|
-
}
|
|
73
|
-
}, visitOnly);
|
|
74
|
-
return hasMatch;
|
|
75
|
-
}
|
|
76
|
-
function has(startNode, match) {
|
|
77
|
-
return some(startNode, () => true, match);
|
|
78
|
-
}
|
|
79
|
-
function every(startNode, predicate, visitOnly) {
|
|
80
|
-
let hasMatch = true;
|
|
81
|
-
walk(startNode, (node, breakout) => {
|
|
82
|
-
if (!predicate(node)) {
|
|
83
|
-
breakout();
|
|
84
|
-
hasMatch = false;
|
|
85
|
-
}
|
|
86
|
-
}, visitOnly);
|
|
87
|
-
return hasMatch;
|
|
88
|
-
}
|
|
89
|
-
function pluck(startNode, predicate, visitOnly) {
|
|
90
|
-
walk(startNode, node => {
|
|
91
|
-
if (predicate(node) && node.parent) {
|
|
92
|
-
node.parent.removeChild(node);
|
|
93
|
-
}
|
|
94
|
-
}, visitOnly);
|
|
95
|
-
}
|
|
96
|
-
function closest(startNode, predicate) {
|
|
97
|
-
let current = startNode;
|
|
98
|
-
while (current.parent) {
|
|
99
|
-
if (predicate(current)) {
|
|
100
|
-
return current;
|
|
101
|
-
}
|
|
102
|
-
current = current.parent;
|
|
72
|
+
class IsolateSuite extends Isolate {
|
|
73
|
+
constructor() {
|
|
74
|
+
super(...arguments);
|
|
75
|
+
this.optional = {};
|
|
103
76
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class Reconciler {
|
|
111
|
-
static reconciler(currentNode, historicNode) {
|
|
112
|
-
if (isNullish(historicNode)) {
|
|
113
|
-
return currentNode;
|
|
114
|
-
}
|
|
115
|
-
return currentNode;
|
|
77
|
+
setOptionalField(fieldName, setter) {
|
|
78
|
+
const current = this.optional;
|
|
79
|
+
const currentField = current[fieldName];
|
|
80
|
+
Object.assign(current, {
|
|
81
|
+
[fieldName]: Object.assign({}, currentField, setter(currentField)),
|
|
82
|
+
});
|
|
116
83
|
}
|
|
117
|
-
|
|
84
|
+
getOptionalField(fieldName) {
|
|
118
85
|
var _a;
|
|
119
|
-
|
|
120
|
-
const historyNode = useHistoryNode();
|
|
121
|
-
let localHistoryNode = historyNode;
|
|
122
|
-
if (parent) {
|
|
123
|
-
// If we have a parent, we need to get the history node from the parent's children
|
|
124
|
-
// We take the history node from the cursor of the active node's children
|
|
125
|
-
localHistoryNode = (_a = historyNode === null || historyNode === void 0 ? void 0 : historyNode.at(useCurrentCursor())) !== null && _a !== void 0 ? _a : null;
|
|
126
|
-
}
|
|
127
|
-
const nextNode = this.reconciler(node, localHistoryNode);
|
|
128
|
-
invariant(nextNode);
|
|
129
|
-
if (Object.is(nextNode, node)) {
|
|
130
|
-
return [node, useRunAsNew(localHistoryNode, node, callback)];
|
|
131
|
-
}
|
|
132
|
-
return [nextNode, nextNode.output];
|
|
86
|
+
return (_a = this.optional[fieldName]) !== null && _a !== void 0 ? _a : {};
|
|
133
87
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const historyNode = useHistoryNode();
|
|
137
|
-
if (!historyNode || !testIsolate) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
historyNode.slice(useCurrentCursor());
|
|
141
|
-
}
|
|
142
|
-
static handleCollision(newNode, prevNode) {
|
|
143
|
-
// we should base our calculation on the key property
|
|
144
|
-
if (newNode.usesKey()) {
|
|
145
|
-
return this.handleIsolateNodeWithKey(newNode);
|
|
146
|
-
}
|
|
147
|
-
if (this.nodeReorderDetected(newNode, prevNode)) {
|
|
148
|
-
this.onNodeReorder(newNode, prevNode);
|
|
149
|
-
}
|
|
150
|
-
return prevNode ? prevNode : newNode;
|
|
151
|
-
}
|
|
152
|
-
static nodeReorderDetected(newNode, prevNode) {
|
|
153
|
-
// This is a dummy return just to satisfy the linter. Overrides will supply the real implementation.
|
|
154
|
-
return !(newNode !== null && newNode !== void 0 ? newNode : prevNode);
|
|
155
|
-
}
|
|
156
|
-
static onNodeReorder(newNode, prevNode) {
|
|
157
|
-
this.removeAllNextNodesInIsolate();
|
|
158
|
-
// This is a dummy return just to satisfy the linter. Overrides will supply the real implementation.
|
|
159
|
-
return newNode !== null && newNode !== void 0 ? newNode : prevNode;
|
|
160
|
-
}
|
|
161
|
-
static handleIsolateNodeWithKey(node) {
|
|
162
|
-
invariant(node.usesKey());
|
|
163
|
-
const prevNodeByKey = useHistoryKey(node.key);
|
|
164
|
-
let nextNode = node;
|
|
165
|
-
if (!isNullish(prevNodeByKey)) {
|
|
166
|
-
nextNode = prevNodeByKey;
|
|
167
|
-
}
|
|
168
|
-
useSetIsolateKey(node.key, node);
|
|
169
|
-
return nextNode;
|
|
88
|
+
getOptionalFields() {
|
|
89
|
+
return this.optional;
|
|
170
90
|
}
|
|
171
91
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
92
|
+
|
|
93
|
+
const suiteResultCache = cache();
|
|
94
|
+
function useCreateVestState({ suiteName, } = {}) {
|
|
95
|
+
const stateRef = {
|
|
96
|
+
doneCallbacks: tinyState.createTinyState(() => []),
|
|
97
|
+
fieldCallbacks: tinyState.createTinyState(() => ({})),
|
|
98
|
+
suiteId: seq(),
|
|
99
|
+
suiteName,
|
|
100
|
+
suiteResultCache,
|
|
101
|
+
};
|
|
102
|
+
return VestRuntime.createRef(stateRef);
|
|
103
|
+
}
|
|
104
|
+
function useX() {
|
|
105
|
+
return VestRuntime.useXAppData();
|
|
106
|
+
}
|
|
107
|
+
function useDoneCallbacks() {
|
|
108
|
+
return useX().doneCallbacks();
|
|
109
|
+
}
|
|
110
|
+
function useFieldCallbacks() {
|
|
111
|
+
return useX().fieldCallbacks();
|
|
112
|
+
}
|
|
113
|
+
function useSuiteName() {
|
|
114
|
+
return useX().suiteName;
|
|
115
|
+
}
|
|
116
|
+
function useSuiteId() {
|
|
117
|
+
return useX().suiteId;
|
|
118
|
+
}
|
|
119
|
+
function useSuiteResultCache(action) {
|
|
120
|
+
const suiteResultCache = useX().suiteResultCache;
|
|
121
|
+
return suiteResultCache([useSuiteId()], action);
|
|
122
|
+
}
|
|
123
|
+
function useExpireSuiteResultCache() {
|
|
124
|
+
const suiteResultCache = useX().suiteResultCache;
|
|
125
|
+
suiteResultCache.invalidate([useSuiteId()]);
|
|
126
|
+
}
|
|
127
|
+
function useResetCallbacks() {
|
|
128
|
+
const [, , resetDoneCallbacks] = useDoneCallbacks();
|
|
129
|
+
const [, , resetFieldCallbacks] = useFieldCallbacks();
|
|
130
|
+
resetDoneCallbacks();
|
|
131
|
+
resetFieldCallbacks();
|
|
132
|
+
}
|
|
133
|
+
function useResetSuite() {
|
|
134
|
+
useResetCallbacks();
|
|
135
|
+
VestRuntime.reset();
|
|
179
136
|
}
|
|
180
137
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.children = [];
|
|
185
|
-
this.keys = {};
|
|
186
|
-
this.parent = null;
|
|
187
|
-
this.key = null;
|
|
188
|
-
this.allowReorder = false;
|
|
189
|
-
}
|
|
190
|
-
setParent(parent) {
|
|
191
|
-
this.parent = parent;
|
|
192
|
-
return this;
|
|
193
|
-
}
|
|
194
|
-
saveOutput(output) {
|
|
195
|
-
this.output = output;
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
setKey(key) {
|
|
199
|
-
this.key = key;
|
|
200
|
-
return this;
|
|
201
|
-
}
|
|
202
|
-
usesKey() {
|
|
203
|
-
return isNotNullish(this.key);
|
|
204
|
-
}
|
|
205
|
-
addChild(child) {
|
|
206
|
-
invariant(this.children);
|
|
207
|
-
this.children.push(child);
|
|
208
|
-
}
|
|
209
|
-
removeChild(node) {
|
|
210
|
-
var _a, _b;
|
|
211
|
-
this.children = (_b = (_a = this.children) === null || _a === void 0 ? void 0 : _a.filter(child => child !== node)) !== null && _b !== void 0 ? _b : null;
|
|
212
|
-
}
|
|
213
|
-
slice(at) {
|
|
214
|
-
if (isNullish(this.children)) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
this.children.length = at;
|
|
218
|
-
}
|
|
219
|
-
at(at) {
|
|
220
|
-
var _a, _b;
|
|
221
|
-
return (_b = (_a = this.children) === null || _a === void 0 ? void 0 : _a[at]) !== null && _b !== void 0 ? _b : null;
|
|
222
|
-
}
|
|
223
|
-
cursor() {
|
|
224
|
-
var _a, _b;
|
|
225
|
-
return (_b = (_a = this.children) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
226
|
-
}
|
|
227
|
-
shouldAllowReorder() {
|
|
228
|
-
var _a;
|
|
229
|
-
return (_a = closestExists(this, node => node.allowReorder)) !== null && _a !== void 0 ? _a : false;
|
|
230
|
-
}
|
|
231
|
-
get rootNode() {
|
|
232
|
-
var _a;
|
|
233
|
-
return (_a = closest(this, node => isNullish(node.parent))) !== null && _a !== void 0 ? _a : this;
|
|
234
|
-
}
|
|
235
|
-
static create(callback, data) {
|
|
236
|
-
return this.createImplementation(callback, data);
|
|
237
|
-
}
|
|
238
|
-
static createImplementation(callback, data) {
|
|
239
|
-
const parent = useIsolate();
|
|
240
|
-
const newCreatedNode = new this(data).setParent(parent);
|
|
241
|
-
const [nextIsolateChild, output] = this.reconciler.reconcile(newCreatedNode, callback);
|
|
242
|
-
nextIsolateChild.saveOutput(output);
|
|
243
|
-
this.setNode(nextIsolateChild);
|
|
244
|
-
return nextIsolateChild;
|
|
245
|
-
}
|
|
246
|
-
static setNode(node) {
|
|
247
|
-
const parent = useIsolate();
|
|
248
|
-
if (parent) {
|
|
249
|
-
useSetNextIsolateChild(node);
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
useSetHistory(node);
|
|
253
|
-
}
|
|
254
|
-
node.setParent(parent);
|
|
255
|
-
}
|
|
256
|
-
static is(node) {
|
|
257
|
-
return node instanceof Isolate;
|
|
138
|
+
const SuiteContext = createCascade((ctxRef, parentContext) => {
|
|
139
|
+
if (parentContext) {
|
|
140
|
+
return null;
|
|
258
141
|
}
|
|
142
|
+
return assign({
|
|
143
|
+
exclusion: {
|
|
144
|
+
tests: {},
|
|
145
|
+
groups: {},
|
|
146
|
+
},
|
|
147
|
+
inclusion: {},
|
|
148
|
+
mode: tinyState.createTinyState(Modes.EAGER),
|
|
149
|
+
testMemoCache,
|
|
150
|
+
}, ctxRef);
|
|
151
|
+
});
|
|
152
|
+
function useCurrentTest(msg) {
|
|
153
|
+
return SuiteContext.useX(msg).currentTest;
|
|
154
|
+
}
|
|
155
|
+
function useGroupName() {
|
|
156
|
+
return SuiteContext.useX().groupName;
|
|
157
|
+
}
|
|
158
|
+
function useExclusion(hookError) {
|
|
159
|
+
return SuiteContext.useX(hookError).exclusion;
|
|
160
|
+
}
|
|
161
|
+
function useInclusion() {
|
|
162
|
+
return SuiteContext.useX().inclusion;
|
|
163
|
+
}
|
|
164
|
+
function useMode() {
|
|
165
|
+
return SuiteContext.useX().mode();
|
|
166
|
+
}
|
|
167
|
+
function useSkipped() {
|
|
168
|
+
var _a;
|
|
169
|
+
return (_a = SuiteContext.useX().skipped) !== null && _a !== void 0 ? _a : false;
|
|
170
|
+
}
|
|
171
|
+
function useOmitted() {
|
|
172
|
+
var _a;
|
|
173
|
+
return (_a = SuiteContext.useX().omitted) !== null && _a !== void 0 ? _a : false;
|
|
174
|
+
}
|
|
175
|
+
const testMemoCache = cache(10);
|
|
176
|
+
function useTestMemoCache() {
|
|
177
|
+
return SuiteContext.useX().testMemoCache;
|
|
259
178
|
}
|
|
260
|
-
|
|
179
|
+
|
|
180
|
+
var ErrorStrings;
|
|
181
|
+
(function (ErrorStrings) {
|
|
182
|
+
ErrorStrings["HOOK_CALLED_OUTSIDE"] = "hook called outside of a running suite.";
|
|
183
|
+
ErrorStrings["EXPECTED_VEST_TEST"] = "Expected value to be an instance of IsolateTest";
|
|
184
|
+
ErrorStrings["FIELD_NAME_REQUIRED"] = "Field name must be passed";
|
|
185
|
+
ErrorStrings["SUITE_MUST_BE_INITIALIZED_WITH_FUNCTION"] = "Suite must be initialized with a function";
|
|
186
|
+
ErrorStrings["PROMISIFY_REQUIRE_FUNCTION"] = "Vest.Promisify must be called with a function";
|
|
187
|
+
ErrorStrings["PARSER_EXPECT_RESULT_OBJECT"] = "Vest parser: expected argument at position 0 to be Vest's result object.";
|
|
188
|
+
ErrorStrings["WARN_MUST_BE_CALLED_FROM_TEST"] = "Warn must be called from within the body of a test function";
|
|
189
|
+
ErrorStrings["EACH_CALLBACK_MUST_BE_A_FUNCTION"] = "Each must be called with a function";
|
|
190
|
+
ErrorStrings["INVALID_PARAM_PASSED_TO_FUNCTION"] = "Incompatible params passed to {fn_name} function. \"{param}\" must be of type {expected}";
|
|
191
|
+
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.";
|
|
192
|
+
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}.";
|
|
193
|
+
ErrorStrings["UNEXPECTED_TEST_RUN_ERROR"] = "Unexpected error encountered during test run. Please report this issue to Vest's Github repository.\n Test Object: {testObject}.";
|
|
194
|
+
})(ErrorStrings || (ErrorStrings = {}));
|
|
261
195
|
|
|
262
196
|
function nonMatchingFieldName(WithFieldName, fieldName) {
|
|
263
197
|
return !!fieldName && !matchingFieldName(WithFieldName, fieldName);
|
|
@@ -295,6 +229,45 @@ function countKeyBySeverity(severity) {
|
|
|
295
229
|
? SeverityCount.ERROR_COUNT
|
|
296
230
|
: SeverityCount.WARN_COUNT;
|
|
297
231
|
}
|
|
232
|
+
var TestSeverity;
|
|
233
|
+
(function (TestSeverity) {
|
|
234
|
+
TestSeverity["Error"] = "error";
|
|
235
|
+
TestSeverity["Warning"] = "warning";
|
|
236
|
+
})(TestSeverity || (TestSeverity = {}));
|
|
237
|
+
|
|
238
|
+
var _a, _b;
|
|
239
|
+
class SummaryBase {
|
|
240
|
+
constructor() {
|
|
241
|
+
this.errorCount = 0;
|
|
242
|
+
this.warnCount = 0;
|
|
243
|
+
this.testCount = 0;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
class SuiteSummary extends SummaryBase {
|
|
247
|
+
constructor() {
|
|
248
|
+
super(...arguments);
|
|
249
|
+
this[_a] = [];
|
|
250
|
+
this[_b] = [];
|
|
251
|
+
this.groups = {};
|
|
252
|
+
this.tests = {};
|
|
253
|
+
this.valid = false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
_a = Severity.ERRORS, _b = Severity.WARNINGS;
|
|
257
|
+
|
|
258
|
+
class SummaryFailure {
|
|
259
|
+
constructor(fieldName, message, groupName) {
|
|
260
|
+
this.fieldName = fieldName;
|
|
261
|
+
this.message = message;
|
|
262
|
+
this.groupName = groupName;
|
|
263
|
+
}
|
|
264
|
+
static fromTestObject(testObject) {
|
|
265
|
+
return new SummaryFailure(testObject.fieldName, testObject.message, testObject.groupName);
|
|
266
|
+
}
|
|
267
|
+
toString() {
|
|
268
|
+
return this.message || '';
|
|
269
|
+
}
|
|
270
|
+
}
|
|
298
271
|
|
|
299
272
|
const nonMatchingGroupName = bindNot(matchingGroupName);
|
|
300
273
|
function matchingGroupName(testObject, groupName) {
|
|
@@ -344,108 +317,6 @@ function hasFailuresByTestObject(testObject, severityKey, fieldName) {
|
|
|
344
317
|
return true;
|
|
345
318
|
}
|
|
346
319
|
|
|
347
|
-
var Modes;
|
|
348
|
-
(function (Modes) {
|
|
349
|
-
Modes["ALL"] = "ALL";
|
|
350
|
-
Modes["EAGER"] = "EAGER";
|
|
351
|
-
})(Modes || (Modes = {}));
|
|
352
|
-
/**
|
|
353
|
-
* Sets the suite to "eager" (fail fast) mode.
|
|
354
|
-
* Eager mode will skip running subsequent tests of a failing fields.
|
|
355
|
-
*
|
|
356
|
-
* @example
|
|
357
|
-
* // in the following example, the second test of username will not run
|
|
358
|
-
* // if the first test of username failed.
|
|
359
|
-
* const suite = create((data) => {
|
|
360
|
-
* eager();
|
|
361
|
-
*
|
|
362
|
-
* test('username', 'username is required', () => {
|
|
363
|
-
* enforce(data.username).isNotBlank();
|
|
364
|
-
* });
|
|
365
|
-
*
|
|
366
|
-
* test('username', 'username is too short', () => {
|
|
367
|
-
* enforce(data.username).longerThan(2);
|
|
368
|
-
* });
|
|
369
|
-
* });
|
|
370
|
-
*/
|
|
371
|
-
// @vx-allow use-use
|
|
372
|
-
function mode(mode) {
|
|
373
|
-
const [, setMode] = useMode();
|
|
374
|
-
setMode(mode);
|
|
375
|
-
}
|
|
376
|
-
function useIsMode(mode) {
|
|
377
|
-
const [currentMode] = useMode();
|
|
378
|
-
return currentMode === mode;
|
|
379
|
-
}
|
|
380
|
-
function useIsEager() {
|
|
381
|
-
return useIsMode(Modes.EAGER);
|
|
382
|
-
}
|
|
383
|
-
function useShouldSkipBasedOnMode(testObject) {
|
|
384
|
-
return useIsEager() && hasErrorsByTestObjects(testObject.fieldName);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const SuiteContext = createCascade((ctxRef, parentContext) => {
|
|
388
|
-
if (parentContext) {
|
|
389
|
-
return null;
|
|
390
|
-
}
|
|
391
|
-
return assign({
|
|
392
|
-
exclusion: {
|
|
393
|
-
tests: {},
|
|
394
|
-
groups: {},
|
|
395
|
-
},
|
|
396
|
-
inclusion: {},
|
|
397
|
-
mode: tinyState.createTinyState(Modes.EAGER),
|
|
398
|
-
testMemoCache,
|
|
399
|
-
}, ctxRef);
|
|
400
|
-
});
|
|
401
|
-
function useCurrentTest(msg) {
|
|
402
|
-
return SuiteContext.useX(msg).currentTest;
|
|
403
|
-
}
|
|
404
|
-
function useGroupName() {
|
|
405
|
-
return SuiteContext.useX().groupName;
|
|
406
|
-
}
|
|
407
|
-
function useExclusion(hookError) {
|
|
408
|
-
return SuiteContext.useX(hookError).exclusion;
|
|
409
|
-
}
|
|
410
|
-
function useInclusion() {
|
|
411
|
-
return SuiteContext.useX().inclusion;
|
|
412
|
-
}
|
|
413
|
-
function useMode() {
|
|
414
|
-
return SuiteContext.useX().mode();
|
|
415
|
-
}
|
|
416
|
-
function useSkipped() {
|
|
417
|
-
var _a;
|
|
418
|
-
return (_a = SuiteContext.useX().skipped) !== null && _a !== void 0 ? _a : false;
|
|
419
|
-
}
|
|
420
|
-
function useOmitted() {
|
|
421
|
-
var _a;
|
|
422
|
-
return (_a = SuiteContext.useX().omitted) !== null && _a !== void 0 ? _a : false;
|
|
423
|
-
}
|
|
424
|
-
const testMemoCache = cache(10);
|
|
425
|
-
function useTestMemoCache() {
|
|
426
|
-
return SuiteContext.useX().testMemoCache;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
var _a, _b;
|
|
430
|
-
class SummaryBase {
|
|
431
|
-
constructor() {
|
|
432
|
-
this.errorCount = 0;
|
|
433
|
-
this.warnCount = 0;
|
|
434
|
-
this.testCount = 0;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
class SuiteSummary extends SummaryBase {
|
|
438
|
-
constructor() {
|
|
439
|
-
super(...arguments);
|
|
440
|
-
this[_a] = [];
|
|
441
|
-
this[_b] = [];
|
|
442
|
-
this.groups = {};
|
|
443
|
-
this.tests = {};
|
|
444
|
-
this.valid = false;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
_a = Severity.ERRORS, _b = Severity.WARNINGS;
|
|
448
|
-
|
|
449
320
|
function useShouldAddValidProperty(fieldName) {
|
|
450
321
|
// Is the field optional, and the optional condition is applied
|
|
451
322
|
if (useIsOptionalFiedApplied(fieldName)) {
|
|
@@ -482,7 +353,10 @@ function useShouldAddValidPropertyInGroup(groupName, fieldName) {
|
|
|
482
353
|
// Does the given field have any pending tests that are not optional?
|
|
483
354
|
function useHasNonOptionalIncomplete(fieldName) {
|
|
484
355
|
return TestWalker.someIncompleteTests(testObject => {
|
|
485
|
-
|
|
356
|
+
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
return !useIsOptionalFiedApplied(fieldName);
|
|
486
360
|
});
|
|
487
361
|
}
|
|
488
362
|
// Do the given group/field have any pending tests that are not optional?
|
|
@@ -491,15 +365,12 @@ function useHasNonOptionalIncompleteByGroup(groupName, fieldName) {
|
|
|
491
365
|
if (nonMatchingGroupName(testObject, groupName)) {
|
|
492
366
|
return false;
|
|
493
367
|
}
|
|
494
|
-
|
|
368
|
+
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return !useIsOptionalFiedApplied(fieldName);
|
|
495
372
|
});
|
|
496
373
|
}
|
|
497
|
-
function useIsTestObjectOptional(testObject, fieldName) {
|
|
498
|
-
if (nonMatchingFieldName(testObject, fieldName)) {
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
return useIsOptionalFiedApplied(fieldName);
|
|
502
|
-
}
|
|
503
374
|
// Did all of the tests for the provided field run/omit?
|
|
504
375
|
// This makes sure that the fields are not skipped or pending.
|
|
505
376
|
function useNoMissingTests(fieldName) {
|
|
@@ -529,16 +400,15 @@ function useNoMissingTestsLogic(testObject, fieldName) {
|
|
|
529
400
|
* or if it is marked as optional, even if the optional check did not apply yet -
|
|
530
401
|
* but the test did not reach its final state.
|
|
531
402
|
*/
|
|
532
|
-
return (
|
|
403
|
+
return (testObject.isOmitted() ||
|
|
533
404
|
testObject.isTested() ||
|
|
534
|
-
testObject
|
|
405
|
+
useOptionalTestAwaitsResolution(testObject));
|
|
535
406
|
}
|
|
536
407
|
function useOptionalTestAwaitsResolution(testObject) {
|
|
537
408
|
// Does the test belong to an optional field,
|
|
538
409
|
// and the test itself is still in an indeterminate state?
|
|
539
410
|
var _a;
|
|
540
|
-
return (((_a =
|
|
541
|
-
OptionalFieldTypes.Delayed && testObject.awaitsResolution());
|
|
411
|
+
return (((_a = VestRuntime.useAvailableRoot()) === null || _a === void 0 ? void 0 : _a.getOptionalField(testObject.fieldName).type) === OptionalFieldTypes.AUTO && testObject.awaitsResolution());
|
|
542
412
|
}
|
|
543
413
|
|
|
544
414
|
function useProduceSuiteSummary() {
|
|
@@ -553,13 +423,12 @@ function useProduceSuiteSummary() {
|
|
|
553
423
|
return countFailures(summary);
|
|
554
424
|
}
|
|
555
425
|
function appendFailures(key, failures, testObject) {
|
|
426
|
+
if (testObject.isOmitted()) {
|
|
427
|
+
return failures;
|
|
428
|
+
}
|
|
556
429
|
const shouldAppend = key === Severity.WARNINGS ? testObject.isWarning() : testObject.isFailing();
|
|
557
430
|
if (shouldAppend) {
|
|
558
|
-
return failures.concat(
|
|
559
|
-
fieldName: testObject.fieldName,
|
|
560
|
-
groupName: testObject.groupName,
|
|
561
|
-
message: testObject.message,
|
|
562
|
-
});
|
|
431
|
+
return failures.concat(SummaryFailure.fromTestObject(testObject));
|
|
563
432
|
}
|
|
564
433
|
return failures;
|
|
565
434
|
}
|
|
@@ -659,6 +528,22 @@ function collectAll(testGroup, severityKey) {
|
|
|
659
528
|
return output;
|
|
660
529
|
}
|
|
661
530
|
|
|
531
|
+
function bindSuiteSelectors(get) {
|
|
532
|
+
return {
|
|
533
|
+
getError: (...args) => get().getError(...args),
|
|
534
|
+
getErrors: (...args) => get().getErrors(...args),
|
|
535
|
+
getErrorsByGroup: (...args) => get().getErrorsByGroup(...args),
|
|
536
|
+
getWarning: (...args) => get().getWarning(...args),
|
|
537
|
+
getWarnings: (...args) => get().getWarnings(...args),
|
|
538
|
+
getWarningsByGroup: (...args) => get().getWarningsByGroup(...args),
|
|
539
|
+
hasErrors: (...args) => get().hasErrors(...args),
|
|
540
|
+
hasErrorsByGroup: (...args) => get().hasErrorsByGroup(...args),
|
|
541
|
+
hasWarnings: (...args) => get().hasWarnings(...args),
|
|
542
|
+
hasWarningsByGroup: (...args) => get().hasWarningsByGroup(...args),
|
|
543
|
+
isValid: (...args) => get().isValid(...args),
|
|
544
|
+
isValidByGroup: (...args) => get().isValidByGroup(...args),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
662
547
|
// eslint-disable-next-line max-lines-per-function, max-statements
|
|
663
548
|
function suiteSelectors(summary) {
|
|
664
549
|
const selectors = {
|
|
@@ -777,11 +662,15 @@ function getFailure(severity, summary, fieldName) {
|
|
|
777
662
|
}
|
|
778
663
|
|
|
779
664
|
function useCreateSuiteResult() {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
665
|
+
return useSuiteResultCache(() => {
|
|
666
|
+
// eslint-disable-next-line vest-internal/use-use
|
|
667
|
+
const summary = useProduceSuiteSummary();
|
|
668
|
+
// eslint-disable-next-line vest-internal/use-use
|
|
669
|
+
const suiteName = useSuiteName();
|
|
670
|
+
return Object.freeze(assign(summary, suiteSelectors(summary), {
|
|
671
|
+
suiteName,
|
|
672
|
+
}));
|
|
673
|
+
});
|
|
785
674
|
}
|
|
786
675
|
|
|
787
676
|
/**
|
|
@@ -877,8 +766,6 @@ function useIsExcluded(testObject) {
|
|
|
877
766
|
// If there is _ANY_ `only`ed test (and we already know this one isn't) return true
|
|
878
767
|
if (hasIncludedTests(keyTests)) {
|
|
879
768
|
// Check if inclusion rules for this field (`include` hook)
|
|
880
|
-
// TODO: Check if this may need to be moved outside of the condition.
|
|
881
|
-
// What if there are no included tests? This shouldn't run then?
|
|
882
769
|
return !optionalFunctionValue(inclusion[fieldName]);
|
|
883
770
|
}
|
|
884
771
|
// We're done here. This field is not excluded
|
|
@@ -944,6 +831,51 @@ function useHasIncludedGroups() {
|
|
|
944
831
|
return false;
|
|
945
832
|
}
|
|
946
833
|
|
|
834
|
+
/**
|
|
835
|
+
* Sets the current execution mode for the current suite.
|
|
836
|
+
*
|
|
837
|
+
* Supported modes:
|
|
838
|
+
* - `EAGER` - (default) Runs all tests, but stops on first failure for each given field.
|
|
839
|
+
* - `ALL` - Runs all tests, regardless of failures.
|
|
840
|
+
* - `ONE` - Stops suite execution on first failure of any field.
|
|
841
|
+
*
|
|
842
|
+
* @example
|
|
843
|
+
* ```js
|
|
844
|
+
* import {Modes, create} from 'vest';
|
|
845
|
+
*
|
|
846
|
+
* const suite = create('suite_name', () => {
|
|
847
|
+
* vest.mode(Modes.ALL);
|
|
848
|
+
*
|
|
849
|
+
* // ...
|
|
850
|
+
* });
|
|
851
|
+
* ```
|
|
852
|
+
* @param 'ALL' | 'EAGER' | 'ONE' mode - The mode to set.
|
|
853
|
+
*/
|
|
854
|
+
// @vx-allow use-use
|
|
855
|
+
function mode(mode) {
|
|
856
|
+
const [, setMode] = useMode();
|
|
857
|
+
setMode(mode);
|
|
858
|
+
}
|
|
859
|
+
function useIsMode(mode) {
|
|
860
|
+
const [currentMode] = useMode();
|
|
861
|
+
return currentMode === mode;
|
|
862
|
+
}
|
|
863
|
+
function useIsEager() {
|
|
864
|
+
return useIsMode(Modes.EAGER);
|
|
865
|
+
}
|
|
866
|
+
function useIsOne() {
|
|
867
|
+
return useIsMode(Modes.ONE);
|
|
868
|
+
}
|
|
869
|
+
function useShouldSkipBasedOnMode(testObject) {
|
|
870
|
+
if (useIsOne()) {
|
|
871
|
+
return hasErrorsByTestObjects();
|
|
872
|
+
}
|
|
873
|
+
if (useIsEager()) {
|
|
874
|
+
return hasErrorsByTestObjects(testObject.fieldName);
|
|
875
|
+
}
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
|
|
947
879
|
/**
|
|
948
880
|
* Conditionally omits tests from the suite.
|
|
949
881
|
*
|
|
@@ -999,49 +931,64 @@ function useForceSkipIfInSkipWhen(testNode) {
|
|
|
999
931
|
return testNode;
|
|
1000
932
|
}
|
|
1001
933
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
if (isNullish(historyNode)) {
|
|
1009
|
-
return this.handleNoHistoryNode(currentNode);
|
|
1010
|
-
}
|
|
1011
|
-
if (!IsolateTest.is(historyNode)) {
|
|
1012
|
-
return currentNode;
|
|
1013
|
-
}
|
|
1014
|
-
const reconcilerOutput = this.pickNode(historyNode, currentNode);
|
|
1015
|
-
cancelOverriddenPendingTestOnTestReRun(reconcilerOutput, currentNode, historyNode);
|
|
1016
|
-
return reconcilerOutput;
|
|
934
|
+
// @vx-allow use-use
|
|
935
|
+
function IsolateTestReconciler(currentNode, historyNode) {
|
|
936
|
+
// Start by verifying params
|
|
937
|
+
if (!IsolateTest.is(currentNode)) {
|
|
938
|
+
// This is unreachable, since this function should only be called with IsolateTest nodes
|
|
939
|
+
return currentNode;
|
|
1017
940
|
}
|
|
1018
|
-
|
|
1019
|
-
return
|
|
941
|
+
if (isNullish(historyNode)) {
|
|
942
|
+
return handleNoHistoryNode(currentNode);
|
|
1020
943
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
944
|
+
if (!IsolateTest.is(historyNode)) {
|
|
945
|
+
return currentNode;
|
|
946
|
+
}
|
|
947
|
+
const reconcilerOutput = usePickNode(historyNode, currentNode);
|
|
948
|
+
cancelOverriddenPendingTestOnTestReRun(reconcilerOutput, currentNode, historyNode);
|
|
949
|
+
return reconcilerOutput;
|
|
950
|
+
}
|
|
951
|
+
// eslint-disable-next-line max-statements
|
|
952
|
+
function nodeReorderDetected(newNode, prevNode) {
|
|
953
|
+
return !!IsolateTest.is(prevNode) && !isSameProfileTest(prevNode, newNode);
|
|
954
|
+
}
|
|
955
|
+
function handleCollision(newNode, prevNode) {
|
|
956
|
+
if (newNode.usesKey()) {
|
|
957
|
+
return IsolateTest.cast(Reconciler.handleIsolateNodeWithKey(newNode));
|
|
1029
958
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
959
|
+
if (nodeReorderDetected(newNode, prevNode)) {
|
|
960
|
+
return onNodeReorder(newNode, prevNode);
|
|
961
|
+
}
|
|
962
|
+
if (!IsolateTest.is(prevNode)) {
|
|
963
|
+
// I believe we cannot actually reach this point.
|
|
964
|
+
// Because it should already be handled by nodeReorderDetected.
|
|
1033
965
|
return newNode;
|
|
1034
966
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
967
|
+
// FIXME: May-13-2023
|
|
968
|
+
// This may not be the most ideal solution.
|
|
969
|
+
// In short: if the node was omitted in the previous run,
|
|
970
|
+
// we want to re-evaluate it. The reason is that we may incorrectly
|
|
971
|
+
// identify it is "optional" because it was omitted in the previous run.
|
|
972
|
+
// There may be a better way to handle this. Need to revisit this.
|
|
973
|
+
if (prevNode.isOmitted()) {
|
|
974
|
+
return newNode;
|
|
1038
975
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
976
|
+
return prevNode;
|
|
977
|
+
}
|
|
978
|
+
function onNodeReorder(newNode, prevNode) {
|
|
979
|
+
throwTestOrderError(newNode, prevNode);
|
|
980
|
+
Reconciler.removeAllNextNodesInIsolate();
|
|
981
|
+
return newNode;
|
|
982
|
+
}
|
|
983
|
+
function usePickNode(historyNode, currentNode) {
|
|
984
|
+
const collisionResult = handleCollision(currentNode, historyNode);
|
|
985
|
+
return useVerifyTestRun(currentNode, collisionResult);
|
|
986
|
+
}
|
|
987
|
+
function handleNoHistoryNode(testNode) {
|
|
988
|
+
if (testNode.usesKey()) {
|
|
989
|
+
return IsolateTest.cast(Reconciler.handleIsolateNodeWithKey(testNode));
|
|
1044
990
|
}
|
|
991
|
+
return testNode;
|
|
1045
992
|
}
|
|
1046
993
|
function cancelOverriddenPendingTestOnTestReRun(nextNode, currentNode, prevTestObject) {
|
|
1047
994
|
if (nextNode === currentNode && IsolateTest.is(currentNode)) {
|
|
@@ -1058,30 +1005,6 @@ function throwTestOrderError(newNode, prevNode) {
|
|
|
1058
1005
|
}));
|
|
1059
1006
|
}
|
|
1060
1007
|
|
|
1061
|
-
function StateMachine(machine) {
|
|
1062
|
-
let state = machine.initial;
|
|
1063
|
-
const api = { getState, transition };
|
|
1064
|
-
return api;
|
|
1065
|
-
function getState() {
|
|
1066
|
-
return state;
|
|
1067
|
-
}
|
|
1068
|
-
function transition(action, payload) {
|
|
1069
|
-
const transitionTo = machine.states[state][action];
|
|
1070
|
-
let target = transitionTo;
|
|
1071
|
-
if (Array.isArray(target)) {
|
|
1072
|
-
const [, conditional] = target;
|
|
1073
|
-
if (!conditional(payload)) {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
target = target[0];
|
|
1077
|
-
}
|
|
1078
|
-
if (!target || target === state) {
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
state = target;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
1008
|
var TestStatus;
|
|
1086
1009
|
(function (TestStatus) {
|
|
1087
1010
|
TestStatus["UNTESTED"] = "UNTESTED";
|
|
@@ -1104,32 +1027,21 @@ function createTestStateMachine() {
|
|
|
1104
1027
|
const machine = {
|
|
1105
1028
|
initial: TestStatus.UNTESTED,
|
|
1106
1029
|
states: {
|
|
1030
|
+
'*': {
|
|
1031
|
+
[TestStatus.OMITTED]: TestStatus.OMITTED,
|
|
1032
|
+
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1033
|
+
},
|
|
1107
1034
|
[TestStatus.UNTESTED]: {
|
|
1108
1035
|
[TestStatus.CANCELED]: TestStatus.CANCELED,
|
|
1109
1036
|
[TestStatus.FAILED]: TestStatus.FAILED,
|
|
1110
|
-
[TestStatus.OMITTED]: TestStatus.OMITTED,
|
|
1111
1037
|
[TestStatus.PASSING]: TestStatus.PASSING,
|
|
1112
1038
|
[TestStatus.PENDING]: TestStatus.PENDING,
|
|
1113
1039
|
[TestStatus.SKIPPED]: TestStatus.SKIPPED,
|
|
1114
1040
|
[TestStatus.WARNING]: TestStatus.WARNING,
|
|
1115
1041
|
},
|
|
1116
|
-
[TestStatus.SKIPPED]: {
|
|
1117
|
-
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1118
|
-
},
|
|
1119
|
-
[TestStatus.FAILED]: {
|
|
1120
|
-
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1121
|
-
},
|
|
1122
|
-
[TestStatus.WARNING]: {
|
|
1123
|
-
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1124
|
-
},
|
|
1125
|
-
[TestStatus.PASSING]: {
|
|
1126
|
-
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1127
|
-
},
|
|
1128
1042
|
[TestStatus.PENDING]: {
|
|
1129
|
-
[TestAction.RESET]: TestStatus.UNTESTED,
|
|
1130
1043
|
[TestStatus.CANCELED]: TestStatus.CANCELED,
|
|
1131
1044
|
[TestStatus.FAILED]: TestStatus.FAILED,
|
|
1132
|
-
[TestStatus.OMITTED]: TestStatus.OMITTED,
|
|
1133
1045
|
[TestStatus.PASSING]: TestStatus.PASSING,
|
|
1134
1046
|
[TestStatus.SKIPPED]: [
|
|
1135
1047
|
TestStatus.SKIPPED,
|
|
@@ -1137,12 +1049,12 @@ const machine = {
|
|
|
1137
1049
|
],
|
|
1138
1050
|
[TestStatus.WARNING]: TestStatus.WARNING,
|
|
1139
1051
|
},
|
|
1140
|
-
[TestStatus.
|
|
1141
|
-
|
|
1142
|
-
},
|
|
1143
|
-
[TestStatus.
|
|
1144
|
-
|
|
1145
|
-
},
|
|
1052
|
+
[TestStatus.SKIPPED]: {},
|
|
1053
|
+
[TestStatus.FAILED]: {},
|
|
1054
|
+
[TestStatus.WARNING]: {},
|
|
1055
|
+
[TestStatus.PASSING]: {},
|
|
1056
|
+
[TestStatus.CANCELED]: {},
|
|
1057
|
+
[TestStatus.OMITTED]: {},
|
|
1146
1058
|
},
|
|
1147
1059
|
};
|
|
1148
1060
|
/* eslint-enable sort-keys */
|
|
@@ -1292,25 +1204,20 @@ class IsolateTest extends Isolate {
|
|
|
1292
1204
|
}
|
|
1293
1205
|
}
|
|
1294
1206
|
IsolateTest.reconciler = IsolateTestReconciler;
|
|
1295
|
-
var TestSeverity;
|
|
1296
|
-
(function (TestSeverity) {
|
|
1297
|
-
TestSeverity["Error"] = "error";
|
|
1298
|
-
TestSeverity["Warning"] = "warning";
|
|
1299
|
-
})(TestSeverity || (TestSeverity = {}));
|
|
1300
1207
|
|
|
1301
1208
|
class TestWalker {
|
|
1302
1209
|
static defaultRoot() {
|
|
1303
|
-
return
|
|
1210
|
+
return VestRuntime.useAvailableRoot();
|
|
1304
1211
|
}
|
|
1305
1212
|
static hasNoTests(root = TestWalker.defaultRoot()) {
|
|
1306
1213
|
if (!root)
|
|
1307
1214
|
return true;
|
|
1308
|
-
return !has(root, IsolateTest.is);
|
|
1215
|
+
return !Walker.has(root, IsolateTest.is);
|
|
1309
1216
|
}
|
|
1310
1217
|
static someIncompleteTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1311
1218
|
if (!root)
|
|
1312
1219
|
return false;
|
|
1313
|
-
return some(root, isolate => {
|
|
1220
|
+
return Walker.some(root, isolate => {
|
|
1314
1221
|
IsolateTest.isX(isolate);
|
|
1315
1222
|
return isolate.isPending() && predicate(isolate);
|
|
1316
1223
|
}, IsolateTest.is);
|
|
@@ -1318,7 +1225,7 @@ class TestWalker {
|
|
|
1318
1225
|
static someTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1319
1226
|
if (!root)
|
|
1320
1227
|
return false;
|
|
1321
|
-
return some(root, isolate => {
|
|
1228
|
+
return Walker.some(root, isolate => {
|
|
1322
1229
|
IsolateTest.isX(isolate);
|
|
1323
1230
|
return predicate(isolate);
|
|
1324
1231
|
}, IsolateTest.is);
|
|
@@ -1326,7 +1233,7 @@ class TestWalker {
|
|
|
1326
1233
|
static everyTest(predicate, root = TestWalker.defaultRoot()) {
|
|
1327
1234
|
if (!root)
|
|
1328
1235
|
return false;
|
|
1329
|
-
return every(root, isolate => {
|
|
1236
|
+
return Walker.every(root, isolate => {
|
|
1330
1237
|
IsolateTest.isX(isolate);
|
|
1331
1238
|
return predicate(isolate);
|
|
1332
1239
|
}, IsolateTest.is);
|
|
@@ -1334,7 +1241,7 @@ class TestWalker {
|
|
|
1334
1241
|
static walkTests(callback, root = TestWalker.defaultRoot()) {
|
|
1335
1242
|
if (!root)
|
|
1336
1243
|
return;
|
|
1337
|
-
walk(root, (isolate, breakout) => {
|
|
1244
|
+
Walker.walk(root, (isolate, breakout) => {
|
|
1338
1245
|
callback(IsolateTest.cast(isolate), breakout);
|
|
1339
1246
|
}, IsolateTest.is);
|
|
1340
1247
|
}
|
|
@@ -1349,7 +1256,7 @@ class TestWalker {
|
|
|
1349
1256
|
static pluckTests(predicate, root = TestWalker.defaultRoot()) {
|
|
1350
1257
|
if (!root)
|
|
1351
1258
|
return;
|
|
1352
|
-
pluck(root, isolate => {
|
|
1259
|
+
Walker.pluck(root, isolate => {
|
|
1353
1260
|
IsolateTest.isX(isolate);
|
|
1354
1261
|
return predicate(isolate);
|
|
1355
1262
|
}, IsolateTest.is);
|
|
@@ -1368,6 +1275,58 @@ class TestWalker {
|
|
|
1368
1275
|
}
|
|
1369
1276
|
}
|
|
1370
1277
|
|
|
1278
|
+
/**
|
|
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.
|
|
1282
|
+
*/
|
|
1283
|
+
function useOmitOptionalFields() {
|
|
1284
|
+
const root = VestRuntime.useAvailableRoot();
|
|
1285
|
+
const emit = 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 (isEmpty(optionalFields)) {
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
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()) {
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
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 (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
|
+
}
|
|
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 (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 (optionalFunctionValue(optionalConfig.rule) === true) {
|
|
1324
|
+
shouldOmit.add(testObject.fieldName);
|
|
1325
|
+
}
|
|
1326
|
+
verifyAndOmit(testObject);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1371
1330
|
/**
|
|
1372
1331
|
* Runs done callback per field when async tests are finished running.
|
|
1373
1332
|
*/
|
|
@@ -1387,8 +1346,9 @@ function useRunDoneCallbacks() {
|
|
|
1387
1346
|
callEach(doneCallbacks);
|
|
1388
1347
|
}
|
|
1389
1348
|
|
|
1349
|
+
// eslint-disable-next-line max-statements
|
|
1390
1350
|
function useInitVestBus() {
|
|
1391
|
-
const VestBus =
|
|
1351
|
+
const VestBus = VestRuntime.useBus();
|
|
1392
1352
|
// Report a the completion of a test. There may be other tests with the same
|
|
1393
1353
|
// name that are still running, or not yet started.
|
|
1394
1354
|
on(Events.TEST_COMPLETED, (testObject) => {
|
|
@@ -1404,8 +1364,18 @@ function useInitVestBus() {
|
|
|
1404
1364
|
on(Events.TEST_RUN_STARTED, () => {
|
|
1405
1365
|
/* Let's just invalidate the suite cache for now */
|
|
1406
1366
|
});
|
|
1367
|
+
on(Events.DONE_TEST_OMISSION_PASS, () => {
|
|
1368
|
+
/* We NEED to refresh the cache here. Don't ask */
|
|
1369
|
+
});
|
|
1407
1370
|
// Called when all the tests, including async, are done running
|
|
1408
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();
|
|
1378
|
+
}
|
|
1409
1379
|
useRunDoneCallbacks();
|
|
1410
1380
|
});
|
|
1411
1381
|
on(Events.RESET_FIELD, (fieldName) => {
|
|
@@ -1414,6 +1384,9 @@ function useInitVestBus() {
|
|
|
1414
1384
|
on(Events.SUITE_RUN_STARTED, () => {
|
|
1415
1385
|
useResetCallbacks();
|
|
1416
1386
|
});
|
|
1387
|
+
on(Events.SUITE_CALLBACK_RUN_FINISHED, () => {
|
|
1388
|
+
useOmitOptionalFields();
|
|
1389
|
+
});
|
|
1417
1390
|
on(Events.REMOVE_FIELD, (fieldName) => {
|
|
1418
1391
|
TestWalker.removeTestByFieldName(fieldName);
|
|
1419
1392
|
});
|
|
@@ -1431,202 +1404,30 @@ function useInitVestBus() {
|
|
|
1431
1404
|
}
|
|
1432
1405
|
}
|
|
1433
1406
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
}
|
|
1439
|
-
invariant(vestState.historyRoot);
|
|
1440
|
-
const [historyRootNode] = vestState.historyRoot();
|
|
1441
|
-
const ctxRef = {};
|
|
1442
|
-
assign(ctxRef, {
|
|
1443
|
-
historyNode: historyRootNode,
|
|
1444
|
-
runtimeNode: null,
|
|
1445
|
-
runtimeRoot: null,
|
|
1446
|
-
}, vestState);
|
|
1447
|
-
return ctxRef;
|
|
1448
|
-
});
|
|
1449
|
-
function useCreateVestState({ suiteName, } = {}) {
|
|
1450
|
-
const stateRef = {
|
|
1451
|
-
VestBus: useInitVestBus(),
|
|
1452
|
-
doneCallbacks: tinyState.createTinyState(() => []),
|
|
1453
|
-
fieldCallbacks: tinyState.createTinyState(() => ({})),
|
|
1454
|
-
historyRoot: tinyState.createTinyState(null),
|
|
1455
|
-
suiteId: seq(),
|
|
1456
|
-
suiteName,
|
|
1457
|
-
suiteResultCache,
|
|
1458
|
-
};
|
|
1459
|
-
return stateRef;
|
|
1460
|
-
}
|
|
1461
|
-
function persist(cb) {
|
|
1462
|
-
const prev = PersistedContext.useX();
|
|
1463
|
-
return function persisted(...args) {
|
|
1464
|
-
var _a;
|
|
1465
|
-
const ctxToUse = (_a = PersistedContext.use()) !== null && _a !== void 0 ? _a : prev;
|
|
1466
|
-
return PersistedContext.run(ctxToUse, () => cb(...args));
|
|
1467
|
-
};
|
|
1468
|
-
}
|
|
1469
|
-
function useSuiteResultCache(action) {
|
|
1470
|
-
const suiteResultCache = useX().suiteResultCache;
|
|
1471
|
-
return suiteResultCache([useSuiteId()], action);
|
|
1472
|
-
}
|
|
1473
|
-
function useExpireSuiteResultCache() {
|
|
1474
|
-
const suiteResultCache = useX().suiteResultCache;
|
|
1475
|
-
suiteResultCache.invalidate([useSuiteId()]);
|
|
1476
|
-
}
|
|
1477
|
-
function useResetCallbacks() {
|
|
1478
|
-
const [, , resetDoneCallbacks] = useDoneCallbacks();
|
|
1479
|
-
const [, , resetFieldCallbacks] = useFieldCallbacks();
|
|
1480
|
-
resetDoneCallbacks();
|
|
1481
|
-
resetFieldCallbacks();
|
|
1482
|
-
}
|
|
1483
|
-
function useResetSuite() {
|
|
1484
|
-
useResetCallbacks();
|
|
1485
|
-
const [, , resetHistoryRoot] = useHistoryRoot();
|
|
1486
|
-
resetHistoryRoot();
|
|
1487
|
-
}
|
|
1488
|
-
function useX() {
|
|
1489
|
-
return PersistedContext.useX();
|
|
1490
|
-
}
|
|
1491
|
-
function useVestBus() {
|
|
1492
|
-
return useX().VestBus;
|
|
1493
|
-
}
|
|
1494
|
-
/*
|
|
1495
|
-
Returns an emitter, but it also has a shortcut for emitting an event immediately
|
|
1496
|
-
by passing an event name.
|
|
1497
|
-
*/
|
|
1498
|
-
function useEmit() {
|
|
1499
|
-
return persist(useVestBus().emit);
|
|
1500
|
-
}
|
|
1501
|
-
function usePrepareEmitter(event) {
|
|
1502
|
-
const emit = useEmit();
|
|
1503
|
-
return (arg) => emit(event, arg);
|
|
1504
|
-
}
|
|
1505
|
-
function useDoneCallbacks() {
|
|
1506
|
-
return useX().doneCallbacks();
|
|
1507
|
-
}
|
|
1508
|
-
function useFieldCallbacks() {
|
|
1509
|
-
return useX().fieldCallbacks();
|
|
1510
|
-
}
|
|
1511
|
-
function useHistoryRoot() {
|
|
1512
|
-
return useX().historyRoot();
|
|
1513
|
-
}
|
|
1514
|
-
function useHistoryNode() {
|
|
1515
|
-
return useX().historyNode;
|
|
1516
|
-
}
|
|
1517
|
-
function useSuiteName() {
|
|
1518
|
-
return useX().suiteName;
|
|
1519
|
-
}
|
|
1520
|
-
function useSuiteId() {
|
|
1521
|
-
return useX().suiteId;
|
|
1522
|
-
}
|
|
1523
|
-
function useSetHistory(history) {
|
|
1524
|
-
const context = PersistedContext.useX();
|
|
1525
|
-
const [, setHistoryRoot] = context.historyRoot();
|
|
1526
|
-
setHistoryRoot(history);
|
|
1527
|
-
}
|
|
1528
|
-
function useHistoryKey(key) {
|
|
1529
|
-
var _a;
|
|
1530
|
-
if (isNullish(key)) {
|
|
1531
|
-
return null;
|
|
1532
|
-
}
|
|
1533
|
-
const historyNode = useX().historyNode;
|
|
1534
|
-
return (_a = historyNode === null || historyNode === void 0 ? void 0 : historyNode.keys[key]) !== null && _a !== void 0 ? _a : null;
|
|
1535
|
-
}
|
|
1536
|
-
function useIsolate() {
|
|
1537
|
-
var _a;
|
|
1538
|
-
return (_a = useX().runtimeNode) !== null && _a !== void 0 ? _a : null;
|
|
1539
|
-
}
|
|
1540
|
-
function useCurrentCursor() {
|
|
1541
|
-
var _a, _b;
|
|
1542
|
-
return (_b = (_a = useIsolate()) === null || _a === void 0 ? void 0 : _a.cursor()) !== null && _b !== void 0 ? _b : 0;
|
|
1543
|
-
}
|
|
1544
|
-
function useRuntimeRoot() {
|
|
1545
|
-
return useX().runtimeRoot;
|
|
1546
|
-
}
|
|
1547
|
-
function useSetNextIsolateChild(child) {
|
|
1548
|
-
const currentIsolate = useIsolate();
|
|
1549
|
-
invariant(currentIsolate, ErrorStrings.NO_ACTIVE_ISOLATE);
|
|
1550
|
-
currentIsolate.addChild(child);
|
|
1551
|
-
}
|
|
1552
|
-
function useSetIsolateKey(key, value) {
|
|
1553
|
-
if (!key) {
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
const currentIsolate = useIsolate();
|
|
1557
|
-
invariant(currentIsolate, ErrorStrings.NO_ACTIVE_ISOLATE);
|
|
1558
|
-
if (isNullish(currentIsolate.keys[key])) {
|
|
1559
|
-
currentIsolate.keys[key] = value;
|
|
1560
|
-
return;
|
|
1561
|
-
}
|
|
1562
|
-
deferThrow(text(ErrorStrings.ENCOUNTERED_THE_SAME_KEY_TWICE, { key }));
|
|
1563
|
-
}
|
|
1564
|
-
function useAvailableSuiteRoot() {
|
|
1565
|
-
const root = useRuntimeRoot();
|
|
1566
|
-
if (root) {
|
|
1567
|
-
return root;
|
|
1568
|
-
}
|
|
1569
|
-
const [historyRoot] = useHistoryRoot();
|
|
1570
|
-
return historyRoot;
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// @vx-allow use-use
|
|
1574
|
-
function optional(optionals) {
|
|
1575
|
-
const suiteRoot = useRuntimeRoot();
|
|
1576
|
-
// There are two types of optional field declarations:
|
|
1577
|
-
// 1. Delayed: A string, which is the name of the field to be optional.
|
|
1578
|
-
// We will only determine whether to omit the test after the suite is done running
|
|
1579
|
-
//
|
|
1580
|
-
// 2. Immediate: Either a boolean or a function, which is used to determine
|
|
1581
|
-
// if the field should be optional.
|
|
1582
|
-
// Delayed case (field name)
|
|
1583
|
-
if (isArray(optionals) || isStringValue(optionals)) {
|
|
1584
|
-
asArray(optionals).forEach(optionalField => {
|
|
1585
|
-
suiteRoot.setOptionalField(optionalField, () => ({
|
|
1586
|
-
type: OptionalFieldTypes.Delayed,
|
|
1587
|
-
applied: false,
|
|
1588
|
-
rule: null,
|
|
1589
|
-
}));
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
|
-
else {
|
|
1593
|
-
// Immediately case (function or boolean)
|
|
1594
|
-
for (const field in optionals) {
|
|
1595
|
-
const value = optionals[field];
|
|
1596
|
-
suiteRoot.setOptionalField(field, () => ({
|
|
1597
|
-
type: OptionalFieldTypes.Immediate,
|
|
1598
|
-
rule: value,
|
|
1599
|
-
applied: optionalFunctionValue(value),
|
|
1600
|
-
}));
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
function useIsOptionalFiedApplied(fieldName) {
|
|
1605
|
-
var _a, _b, _c;
|
|
1606
|
-
if (!fieldName) {
|
|
1607
|
-
return false;
|
|
1608
|
-
}
|
|
1609
|
-
return (_c = (_b = (_a = useAvailableSuiteRoot()) === null || _a === void 0 ? void 0 : _a.getOptionalField(fieldName)) === null || _b === void 0 ? void 0 : _b.applied) !== null && _c !== void 0 ? _c : false;
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
class IsolateSuite extends Isolate {
|
|
1613
|
-
constructor() {
|
|
1614
|
-
super(...arguments);
|
|
1615
|
-
this.optional = {};
|
|
1616
|
-
}
|
|
1617
|
-
setOptionalField(fieldName, setter) {
|
|
1618
|
-
const current = this.optional;
|
|
1619
|
-
const currentField = current[fieldName];
|
|
1620
|
-
Object.assign(current, {
|
|
1621
|
-
[fieldName]: Object.assign({}, currentField, setter(currentField)),
|
|
1622
|
-
});
|
|
1623
|
-
}
|
|
1624
|
-
getOptionalField(fieldName) {
|
|
1625
|
-
var _a;
|
|
1626
|
-
return (_a = this.optional[fieldName]) !== null && _a !== void 0 ? _a : {};
|
|
1627
|
-
}
|
|
1407
|
+
function group(groupName, callback) {
|
|
1408
|
+
return Isolate.create(() => {
|
|
1409
|
+
SuiteContext.run({ groupName }, callback);
|
|
1410
|
+
});
|
|
1628
1411
|
}
|
|
1629
1412
|
|
|
1413
|
+
/**
|
|
1414
|
+
* Conditionally includes a field for testing, based on specified criteria.
|
|
1415
|
+
*
|
|
1416
|
+
* @param {string} fieldName - The name of the field to include for testing.
|
|
1417
|
+
*
|
|
1418
|
+
* @example
|
|
1419
|
+
* include('confirm').when('password');
|
|
1420
|
+
* // Includes the "confirm" field for testing when the "password" field is included
|
|
1421
|
+
*
|
|
1422
|
+
* include('confirm').when(someValue);
|
|
1423
|
+
* // Includes the "confirm" field for testing when the value of `someValue` is true
|
|
1424
|
+
*
|
|
1425
|
+
* include('confirm').when(() => someValue);
|
|
1426
|
+
* // Includes the "confirm" field for testing when the callback function returns true
|
|
1427
|
+
*
|
|
1428
|
+
* include('username').when(result => result.hasErrors('username'));
|
|
1429
|
+
* // Includes the "username" field for testing when there are errors associated with it in the current suite result
|
|
1430
|
+
*/
|
|
1630
1431
|
// @vx-allow use-use
|
|
1631
1432
|
function include(fieldName) {
|
|
1632
1433
|
const inclusion = useInclusion();
|
|
@@ -1634,6 +1435,9 @@ function include(fieldName) {
|
|
|
1634
1435
|
invariant(isStringValue(fieldName));
|
|
1635
1436
|
inclusion[fieldName] = defaultTo(exclusion.tests[fieldName], true);
|
|
1636
1437
|
return { when };
|
|
1438
|
+
/**
|
|
1439
|
+
* Specifies the inclusion criteria for the field in `include` function.
|
|
1440
|
+
*/
|
|
1637
1441
|
function when(condition) {
|
|
1638
1442
|
const inclusion = useInclusion();
|
|
1639
1443
|
const exclusion = useExclusion();
|
|
@@ -1653,18 +1457,16 @@ function include(fieldName) {
|
|
|
1653
1457
|
}
|
|
1654
1458
|
}
|
|
1655
1459
|
|
|
1656
|
-
|
|
1460
|
+
// eslint-disable-next-line max-statements
|
|
1461
|
+
function useAttemptRunTest(testObject) {
|
|
1657
1462
|
useVerifyTestRun(testObject);
|
|
1658
|
-
if (testObject.isNonActionable()) {
|
|
1659
|
-
// TODO: Need to test that this works as expected
|
|
1660
|
-
return;
|
|
1661
|
-
}
|
|
1662
1463
|
if (testObject.isUntested()) {
|
|
1663
|
-
useRunTest(testObject);
|
|
1464
|
+
return useRunTest(testObject);
|
|
1664
1465
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1466
|
+
if (!testObject.isNonActionable()) {
|
|
1467
|
+
deferThrow(text(ErrorStrings.UNEXPECTED_TEST_REGISTRATION_ERROR, {
|
|
1468
|
+
testObject: JSON.stringify(testObject),
|
|
1469
|
+
}));
|
|
1668
1470
|
}
|
|
1669
1471
|
}
|
|
1670
1472
|
function runSyncTest(testObject) {
|
|
@@ -1674,7 +1476,7 @@ function runSyncTest(testObject) {
|
|
|
1674
1476
|
* runs test, if async - adds to pending array
|
|
1675
1477
|
*/
|
|
1676
1478
|
function useRunTest(testObject) {
|
|
1677
|
-
const VestBus =
|
|
1479
|
+
const VestBus = VestRuntime.useBus();
|
|
1678
1480
|
// Run test callback.
|
|
1679
1481
|
// If a promise is returned, set as async and
|
|
1680
1482
|
// Move to pending list.
|
|
@@ -1684,7 +1486,6 @@ function useRunTest(testObject) {
|
|
|
1684
1486
|
// in case object is an enforce chain
|
|
1685
1487
|
if (isPromise(result)) {
|
|
1686
1488
|
testObject.asyncTest = result;
|
|
1687
|
-
testObject.setPending();
|
|
1688
1489
|
useRunAsyncTest(testObject);
|
|
1689
1490
|
}
|
|
1690
1491
|
else {
|
|
@@ -1705,11 +1506,12 @@ function useRunAsyncTest(testObject) {
|
|
|
1705
1506
|
const { asyncTest, message } = testObject;
|
|
1706
1507
|
if (!isPromise(asyncTest))
|
|
1707
1508
|
return;
|
|
1708
|
-
|
|
1709
|
-
const
|
|
1509
|
+
testObject.setPending();
|
|
1510
|
+
const VestBus = VestRuntime.useBus();
|
|
1511
|
+
const done = VestRuntime.persist(() => {
|
|
1710
1512
|
onTestCompleted(VestBus, testObject);
|
|
1711
1513
|
});
|
|
1712
|
-
const fail = persist((rejectionMessage) => {
|
|
1514
|
+
const fail = VestRuntime.persist((rejectionMessage) => {
|
|
1713
1515
|
if (testObject.isCanceled()) {
|
|
1714
1516
|
return;
|
|
1715
1517
|
}
|
|
@@ -1733,7 +1535,11 @@ function wrapTestMemo(test) {
|
|
|
1733
1535
|
function memo(fieldName, ...args) {
|
|
1734
1536
|
const [deps, testFn, msg] = args.reverse();
|
|
1735
1537
|
// Implicit dependency for better specificity
|
|
1736
|
-
const dependencies = [
|
|
1538
|
+
const dependencies = [
|
|
1539
|
+
useSuiteId(),
|
|
1540
|
+
fieldName,
|
|
1541
|
+
VestRuntime.useCurrentCursor(),
|
|
1542
|
+
].concat(deps);
|
|
1737
1543
|
return useGetTestFromCache(dependencies, cacheAction);
|
|
1738
1544
|
function cacheAction() {
|
|
1739
1545
|
return test(fieldName, msg, testFn);
|
|
@@ -1763,11 +1569,11 @@ function vestTest(fieldName, ...args) {
|
|
|
1763
1569
|
const [message, testFn, key] = (isFunction(args[1]) ? args : [undefined, ...args]);
|
|
1764
1570
|
validateTestParams(fieldName, testFn);
|
|
1765
1571
|
const groupName = useGroupName();
|
|
1766
|
-
const emit = useEmit();
|
|
1572
|
+
const emit = VestRuntime.useEmit();
|
|
1767
1573
|
const testObjectInput = { fieldName, groupName, key, message, testFn };
|
|
1768
1574
|
// This invalidates the suite cache.
|
|
1769
1575
|
emit(Events.TEST_RUN_STARTED);
|
|
1770
|
-
return IsolateTest.create(
|
|
1576
|
+
return IsolateTest.create(useAttemptRunTest, testObjectInput);
|
|
1771
1577
|
}
|
|
1772
1578
|
const test = assign(vestTest, {
|
|
1773
1579
|
memo: wrapTestMemo(vestTest),
|
|
@@ -1786,6 +1592,7 @@ function validateTestParams(fieldName, testFn) {
|
|
|
1786
1592
|
}));
|
|
1787
1593
|
}
|
|
1788
1594
|
|
|
1595
|
+
// import { optional, skipWhen, omitWhen, IsolateTest, group } from 'vest';
|
|
1789
1596
|
function getTypedMethods() {
|
|
1790
1597
|
return {
|
|
1791
1598
|
group,
|
|
@@ -1822,9 +1629,9 @@ function shouldSkipDoneRegistration(callback, fieldName, output) {
|
|
|
1822
1629
|
}
|
|
1823
1630
|
|
|
1824
1631
|
function useSuiteRunResult() {
|
|
1825
|
-
return assign({
|
|
1826
|
-
done: persist(done),
|
|
1827
|
-
});
|
|
1632
|
+
return Object.freeze(assign({
|
|
1633
|
+
done: VestRuntime.persist(done),
|
|
1634
|
+
}, useCreateSuiteResult()));
|
|
1828
1635
|
}
|
|
1829
1636
|
/**
|
|
1830
1637
|
* Registers done callbacks.
|
|
@@ -1860,24 +1667,27 @@ function createSuite(...args) {
|
|
|
1860
1667
|
function suite(...args) {
|
|
1861
1668
|
return SuiteContext.run({}, () => {
|
|
1862
1669
|
// eslint-disable-next-line vest-internal/use-use
|
|
1863
|
-
const emit = useEmit();
|
|
1670
|
+
const emit = VestRuntime.useEmit();
|
|
1864
1671
|
emit(Events.SUITE_RUN_STARTED);
|
|
1865
1672
|
return IsolateSuite.create(useRunSuiteCallback(suiteCallback, ...args));
|
|
1866
1673
|
}).output;
|
|
1867
1674
|
}
|
|
1868
1675
|
// Assign methods to the suite
|
|
1869
|
-
// We do this within the
|
|
1676
|
+
// We do this within the VestRuntime so that the suite methods
|
|
1870
1677
|
// will be bound to the suite's stateRef and be able to access it.
|
|
1871
|
-
return
|
|
1678
|
+
return VestRuntime.Run(stateRef, () => {
|
|
1679
|
+
useInitVestBus();
|
|
1872
1680
|
return assign(
|
|
1873
1681
|
// We're also binding the suite to the stateRef, so that the suite
|
|
1874
1682
|
// can access the stateRef when it's called.
|
|
1875
|
-
|
|
1683
|
+
VestRuntime.persist(suite), Object.assign(Object.assign({ get: VestRuntime.persist(useCreateSuiteResult), remove: VestRuntime.usePrepareEmitter(Events.REMOVE_FIELD), reset: VestRuntime.usePrepareEmitter(Events.RESET_SUITE), resetField: VestRuntime.usePrepareEmitter(Events.RESET_FIELD) }, bindSuiteSelectors(VestRuntime.persist(useCreateSuiteResult))), getTypedMethods()));
|
|
1876
1684
|
});
|
|
1877
1685
|
}
|
|
1878
1686
|
function useRunSuiteCallback(suiteCallback, ...args) {
|
|
1687
|
+
const emit = VestRuntime.useEmit();
|
|
1879
1688
|
return () => {
|
|
1880
1689
|
suiteCallback(...args);
|
|
1690
|
+
emit(Events.SUITE_CALLBACK_RUN_FINISHED);
|
|
1881
1691
|
return useSuiteRunResult();
|
|
1882
1692
|
};
|
|
1883
1693
|
}
|
|
@@ -1911,19 +1721,45 @@ function each(list, callback) {
|
|
|
1911
1721
|
});
|
|
1912
1722
|
}
|
|
1913
1723
|
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1724
|
+
/**
|
|
1725
|
+
* Creates a static suite for server-side validation.
|
|
1726
|
+
*
|
|
1727
|
+
* @param {Function} validationFn - The validation function that defines the suite's tests.
|
|
1728
|
+
* @returns {Function} - A function that runs the validations defined in the suite.
|
|
1729
|
+
*
|
|
1730
|
+
* @example
|
|
1731
|
+
* import { staticSuite, test, enforce } from 'vest';
|
|
1732
|
+
*
|
|
1733
|
+
* const suite = staticSuite(data => {
|
|
1734
|
+
* test('username', 'username is required', () => {
|
|
1735
|
+
* enforce(data.username).isNotEmpty();
|
|
1736
|
+
* });
|
|
1737
|
+
* });
|
|
1738
|
+
*
|
|
1739
|
+
* suite(data);
|
|
1740
|
+
*/
|
|
1920
1741
|
function staticSuite(suiteCallback) {
|
|
1921
1742
|
return assign((...args) => createSuite(suiteCallback)(...args), Object.assign({}, getTypedMethods()));
|
|
1922
1743
|
}
|
|
1923
1744
|
|
|
1924
1745
|
const ERROR_OUTSIDE_OF_TEST = ErrorStrings.WARN_MUST_BE_CALLED_FROM_TEST;
|
|
1925
1746
|
/**
|
|
1926
|
-
* Sets a
|
|
1747
|
+
* Sets the severity level of a test to `warn`, allowing it to fail without marking the suite as invalid.
|
|
1748
|
+
* Use this function within the body of a test to create warn-only tests.
|
|
1749
|
+
*
|
|
1750
|
+
* @returns {void}
|
|
1751
|
+
*
|
|
1752
|
+
* @example
|
|
1753
|
+
* test('password', 'Your password strength is: WEAK', () => {
|
|
1754
|
+
* warn();
|
|
1755
|
+
*
|
|
1756
|
+
* enforce(data.password).matches(/0-9/);
|
|
1757
|
+
* });
|
|
1758
|
+
*
|
|
1759
|
+
* @limitations
|
|
1760
|
+
* - The `warn` function should only be used within the body of a `test` function.
|
|
1761
|
+
* - When using `warn()` in an async test, it should be called in the synchronous portion of the test, not after an `await` call or in the Promise body.
|
|
1762
|
+
* - It is recommended to call `warn()` at the top of the test function.
|
|
1927
1763
|
*/
|
|
1928
1764
|
// @vx-allow use-use
|
|
1929
1765
|
function warn() {
|