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