vest 4.0.0-dev-7acb76 → 4.0.0-dev-1aae50

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 (73) hide show
  1. package/CHANGELOG.md +70 -50
  2. package/README.md +2 -112
  3. package/dist/cjs/classnames.development.js +3 -3
  4. package/dist/cjs/classnames.production.js +1 -1
  5. package/dist/cjs/compose.js +7 -0
  6. package/dist/cjs/compounds.js +7 -0
  7. package/dist/cjs/enforce/compose.development.js +139 -0
  8. package/dist/cjs/enforce/compose.production.js +1 -0
  9. package/dist/cjs/enforce/compounds.development.js +132 -0
  10. package/dist/cjs/enforce/compounds.production.js +1 -0
  11. package/dist/cjs/enforce/package.json +1 -0
  12. package/dist/cjs/enforce/schema.development.js +144 -0
  13. package/dist/cjs/enforce/schema.production.js +1 -0
  14. package/dist/cjs/promisify.development.js +1 -1
  15. package/dist/cjs/promisify.production.js +1 -1
  16. package/dist/cjs/schema.js +7 -0
  17. package/dist/cjs/vest.development.js +582 -1083
  18. package/dist/cjs/vest.production.js +1 -1
  19. package/dist/es/classnames.development.js +3 -3
  20. package/dist/es/classnames.production.js +1 -1
  21. package/dist/es/enforce/compose.development.js +137 -0
  22. package/dist/es/enforce/compose.production.js +1 -0
  23. package/dist/es/enforce/compounds.development.js +130 -0
  24. package/dist/es/enforce/compounds.production.js +1 -0
  25. package/dist/es/enforce/package.json +1 -0
  26. package/dist/es/enforce/schema.development.js +140 -0
  27. package/dist/es/enforce/schema.production.js +1 -0
  28. package/dist/es/promisify.development.js +1 -1
  29. package/dist/es/promisify.production.js +1 -1
  30. package/dist/es/vest.development.js +577 -1084
  31. package/dist/es/vest.production.js +1 -1
  32. package/dist/umd/classnames.development.js +3 -3
  33. package/dist/umd/classnames.production.js +1 -1
  34. package/dist/umd/enforce/compose.development.js +143 -0
  35. package/dist/umd/enforce/compose.production.js +1 -0
  36. package/dist/umd/enforce/compounds.development.js +136 -0
  37. package/dist/umd/enforce/compounds.production.js +1 -0
  38. package/dist/umd/enforce/schema.development.js +148 -0
  39. package/dist/umd/enforce/schema.production.js +1 -0
  40. package/dist/umd/promisify.development.js +1 -1
  41. package/dist/umd/promisify.production.js +1 -1
  42. package/dist/umd/vest.development.js +1693 -2197
  43. package/dist/umd/vest.production.js +1 -1
  44. package/enforce/compose/package.json +7 -0
  45. package/enforce/compounds/package.json +7 -0
  46. package/enforce/schema/package.json +7 -0
  47. package/package.json +107 -13
  48. package/testUtils/mockThrowError.ts +16 -0
  49. package/types/classnames.d.ts +2 -2
  50. package/types/enforce/compose.d.ts +134 -0
  51. package/types/enforce/compounds.d.ts +146 -0
  52. package/types/enforce/schema.d.ts +151 -0
  53. package/types/vest.d.ts +31 -196
  54. package/docs/.nojekyll +0 -0
  55. package/docs/README.md +0 -113
  56. package/docs/_assets/favicon.ico +0 -0
  57. package/docs/_assets/vest-logo.png +0 -0
  58. package/docs/_sidebar.md +0 -14
  59. package/docs/cross_field_validations.md +0 -33
  60. package/docs/enforce.md +0 -11
  61. package/docs/exclusion.md +0 -129
  62. package/docs/getting_started.md +0 -72
  63. package/docs/group.md +0 -142
  64. package/docs/index.html +0 -41
  65. package/docs/migration.md +0 -202
  66. package/docs/n4s/rules.md +0 -1282
  67. package/docs/node.md +0 -36
  68. package/docs/optional.md +0 -103
  69. package/docs/result.md +0 -249
  70. package/docs/state.md +0 -102
  71. package/docs/test.md +0 -172
  72. package/docs/utilities.md +0 -109
  73. package/docs/warn.md +0 -82
@@ -1,2204 +1,1700 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vest = {}));
5
- }(this, (function (exports) { 'use strict';
6
-
7
- /*! *****************************************************************************
8
- Copyright (c) Microsoft Corporation.
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('n4s'), require('context')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'n4s', 'context'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vest = {}, global.n4s, global.context));
5
+ }(this, (function (exports, n4s, context$1) { 'use strict';
6
+
7
+ var assign = Object.assign;
8
+
9
+ /**
10
+ * @returns a unique numeric id.
11
+ */
12
+ var genId = (function (n) { return function () {
13
+ return "" + n++;
14
+ }; })(0);
15
+
16
+ function isFunction(value) {
17
+ return typeof value === 'function';
18
+ }
19
+
20
+ function optionalFunctionValue(value) {
21
+ var args = [];
22
+ for (var _i = 1; _i < arguments.length; _i++) {
23
+ args[_i - 1] = arguments[_i];
24
+ }
25
+ return isFunction(value) ? value.apply(void 0, args) : value;
26
+ }
27
+
28
+ function defaultTo(callback, defaultValue) {
29
+ var _a;
30
+ return (_a = optionalFunctionValue(callback)) !== null && _a !== void 0 ? _a : defaultValue;
31
+ }
32
+
33
+ /**
34
+ * Throws a timed out error.
35
+ */
36
+ function throwError(devMessage, productionMessage) {
37
+ throw new Error(devMessage );
38
+ }
39
+ function throwErrorDeferred(devMessage, productionMessage) {
40
+ setTimeout(function () {
41
+ throwError(devMessage);
42
+ }, 0);
43
+ }
44
+
45
+ // eslint-disable-next-line max-lines-per-function
46
+ function createState(onStateChange) {
47
+ var state = {
48
+ references: []
49
+ };
50
+ var registrations = [];
51
+ return {
52
+ registerStateKey: registerStateKey,
53
+ reset: reset
54
+ };
55
+ /**
56
+ * Registers a new key in the state, takes the initial value (may be a function that returns the initial value), returns a function.
57
+ *
58
+ * @example
59
+ *
60
+ * const useColor = state.registerStateKey("blue");
61
+ *
62
+ * let [color, setColor] = useColor(); // -> ["blue", Function]
63
+ *
64
+ * setColor("green");
65
+ *
66
+ * useColor()[0]; -> "green"
67
+ */
68
+ function registerStateKey(initialState, onUpdate) {
69
+ var key = registrations.length;
70
+ registrations.push([initialState, onUpdate]);
71
+ return initKey(key, initialState);
72
+ }
73
+ function reset() {
74
+ var prev = current();
75
+ state.references = [];
76
+ registrations.forEach(function (_a, index) {
77
+ var initialValue = _a[0];
78
+ return initKey(index, initialValue, prev[index]);
79
+ });
80
+ }
81
+ function initKey(key, initialState, prevState) {
82
+ current().push();
83
+ set(key, optionalFunctionValue(initialState, prevState));
84
+ return function useStateKey() {
85
+ return [
86
+ current()[key],
87
+ function (nextState) {
88
+ return set(key, optionalFunctionValue(nextState, current()[key]));
89
+ },
90
+ ];
91
+ };
92
+ }
93
+ function current() {
94
+ return state.references;
95
+ }
96
+ function set(index, value) {
97
+ var prevValue = state.references[index];
98
+ state.references[index] = value;
99
+ var _a = registrations[index], onUpdate = _a[1];
100
+ if (isFunction(onUpdate)) {
101
+ onUpdate(value, prevValue);
102
+ }
103
+ if (isFunction(onStateChange)) {
104
+ onStateChange();
105
+ }
106
+ }
107
+ }
108
+
109
+ var IsolateTypes;
110
+ (function (IsolateTypes) {
111
+ IsolateTypes[IsolateTypes["DEFAULT"] = 0] = "DEFAULT";
112
+ IsolateTypes[IsolateTypes["SUITE"] = 1] = "SUITE";
113
+ IsolateTypes[IsolateTypes["EACH"] = 2] = "EACH";
114
+ IsolateTypes[IsolateTypes["SKIP_WHEN"] = 3] = "SKIP_WHEN";
115
+ IsolateTypes[IsolateTypes["GROUP"] = 4] = "GROUP";
116
+ })(IsolateTypes || (IsolateTypes = {}));
117
+
118
+ function createStateRef(state, _a) {
119
+ var suiteId = _a.suiteId, suiteName = _a.suiteName;
120
+ return {
121
+ optionalFields: state.registerStateKey(function () { return ({}); }),
122
+ suiteId: state.registerStateKey(suiteId),
123
+ suiteName: state.registerStateKey(suiteName),
124
+ testCallbacks: state.registerStateKey(function () { return ({
125
+ fieldCallbacks: {},
126
+ doneCallbacks: []
127
+ }); }),
128
+ testObjects: state.registerStateKey(function (prev) {
129
+ return {
130
+ prev: prev ? prev.current : [],
131
+ current: []
132
+ };
133
+ })
134
+ };
135
+ }
136
+
137
+ function asArray(possibleArg) {
138
+ return [].concat(possibleArg);
139
+ }
140
+
141
+ function last(values) {
142
+ var valuesArray = asArray(values);
143
+ return valuesArray[valuesArray.length - 1];
144
+ }
145
+
146
+ function createCursor() {
147
+ var storage = {
148
+ cursor: []
149
+ };
150
+ function addLevel() {
151
+ storage.cursor.push(0);
152
+ }
153
+ function removeLevel() {
154
+ storage.cursor.pop();
155
+ }
156
+ function cursorAt() {
157
+ return last(storage.cursor);
158
+ }
159
+ function getCursor() {
160
+ return asArray(storage.cursor);
161
+ }
162
+ function next() {
163
+ storage.cursor[storage.cursor.length - 1]++;
164
+ return last(storage.cursor);
165
+ }
166
+ function reset() {
167
+ storage.cursor = [0];
168
+ }
169
+ reset();
170
+ return {
171
+ addLevel: addLevel,
172
+ cursorAt: cursorAt,
173
+ getCursor: getCursor,
174
+ next: next,
175
+ removeLevel: removeLevel,
176
+ reset: reset
177
+ };
178
+ }
179
+
180
+ var context = context$1.createContext(function (ctxRef, parentContext) {
181
+ return parentContext
182
+ ? null
183
+ : assign({}, {
184
+ exclusion: {
185
+ tests: {},
186
+ groups: {}
187
+ },
188
+ isolate: {
189
+ type: IsolateTypes.DEFAULT,
190
+ keys: {
191
+ current: {},
192
+ prev: {}
193
+ }
194
+ },
195
+ testCursor: createCursor()
196
+ }, ctxRef);
197
+ });
198
+
199
+ function bindNot(fn) {
200
+ return function () {
201
+ var args = [];
202
+ for (var _i = 0; _i < arguments.length; _i++) {
203
+ args[_i] = arguments[_i];
204
+ }
205
+ return !fn.apply(void 0, args);
206
+ };
207
+ }
208
+
209
+ // The module is named "isArrayValue" since it
210
+ // is conflicting with a nested npm dependency.
211
+ // We may need to revisit this in the future.
212
+ function isArray(value) {
213
+ return Boolean(Array.isArray(value));
214
+ }
215
+
216
+ function isNull(value) {
217
+ return value === null;
218
+ }
219
+ var isNotNull = bindNot(isNull);
220
+
221
+ // This is sort of a map/filter in one function.
222
+ // Normally, behaves like a nested-array map
223
+ // Returning `null` will drop the element from the array
224
+ function transform(array, cb) {
225
+ var res = [];
226
+ for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
227
+ var v = array_1[_i];
228
+ if (isArray(v)) {
229
+ res.push(transform(v, cb));
230
+ }
231
+ else {
232
+ var output = cb(v);
233
+ if (isNotNull(output)) {
234
+ res.push(output);
235
+ }
236
+ }
237
+ }
238
+ return res;
239
+ }
240
+ function valueAtPath(array, path) {
241
+ return getCurrent(array, path)[last(path)];
242
+ }
243
+ function setValueAtPath(array, path, value) {
244
+ var current = getCurrent(array, path);
245
+ current[last(path)] = value;
246
+ return array;
247
+ }
248
+ function flatten(values) {
249
+ return asArray(values).reduce(function (acc, value) {
250
+ if (isArray(value)) {
251
+ return acc.concat(flatten(value));
252
+ }
253
+ return asArray(acc).concat(value);
254
+ }, []);
255
+ }
256
+ function getCurrent(array, path) {
257
+ var current = array;
258
+ for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
259
+ var p = _a[_i];
260
+ current[p] = defaultTo(current[p], []);
261
+ current = current[p];
262
+ }
263
+ return current;
264
+ }
265
+
266
+ function isUndefined(value) {
267
+ return value === undefined;
268
+ }
269
+
270
+ function isNullish(value) {
271
+ return isNull(value) || isUndefined(value);
272
+ }
273
+
274
+ function isStringValue(v) {
275
+ return String(v) === v;
276
+ }
277
+
278
+ function shouldUseErrorAsMessage(message, error) {
279
+ // kind of cheating with this safe guard, but it does the job
280
+ return isUndefined(message) && isStringValue(error);
281
+ }
282
+
283
+ function lengthEquals(value, arg1) {
284
+ return value.length === Number(arg1);
285
+ }
286
+
287
+ function longerThan(value, arg1) {
288
+ return value.length > Number(arg1);
289
+ }
290
+
291
+ /**
292
+ * Creates a cache function
293
+ */
294
+ function createCache(maxSize) {
295
+ if (maxSize === void 0) { maxSize = 1; }
296
+ var cacheStorage = [];
297
+ var cache = function (deps, cacheAction) {
298
+ var cacheHit = cache.get(deps);
299
+ // cache hit is not null
300
+ if (cacheHit)
301
+ return cacheHit[1];
302
+ var result = cacheAction();
303
+ cacheStorage.unshift([deps.concat(), result]);
304
+ if (longerThan(cacheStorage, maxSize))
305
+ cacheStorage.length = maxSize;
306
+ return result;
307
+ };
308
+ // invalidate an item in the cache by its dependencies
309
+ cache.invalidate = function (deps) {
310
+ var index = cacheStorage.findIndex(function (_a) {
311
+ var cachedDeps = _a[0];
312
+ return lengthEquals(deps, cachedDeps.length) &&
313
+ deps.every(function (dep, i) { return dep === cachedDeps[i]; });
314
+ });
315
+ if (index > -1)
316
+ cacheStorage.splice(index, 1);
317
+ };
318
+ // Retrieves an item from the cache.
319
+ cache.get = function (deps) {
320
+ return cacheStorage[cacheStorage.findIndex(function (_a) {
321
+ var cachedDeps = _a[0];
322
+ return lengthEquals(deps, cachedDeps.length) &&
323
+ deps.every(function (dep, i) { return dep === cachedDeps[i]; });
324
+ })] || null;
325
+ };
326
+ return cache;
327
+ }
328
+
329
+ // STATE REF
330
+ function useStateRef() {
331
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
332
+ return context.useX().stateRef; // I should revisit this
333
+ }
334
+ // STATE KEYS
335
+ function useSuiteId() {
336
+ return useStateRef().suiteId()[0];
337
+ }
338
+ function useSuiteName() {
339
+ return useStateRef().suiteName()[0];
340
+ }
341
+ function useTestCallbacks() {
342
+ return useStateRef().testCallbacks();
343
+ }
344
+ function useOptionalFields() {
345
+ return useStateRef().optionalFields();
346
+ }
347
+ function useTestObjects() {
348
+ return useStateRef().testObjects();
349
+ }
350
+ // STATE ACTIONS
351
+ function useRefreshTestObjects() {
352
+ var _a = useTestObjects(), setTestObjects = _a[1];
353
+ setTestObjects(function (_a) {
354
+ var current = _a.current, prev = _a.prev;
355
+ return ({
356
+ prev: prev,
357
+ current: asArray(current)
358
+ });
359
+ });
360
+ }
361
+ function useSetTests(handler) {
362
+ var _a = useTestObjects(), testObjects = _a[1];
363
+ testObjects(function (_a) {
364
+ var current = _a.current, prev = _a.prev;
365
+ return ({
366
+ prev: prev,
367
+ current: asArray(handler(current))
368
+ });
369
+ });
370
+ }
371
+ // Derived state
372
+ function useAllIncomplete() {
373
+ var current = useTestObjects()[0].current;
374
+ return flatten(transform(current, function (testObject) {
375
+ return testObject.isPending() ? testObject : null;
376
+ }));
377
+ }
378
+ function useOmittedFields() {
379
+ var testObjects = useTestsFlat();
380
+ return testObjects.reduce(function (omittedFields, testObject) {
381
+ if (omittedFields[testObject.fieldName]) {
382
+ return omittedFields;
383
+ }
384
+ if (testObject.isOmitted()) {
385
+ omittedFields[testObject.fieldName] = true;
386
+ }
387
+ return omittedFields;
388
+ }, {});
389
+ }
390
+ var flatCache = createCache();
391
+ function useTestsFlat() {
392
+ var current = useTestObjects()[0].current;
393
+ return flatCache([current], function () { return flatten(current); });
394
+ }
395
+
396
+ var TestSeverity;
397
+ (function (TestSeverity) {
398
+ TestSeverity["Error"] = "error";
399
+ TestSeverity["Warning"] = "warning";
400
+ })(TestSeverity || (TestSeverity = {}));
401
+ var VestTest = /** @class */ (function () {
402
+ function VestTest(fieldName, testFn, _a) {
403
+ var _b = _a === void 0 ? {} : _a, message = _b.message, groupName = _b.groupName, key = _b.key;
404
+ this.key = null;
405
+ this.id = genId();
406
+ this.severity = TestSeverity.Error;
407
+ this.status = STATUS_UNTESTED;
408
+ this.fieldName = fieldName;
409
+ this.testFn = testFn;
410
+ if (groupName) {
411
+ this.groupName = groupName;
412
+ }
413
+ if (message) {
414
+ this.message = message;
415
+ }
416
+ if (key) {
417
+ this.key = key;
418
+ }
419
+ }
420
+ VestTest.prototype.run = function () {
421
+ var result;
422
+ try {
423
+ result = this.testFn();
424
+ }
425
+ catch (error) {
426
+ if (shouldUseErrorAsMessage(this.message, error)) {
427
+ this.message = error;
428
+ }
429
+ result = false;
430
+ }
431
+ if (result === false) {
432
+ this.fail();
433
+ }
434
+ return result;
435
+ };
436
+ VestTest.prototype.setStatus = function (status) {
437
+ if (this.isFinalStatus() && status !== STATUS_OMITTED) {
438
+ return;
439
+ }
440
+ this.status = status;
441
+ };
442
+ VestTest.prototype.warns = function () {
443
+ return this.severity === TestSeverity.Warning;
444
+ };
445
+ VestTest.prototype.setPending = function () {
446
+ this.setStatus(STATUS_PENDING);
447
+ };
448
+ VestTest.prototype.fail = function () {
449
+ this.setStatus(this.warns() ? STATUS_WARNING : STATUS_FAILED);
450
+ };
451
+ VestTest.prototype.done = function () {
452
+ if (this.isFinalStatus()) {
453
+ return;
454
+ }
455
+ this.setStatus(STATUS_PASSING);
456
+ };
457
+ VestTest.prototype.warn = function () {
458
+ this.severity = TestSeverity.Warning;
459
+ };
460
+ VestTest.prototype.isFinalStatus = function () {
461
+ return this.hasFailures() || this.isCanceled() || this.isPassing();
462
+ };
463
+ VestTest.prototype.skip = function (force) {
464
+ if (this.isPending() && !force) {
465
+ // Without this condition, the test will be marked as skipped even if it is pending.
466
+ // This means that it will not be counted in "allIncomplete" and its done callbacks
467
+ // will not be called, or will be called prematurely.
468
+ // What this mostly say is that when we have a pending test for one field, and we then
469
+ // start typing in a different field - the pending test will be canceled, which
470
+ // is usually an unwanted behavior.
471
+ // The only scenario in which we DO want to cancel the async test regardless
472
+ // is when we specifically skip a test with `skipWhen`, which is handled by the
473
+ // "force" boolean flag.
474
+ // I am not a fan of this flag, but it gets the job done.
475
+ return;
476
+ }
477
+ this.setStatus(STATUS_SKIPPED);
478
+ };
479
+ VestTest.prototype.cancel = function () {
480
+ this.setStatus(STATUS_CANCELED);
481
+ useRefreshTestObjects();
482
+ };
483
+ VestTest.prototype.omit = function () {
484
+ this.setStatus(STATUS_OMITTED);
485
+ };
486
+ VestTest.prototype.valueOf = function () {
487
+ return !this.isFailing();
488
+ };
489
+ VestTest.prototype.hasFailures = function () {
490
+ return this.isFailing() || this.isWarning();
491
+ };
492
+ VestTest.prototype.isPending = function () {
493
+ return this.status === STATUS_PENDING;
494
+ };
495
+ VestTest.prototype.isTested = function () {
496
+ return this.hasFailures() || this.isPassing();
497
+ };
498
+ VestTest.prototype.isOmitted = function () {
499
+ return this.status === STATUS_OMITTED;
500
+ };
501
+ VestTest.prototype.isUntested = function () {
502
+ return this.status === STATUS_UNTESTED;
503
+ };
504
+ VestTest.prototype.isFailing = function () {
505
+ return this.status === STATUS_FAILED;
506
+ };
507
+ VestTest.prototype.isCanceled = function () {
508
+ return this.status === STATUS_CANCELED;
509
+ };
510
+ VestTest.prototype.isSkipped = function () {
511
+ return this.status === STATUS_SKIPPED;
512
+ };
513
+ VestTest.prototype.isPassing = function () {
514
+ return this.status === STATUS_PASSING;
515
+ };
516
+ VestTest.prototype.isWarning = function () {
517
+ return this.status === STATUS_WARNING;
518
+ };
519
+ return VestTest;
520
+ }());
521
+ var STATUS_UNTESTED = 'UNTESTED';
522
+ var STATUS_SKIPPED = 'SKIPPED';
523
+ var STATUS_FAILED = 'FAILED';
524
+ var STATUS_WARNING = 'WARNING';
525
+ var STATUS_PASSING = 'PASSING';
526
+ var STATUS_PENDING = 'PENDING';
527
+ var STATUS_CANCELED = 'CANCELED';
528
+ var STATUS_OMITTED = 'OMITTED';
529
+
530
+ function usePath() {
531
+ var context$1 = context.useX();
532
+ return context$1.testCursor.getCursor();
533
+ }
534
+ function useCursorAt() {
535
+ var context$1 = context.useX();
536
+ return context$1.testCursor.cursorAt();
537
+ }
538
+ function moveForward() {
539
+ var context$1 = context.useX();
540
+ return context$1.testCursor.next();
541
+ }
542
+ function addLevel() {
543
+ var context$1 = context.useX();
544
+ context$1.testCursor.addLevel();
545
+ }
546
+ function removeLevel() {
547
+ var context$1 = context.useX();
548
+ context$1.testCursor.removeLevel();
549
+ }
550
+
551
+ function usePrevKeys() {
552
+ var prev = useTestObjects()[0].prev;
553
+ return asArray(getCurrent(prev, usePath())).reduce(function (prevKeys, testObject) {
554
+ if (!(testObject instanceof VestTest)) {
555
+ return prevKeys;
556
+ }
557
+ if (isNullish(testObject.key)) {
558
+ return prevKeys;
559
+ }
560
+ prevKeys[testObject.key] = testObject;
561
+ return prevKeys;
562
+ }, {});
563
+ }
564
+ function usePrevTestByKey(key) {
565
+ var prev = context.useX().isolate.keys.prev;
566
+ return prev[key];
567
+ }
568
+ function useRetainTestKey(key, testObject) {
569
+ var context$1 = context.useX();
570
+ var current = context$1.isolate.keys.current;
571
+ if (isNullish(current[key])) {
572
+ current[key] = testObject;
573
+ }
574
+ else {
575
+ throwErrorDeferred("Encountered the same test key \"" + key + "\" twice. This may lead to tests overriding each other's results, or to tests being unexpectedly omitted.");
576
+ }
577
+ }
578
+
579
+ function isolate(_a, callback) {
580
+ var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
581
+ if (!isFunction(callback)) {
582
+ return;
583
+ }
584
+ var keys = {
585
+ current: {},
586
+ prev: {}
587
+ };
588
+ var path = usePath();
589
+ return context.run({ isolate: { type: type, keys: keys } }, function () {
590
+ addLevel();
591
+ keys.prev = usePrevKeys();
592
+ useSetTests(function (tests) { return setValueAtPath(tests, path, []); });
593
+ var res = callback();
594
+ removeLevel();
595
+ moveForward();
596
+ return res;
597
+ });
598
+ }
599
+ function shouldAllowReorder() {
600
+ return context.useX().isolate.type === IsolateTypes.EACH;
601
+ }
602
+
603
+ /**
604
+ * A safe hasOwnProperty access
605
+ */
606
+ function hasOwnProperty(obj, key) {
607
+ return Object.prototype.hasOwnProperty.call(obj, key);
608
+ }
609
+
610
+ function isNumber(value) {
611
+ return Boolean(typeof value === 'number');
612
+ }
613
+
614
+ function isEmpty(value) {
615
+ if (!value) {
616
+ return true;
617
+ }
618
+ else if (isNumber(value)) {
619
+ return value === 0;
620
+ }
621
+ else if (hasOwnProperty(value, 'length')) {
622
+ return lengthEquals(value, 0);
623
+ }
624
+ else if (typeof value === 'object') {
625
+ return lengthEquals(Object.keys(value), 0);
626
+ }
627
+ return true;
628
+ }
629
+ var isNotEmpty = bindNot(isEmpty);
630
+
631
+ function nonMatchingFieldName(testObject, fieldName) {
632
+ return !!fieldName && !matchingFieldName(testObject, fieldName);
633
+ }
634
+ function matchingFieldName(testObject, fieldName) {
635
+ return !!(fieldName && testObject.fieldName === fieldName);
636
+ }
637
+
638
+ /**
639
+ * Checks if a given field, or the suite as a whole still have remaining tests.
640
+ */
641
+ function hasRemainingTests(fieldName) {
642
+ var allIncomplete = useAllIncomplete();
643
+ if (isEmpty(allIncomplete)) {
644
+ return false;
645
+ }
646
+ if (fieldName) {
647
+ return allIncomplete.some(function (testObject) {
648
+ return matchingFieldName(testObject, fieldName);
649
+ });
650
+ }
651
+ return isNotEmpty(allIncomplete);
652
+ }
653
+
654
+ /**
655
+ * Reads the testObjects list and gets full validation result from it.
656
+ */
657
+ function genTestsSummary() {
658
+ var testObjects = useTestsFlat();
659
+ var summary = {
660
+ errorCount: 0,
661
+ groups: {},
662
+ testCount: 0,
663
+ tests: {},
664
+ warnCount: 0
665
+ };
666
+ appendSummary(testObjects);
667
+ return countFailures(summary);
668
+ function appendSummary(testObjects) {
669
+ testObjects.forEach(function (testObject) {
670
+ var fieldName = testObject.fieldName, groupName = testObject.groupName;
671
+ summary.tests[fieldName] = genTestObject(summary.tests, testObject);
672
+ if (groupName) {
673
+ summary.groups[groupName] = summary.groups[groupName] || {};
674
+ summary.groups[groupName][fieldName] = genTestObject(summary.groups[groupName], testObject);
675
+ }
676
+ });
677
+ }
678
+ }
679
+ /**
680
+ * Counts the failed tests and adds global counters
681
+ */
682
+ function countFailures(summary) {
683
+ for (var test in summary.tests) {
684
+ summary.errorCount += summary.tests[test].errorCount;
685
+ summary.warnCount += summary.tests[test].warnCount;
686
+ summary.testCount += summary.tests[test].testCount;
687
+ }
688
+ return summary;
689
+ }
690
+ // eslint-disable-next-line max-statements
691
+ function genTestObject(summaryKey, testObject) {
692
+ var fieldName = testObject.fieldName, message = testObject.message;
693
+ summaryKey[fieldName] = summaryKey[fieldName] || {
694
+ errorCount: 0,
695
+ warnCount: 0,
696
+ testCount: 0
697
+ };
698
+ var testKey = summaryKey[fieldName];
699
+ if (testObject.isSkipped())
700
+ return testKey;
701
+ summaryKey[fieldName].testCount++;
702
+ // Adds to severity group
703
+ function addTo(countKey, group) {
704
+ testKey[countKey]++;
705
+ if (message) {
706
+ testKey[group] = (testKey[group] || []).concat(message);
707
+ }
708
+ }
709
+ if (testObject.isFailing()) {
710
+ addTo('errorCount', 'errors');
711
+ }
712
+ else if (testObject.isWarning()) {
713
+ addTo('warnCount', 'warnings');
714
+ }
715
+ return testKey;
716
+ }
717
+
718
+ /*! *****************************************************************************
719
+ Copyright (c) Microsoft Corporation.
9
720
 
10
- Permission to use, copy, modify, and/or distribute this software for any
11
- purpose with or without fee is hereby granted.
721
+ Permission to use, copy, modify, and/or distribute this software for any
722
+ purpose with or without fee is hereby granted.
12
723
 
13
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
14
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
16
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19
- PERFORMANCE OF THIS SOFTWARE.
20
- ***************************************************************************** */
724
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
725
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
726
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
727
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
728
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
729
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
730
+ PERFORMANCE OF THIS SOFTWARE.
731
+ ***************************************************************************** */
21
732
 
22
- var __assign = function() {
23
- __assign = Object.assign || function __assign(t) {
24
- for (var s, i = 1, n = arguments.length; i < n; i++) {
25
- s = arguments[i];
26
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
27
- }
28
- return t;
29
- };
30
- return __assign.apply(this, arguments);
31
- };
733
+ var __assign = function() {
734
+ __assign = Object.assign || function __assign(t) {
735
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
736
+ s = arguments[i];
737
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
738
+ }
739
+ return t;
740
+ };
741
+ return __assign.apply(this, arguments);
742
+ };
32
743
 
33
- function __spreadArray(to, from, pack) {
34
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
35
- if (ar || !(i in from)) {
36
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
37
- ar[i] = from[i];
38
- }
39
- }
40
- return to.concat(ar || from);
41
- }
42
-
43
- var assign = Object.assign;
44
-
45
- function isFunction(value) {
46
- return typeof value === 'function';
47
- }
48
-
49
- function mapFirst(array, callback) {
50
- var broke = false;
51
- var breakoutValue = null;
52
- for (var i = 0; i < array.length; i++) {
53
- callback(array[i], breakout, i);
54
- if (broke) {
55
- return breakoutValue;
56
- }
57
- }
58
- function breakout(value) {
59
- broke = true;
60
- breakoutValue = value;
61
- }
62
- }
63
-
64
- function optionalFunctionValue(value) {
65
- var args = [];
66
- for (var _i = 1; _i < arguments.length; _i++) {
67
- args[_i - 1] = arguments[_i];
68
- }
69
- return isFunction(value) ? value.apply(void 0, args) : value;
70
- }
71
-
72
- function defaultTo(callback, defaultValue) {
73
- var _a;
74
- return (_a = optionalFunctionValue(callback)) !== null && _a !== void 0 ? _a : defaultValue;
75
- }
76
-
77
- function ruleReturn(pass, message) {
78
- var output = { pass: pass };
79
- if (message) {
80
- output.message = message;
81
- }
82
- return output;
83
- }
84
- function failing() {
85
- return ruleReturn(false);
86
- }
87
- function passing() {
88
- return ruleReturn(true);
89
- }
90
- function defaultToFailing(callback) {
91
- return defaultTo(callback, failing());
92
- }
93
- function defaultToPassing(callback) {
94
- return defaultTo(callback, passing());
95
- }
96
-
97
- function runLazyRule(lazyRule, currentValue) {
98
- try {
99
- return lazyRule.run(currentValue);
100
- }
101
- catch (_a) {
102
- return failing();
103
- }
104
- }
105
-
106
- function allOf(value) {
107
- var rules = [];
108
- for (var _i = 1; _i < arguments.length; _i++) {
109
- rules[_i - 1] = arguments[_i];
110
- }
111
- return defaultToPassing(mapFirst(rules, function (rule, breakout) {
112
- var res = runLazyRule(rule, value);
113
- if (!res.pass) {
114
- breakout(res);
115
- }
116
- }));
117
- }
118
-
119
- function anyOf(value) {
120
- var rules = [];
121
- for (var _i = 1; _i < arguments.length; _i++) {
122
- rules[_i - 1] = arguments[_i];
123
- }
124
- return defaultToFailing(mapFirst(rules, function (rule, breakout) {
125
- var res = runLazyRule(rule, value);
126
- if (res.pass) {
127
- breakout(res);
128
- }
129
- }));
130
- }
131
-
132
- function noneOf(value) {
133
- var rules = [];
134
- for (var _i = 1; _i < arguments.length; _i++) {
135
- rules[_i - 1] = arguments[_i];
136
- }
137
- return defaultToPassing(mapFirst(rules, function (rule, breakout) {
138
- var res = runLazyRule(rule, value);
139
- if (res.pass) {
140
- breakout(failing());
141
- }
142
- }));
143
- }
144
-
145
- function bindNot(fn) {
146
- return function () {
147
- var args = [];
148
- for (var _i = 0; _i < arguments.length; _i++) {
149
- args[_i] = arguments[_i];
150
- }
151
- return !fn.apply(void 0, args);
152
- };
153
- }
154
-
155
- function lengthEquals(value, arg1) {
156
- return value.length === Number(arg1);
157
- }
158
- var lengthNotEquals = bindNot(lengthEquals);
159
-
160
- function longerThan(value, arg1) {
161
- return value.length > Number(arg1);
162
- }
163
-
164
- function oneOf(value) {
165
- var rules = [];
166
- for (var _i = 1; _i < arguments.length; _i++) {
167
- rules[_i - 1] = arguments[_i];
168
- }
169
- var passing = [];
170
- rules.some(function (rule) {
171
- if (longerThan(passing, 1)) {
172
- return false;
173
- }
174
- var res = runLazyRule(rule, value);
175
- if (res.pass) {
176
- passing.push(res);
177
- }
178
- });
179
- return ruleReturn(lengthEquals(passing, 1));
180
- }
181
-
182
- function isNull(value) {
183
- return value === null;
184
- }
185
- var isNotNull = bindNot(isNull);
186
-
187
- function isUndefined(value) {
188
- return value === undefined;
189
- }
190
- var isNotUndefined = bindNot(isUndefined);
191
-
192
- function optional$1(value, ruleChain) {
193
- if (isUndefined(value) || isNull(value)) {
194
- return passing();
195
- }
196
- return runLazyRule(ruleChain, value);
197
- }
198
-
199
- function compounds() {
200
- return { allOf: allOf, anyOf: anyOf, noneOf: noneOf, oneOf: oneOf, optional: optional$1 };
201
- }
202
-
203
- function isStringValue(v) {
204
- return String(v) === v;
205
- }
206
-
207
- function endsWith(value, arg1) {
208
- return isStringValue(value) && isStringValue(arg1) && value.endsWith(arg1);
209
- }
210
- var doesNotEndWith = bindNot(endsWith);
211
-
212
- function equals(value, arg1) {
213
- return value === arg1;
214
- }
215
- var notEquals = bindNot(equals);
216
-
217
- function isNumeric(value) {
218
- var str = String(value);
219
- var num = Number(value);
220
- var result = !isNaN(parseFloat(str)) && !isNaN(Number(value)) && isFinite(num);
221
- return Boolean(result);
222
- }
223
- var isNotNumeric = bindNot(isNumeric);
224
-
225
- function greaterThan(value, gt) {
226
- return isNumeric(value) && isNumeric(gt) && Number(value) > Number(gt);
227
- }
228
-
229
- function greaterThanOrEquals(value, gte) {
230
- return isNumeric(value) && isNumeric(gte) && Number(value) >= Number(gte);
231
- }
232
-
233
- // The module is named "isArrayValue" since it
234
- // is conflicting with a nested npm dependency.
235
- // We may need to revisit this in the future.
236
- function isArray(value) {
237
- return Boolean(Array.isArray(value));
238
- }
239
- var isNotArray = bindNot(isArray);
240
-
241
- function inside(value, arg1) {
242
- if (isArray(arg1)) {
243
- return arg1.indexOf(value) !== -1;
244
- }
245
- // both value and arg1 are strings
246
- if (isStringValue(arg1) && isStringValue(value)) {
247
- return arg1.indexOf(value) !== -1;
248
- }
249
- return false;
250
- }
251
- var notInside = bindNot(inside);
252
-
253
- function lessThanOrEquals(value, lte) {
254
- return isNumeric(value) && isNumeric(lte) && Number(value) <= Number(lte);
255
- }
256
-
257
- function isBetween(value, min, max) {
258
- return greaterThanOrEquals(value, min) && lessThanOrEquals(value, max);
259
- }
260
- var isNotBetween = bindNot(isBetween);
261
-
262
- function isBlank(value) {
263
- return isStringValue(value) && !value.trim();
264
- }
265
- var isNotBlank = bindNot(isBlank);
266
-
267
- function isBoolean(value) {
268
- return !!value === value;
269
- }
270
-
271
- var isNotBoolean = bindNot(isBoolean);
272
-
273
- /**
274
- * A safe hasOwnProperty access
275
- */
276
- function hasOwnProperty(obj, key) {
277
- return Object.prototype.hasOwnProperty.call(obj, key);
278
- }
279
-
280
- function isNumber(value) {
281
- return Boolean(typeof value === 'number');
282
- }
283
- var isNotNumber = bindNot(isNumber);
284
-
285
- function isEmpty(value) {
286
- if (!value) {
287
- return true;
288
- }
289
- else if (isNumber(value)) {
290
- return value === 0;
291
- }
292
- else if (hasOwnProperty(value, 'length')) {
293
- return lengthEquals(value, 0);
294
- }
295
- else if (typeof value === 'object') {
296
- return lengthEquals(Object.keys(value), 0);
297
- }
298
- return true;
299
- }
300
- var isNotEmpty = bindNot(isEmpty);
301
-
302
- /**
303
- * Validates that a given value is an even number
304
- */
305
- var isEven = function (value) {
306
- if (isNumeric(value)) {
307
- return value % 2 === 0;
308
- }
309
- return false;
310
- };
311
-
312
- function isNaN$1(value) {
313
- return Number.isNaN(value);
314
- }
315
- var isNotNaN = bindNot(isNaN$1);
316
-
317
- function isNegative(value) {
318
- if (isNumeric(value)) {
319
- return Number(value) < 0;
320
- }
321
- return false;
322
- }
323
- var isPositive = bindNot(isNegative);
324
-
325
- /**
326
- * Validates that a given value is an odd number
327
- */
328
- var isOdd = function (value) {
329
- if (isNumeric(value)) {
330
- return value % 2 !== 0;
331
- }
332
- return false;
333
- };
334
-
335
- var isNotString = bindNot(isStringValue);
336
-
337
- function isTruthy(value) {
338
- return !!value;
339
- }
340
- var isFalsy = bindNot(isTruthy);
341
-
342
- function lessThan(value, lt) {
343
- return isNumeric(value) && isNumeric(lt) && Number(value) < Number(lt);
344
- }
345
-
346
- function longerThanOrEquals(value, arg1) {
347
- return value.length >= Number(arg1);
348
- }
349
-
350
- function matches(value, regex) {
351
- if (regex instanceof RegExp) {
352
- return regex.test(value);
353
- }
354
- else if (isStringValue(regex)) {
355
- return new RegExp(regex).test(value);
356
- }
357
- else {
358
- return false;
359
- }
360
- }
361
- var notMatches = bindNot(matches);
362
-
363
- function numberEquals(value, eq) {
364
- return isNumeric(value) && isNumeric(eq) && Number(value) === Number(eq);
365
- }
366
- var numberNotEquals = bindNot(numberEquals);
367
-
368
- function condition(value, callback) {
369
- try {
370
- return callback(value);
371
- }
372
- catch (_a) {
373
- return false;
374
- }
375
- }
376
-
377
- function shorterThan(value, arg1) {
378
- return value.length < Number(arg1);
379
- }
380
-
381
- function shorterThanOrEquals(value, arg1) {
382
- return value.length <= Number(arg1);
383
- }
384
-
385
- function startsWith(value, arg1) {
386
- return isStringValue(value) && isStringValue(arg1) && value.startsWith(arg1);
387
- }
388
- var doesNotStartWith = bindNot(startsWith);
389
-
390
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, max-lines-per-function
391
- function rules() {
392
- return {
393
- condition: condition,
394
- doesNotEndWith: doesNotEndWith,
395
- doesNotStartWith: doesNotStartWith,
396
- endsWith: endsWith,
397
- equals: equals,
398
- greaterThan: greaterThan,
399
- greaterThanOrEquals: greaterThanOrEquals,
400
- gt: greaterThan,
401
- gte: greaterThanOrEquals,
402
- inside: inside,
403
- isArray: isArray,
404
- isBetween: isBetween,
405
- isBlank: isBlank,
406
- isBoolean: isBoolean,
407
- isEmpty: isEmpty,
408
- isEven: isEven,
409
- isFalsy: isFalsy,
410
- isNaN: isNaN$1,
411
- isNegative: isNegative,
412
- isNotArray: isNotArray,
413
- isNotBetween: isNotBetween,
414
- isNotBlank: isNotBlank,
415
- isNotBoolean: isNotBoolean,
416
- isNotEmpty: isNotEmpty,
417
- isNotNaN: isNotNaN,
418
- isNotNull: isNotNull,
419
- isNotNumber: isNotNumber,
420
- isNotNumeric: isNotNumeric,
421
- isNotString: isNotString,
422
- isNotUndefined: isNotUndefined,
423
- isNull: isNull,
424
- isNumber: isNumber,
425
- isNumeric: isNumeric,
426
- isOdd: isOdd,
427
- isPositive: isPositive,
428
- isString: isStringValue,
429
- isTruthy: isTruthy,
430
- isUndefined: isUndefined,
431
- lengthEquals: lengthEquals,
432
- lengthNotEquals: lengthNotEquals,
433
- lessThan: lessThan,
434
- lessThanOrEquals: lessThanOrEquals,
435
- longerThan: longerThan,
436
- longerThanOrEquals: longerThanOrEquals,
437
- lt: lessThan,
438
- lte: lessThanOrEquals,
439
- matches: matches,
440
- notEquals: notEquals,
441
- notInside: notInside,
442
- notMatches: notMatches,
443
- numberEquals: numberEquals,
444
- numberNotEquals: numberNotEquals,
445
- shorterThan: shorterThan,
446
- shorterThanOrEquals: shorterThanOrEquals,
447
- startsWith: startsWith
448
- };
449
- }
450
-
451
- /**
452
- * Throws a timed out error.
453
- */
454
- function throwError(devMessage, productionMessage) {
455
- throw new Error(devMessage );
456
- }
457
- function throwErrorDeferred(devMessage, productionMessage) {
458
- setTimeout(function () {
459
- throwError(devMessage);
460
- }, 0);
461
- }
462
-
463
- // eslint-disable-next-line max-lines-per-function
464
- function createContext(init) {
465
- var storage = { ancestry: [] };
466
- return {
467
- bind: bind,
468
- run: run,
469
- use: use,
470
- useX: useX
471
- };
472
- function useX(errorMessage) {
473
- var _a;
474
- return ((_a = storage.ctx) !== null && _a !== void 0 ? _a : throwError(defaultTo(errorMessage, 'Context was used after it was closed')));
475
- }
476
- function run(ctxRef, fn) {
477
- var _a;
478
- var parentContext = use();
479
- var out = assign({}, parentContext ? parentContext : {}, (_a = init === null || init === void 0 ? void 0 : init(ctxRef, parentContext)) !== null && _a !== void 0 ? _a : ctxRef);
480
- var ctx = set(Object.freeze(out));
481
- storage.ancestry.unshift(ctx);
482
- var res = fn(ctx);
483
- clear();
484
- return res;
485
- }
486
- function bind(ctxRef, fn) {
487
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
488
- // @ts-ignore - this one's pretty hard to get right
489
- var returnedFn = function () {
490
- var runTimeArgs = [];
491
- for (var _i = 0; _i < arguments.length; _i++) {
492
- runTimeArgs[_i] = arguments[_i];
493
- }
494
- return run(ctxRef, function () {
495
- return fn.apply(void 0, runTimeArgs);
496
- });
497
- };
498
- return returnedFn;
499
- }
500
- function use() {
501
- return storage.ctx;
502
- }
503
- function set(value) {
504
- return (storage.ctx = value);
505
- }
506
- function clear() {
507
- var _a;
508
- storage.ancestry.shift();
509
- set((_a = storage.ancestry[0]) !== null && _a !== void 0 ? _a : null);
510
- }
511
- }
512
-
513
- var ctx$1 = createContext(function (ctxRef, parentContext) {
514
- var base = {
515
- value: ctxRef.value,
516
- meta: ctxRef.meta || {}
517
- };
518
- if (!parentContext) {
519
- return assign(base, {
520
- parent: emptyParent
521
- });
522
- }
523
- else if (ctxRef.set) {
524
- return assign(base, {
525
- parent: function () { return stripContext(parentContext); }
526
- });
527
- }
528
- return parentContext;
529
- });
530
- function stripContext(ctx) {
531
- if (!ctx) {
532
- return ctx;
533
- }
534
- return {
535
- value: ctx.value,
536
- meta: ctx.meta,
537
- parent: ctx.parent
538
- };
539
- }
540
- function emptyParent() {
541
- return null;
542
- }
543
-
544
- function isArrayOf(inputArray, currentRule) {
545
- return defaultToPassing(mapFirst(inputArray, function (currentValue, breakout, index) {
546
- var res = ctx$1.run({ value: currentValue, set: true, meta: { index: index } }, function () { return runLazyRule(currentRule, currentValue); });
547
- if (!res.pass) {
548
- breakout(res);
549
- }
550
- }));
551
- }
552
-
553
- function loose(inputObject, shapeObject) {
554
- var _loop_1 = function (key) {
555
- var currentValue = inputObject[key];
556
- var currentRule = shapeObject[key];
557
- var res = ctx$1.run({ value: currentValue, set: true, meta: { key: key } }, function () {
558
- return runLazyRule(currentRule, currentValue);
559
- });
560
- if (!res.pass) {
561
- return { value: res };
562
- }
563
- };
564
- for (var key in shapeObject) {
565
- var state_1 = _loop_1(key);
566
- if (typeof state_1 === "object")
567
- return state_1.value;
568
- }
569
- return passing();
570
- }
571
-
572
- function shape(inputObject, shapeObject) {
573
- var baseRes = loose(inputObject, shapeObject);
574
- if (!baseRes.pass) {
575
- return baseRes;
576
- }
577
- for (var key in inputObject) {
578
- if (!hasOwnProperty(shapeObject, key)) {
579
- return failing();
580
- }
581
- }
582
- return passing();
583
- }
584
-
585
- function schema() {
586
- return { shape: shape, loose: loose, isArrayOf: isArrayOf };
587
- }
588
-
589
- var baseRules = assign(rules(), compounds(), schema());
590
- function getRule(ruleName) {
591
- return baseRules[ruleName];
592
- }
593
-
594
- function eachEnforceRule(action) {
595
- for (var ruleName in baseRules) {
596
- var ruleFn = getRule(ruleName);
597
- if (isFunction(ruleFn)) {
598
- action(ruleName, ruleFn);
599
- }
600
- }
601
- }
602
-
603
- function isProxySupported() {
604
- try {
605
- return typeof Proxy === 'function';
606
- }
607
- catch (_a) {
608
- return false;
609
- }
610
- }
611
-
612
- /**
613
- * Transform the result of a rule into a standard format
614
- */
615
- function transformResult(result, ruleName, value) {
616
- var args = [];
617
- for (var _i = 3; _i < arguments.length; _i++) {
618
- args[_i - 3] = arguments[_i];
619
- }
620
- validateResult(result);
621
- // if result is boolean
622
- if (isBoolean(result)) {
623
- return ruleReturn(result);
624
- }
625
- else {
626
- return ruleReturn(result.pass, optionalFunctionValue.apply(void 0, __spreadArray([result.message, ruleName, value], args)));
627
- }
628
- }
629
- function validateResult(result) {
630
- // if result is boolean, or if result.pass is boolean
631
- if (isBoolean(result) || (result && isBoolean(result.pass))) {
632
- return;
633
- }
634
- throwError('Incorrect return value for rule: ' + JSON.stringify(result));
635
- }
636
-
637
- function enforceEager(value) {
638
- var target = {};
639
- if (!isProxySupported()) {
640
- eachEnforceRule(function (ruleName, ruleFn) {
641
- target[ruleName] = genRuleCall(target, ruleFn, ruleName);
642
- });
643
- return target;
644
- }
645
- var proxy = new Proxy(target, {
646
- get: function (_, ruleName) {
647
- var rule = getRule(ruleName);
648
- if (rule) {
649
- return genRuleCall(proxy, rule, ruleName);
650
- }
651
- }
652
- });
653
- return proxy;
654
- function genRuleCall(target, rule, ruleName) {
655
- return function ruleCall() {
656
- var args = [];
657
- for (var _i = 0; _i < arguments.length; _i++) {
658
- args[_i] = arguments[_i];
659
- }
660
- var transformedResult = transformResult.apply(void 0, __spreadArray([ctx$1.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args)); }),
661
- ruleName,
662
- value], args));
663
- if (!transformedResult.pass) {
664
- if (isEmpty(transformedResult.message)) {
665
- throwError("enforce/" + ruleName + " failed with " + JSON.stringify(value));
666
- }
667
- else {
668
- // Explicitly throw a string so that vest.test can pick it up as the validation error message
669
- throw transformedResult.message;
670
- }
671
- }
672
- return target;
673
- };
674
- }
675
- }
676
-
677
- // eslint-disable-next-line max-lines-per-function
678
- function genEnforceLazy(key) {
679
- var registeredRules = [];
680
- var lazyMessage;
681
- return addLazyRule(key);
682
- // eslint-disable-next-line max-lines-per-function
683
- function addLazyRule(ruleName) {
684
- // eslint-disable-next-line max-lines-per-function
685
- return function () {
686
- var args = [];
687
- for (var _i = 0; _i < arguments.length; _i++) {
688
- args[_i] = arguments[_i];
689
- }
690
- var rule = getRule(ruleName);
691
- registeredRules.push(function (value) {
692
- return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args)), ruleName, value], args));
693
- });
694
- var proxy = {
695
- run: function (value) {
696
- return defaultToPassing(mapFirst(registeredRules, function (rule, breakout) {
697
- var _a;
698
- var res = ctx$1.run({ value: value }, function () { return rule(value); });
699
- if (!res.pass) {
700
- breakout(ruleReturn(!!res.pass, (_a = optionalFunctionValue(lazyMessage, value, res.message)) !== null && _a !== void 0 ? _a : res.message));
701
- }
702
- }));
703
- },
704
- test: function (value) { return proxy.run(value).pass; },
705
- message: function (message) {
706
- if (message) {
707
- lazyMessage = message;
708
- }
709
- return proxy;
710
- }
711
- };
712
- if (!isProxySupported()) {
713
- eachEnforceRule(function (ruleName) {
714
- proxy[ruleName] = addLazyRule(ruleName);
715
- });
716
- return proxy;
717
- }
718
- // reassigning the proxy here is not pretty
719
- // but it's a cleaner way of getting `run` and `test` for free
720
- proxy = new Proxy(proxy, {
721
- get: function (target, key) {
722
- if (getRule(key)) {
723
- return addLazyRule(key);
724
- }
725
- return target[key]; // already has `run` and `test` on it
726
- }
727
- });
728
- return proxy;
729
- };
730
- }
731
- }
732
-
733
- // Help needed improving the typings of this file.
734
- // Ideally, we'd be able to extend TShapeObject, but that's not possible.
735
- function partial(shapeObject) {
736
- var output = {};
737
- for (var key in shapeObject) {
738
- output[key] = enforce.optional(shapeObject[key]);
739
- }
740
- return output;
741
- }
742
-
743
- function modifiers() {
744
- return { partial: partial };
745
- }
746
-
747
- /**
748
- * Enforce is quite complicated, I want to explain it in detail.
749
- * It is dynamic in nature, so a lot of proxy objects are involved.
750
- *
751
- * Enforce has two main interfaces
752
- * 1. eager
753
- * 2. lazy
754
- *
755
- * The eager interface is the most commonly used, and the easier to understand.
756
- * It throws an error when a rule is not satisfied.
757
- * The eager interface is declared in enforceEager.ts and it is quite simple to understand.
758
- * enforce is called with a value, and the return value is a proxy object that points back to all the rules.
759
- * When a rule is called, the value is mapped as its first argument, and if the rule passes, the same
760
- * proxy object is returned. Otherwise, an error is thrown.
761
- *
762
- * The lazy interface works quite differently. It is declared in genEnforceLazy.ts.
763
- * Rather than calling enforce directly, the lazy interface has all the rules as "methods" (only by proxy).
764
- * Calling the first function in the chain will initialize an array of calls. It stores the different rule calls
765
- * and the parameters passed to them. None of the rules are called yet.
766
- * The rules are only invoked in sequence once either of these chained functions are called:
767
- * 1. test(value)
768
- * 2. run(value)
769
- *
770
- * Calling run or test will call all the rules in sequence, with the difference that test will only return a boolean value,
771
- * while run will return an object with the validation result and an optional message created by the rule.
772
- */
773
- function genEnforce() {
774
- var target = __assign({ context: function () { return ctx$1.useX(); }, extend: function (customRules) {
775
- assign(baseRules, customRules);
776
- } }, modifiers());
777
- if (!isProxySupported()) {
778
- eachEnforceRule(function (ruleName) {
779
- // Only on the first rule access - start the chain of calls
780
- target[ruleName] = genEnforceLazy(ruleName);
781
- });
782
- return target;
783
- }
784
- return new Proxy(assign(enforceEager, target), {
785
- get: function (target, key) {
786
- if (key in target) {
787
- return target[key];
788
- }
789
- if (!getRule(key)) {
790
- return;
791
- }
792
- // Only on the first rule access - start the chain of calls
793
- return genEnforceLazy(key);
794
- }
795
- });
796
- }
797
- var enforce = genEnforce();
798
-
799
- /**
800
- * @returns a unique numeric id.
801
- */
802
- var genId = (function (n) { return function () {
803
- return "" + n++;
804
- }; })(0);
805
-
806
- // eslint-disable-next-line max-lines-per-function
807
- function createState(onStateChange) {
808
- var state = {
809
- references: []
810
- };
811
- var registrations = [];
812
- return {
813
- registerStateKey: registerStateKey,
814
- reset: reset
815
- };
816
- /**
817
- * Registers a new key in the state, takes the initial value (may be a function that returns the initial value), returns a function.
818
- *
819
- * @example
820
- *
821
- * const useColor = state.registerStateKey("blue");
822
- *
823
- * let [color, setColor] = useColor(); // -> ["blue", Function]
824
- *
825
- * setColor("green");
826
- *
827
- * useColor()[0]; -> "green"
828
- */
829
- function registerStateKey(initialState, onUpdate) {
830
- var key = registrations.length;
831
- registrations.push([initialState, onUpdate]);
832
- return initKey(key, initialState);
833
- }
834
- function reset() {
835
- var prev = current();
836
- state.references = [];
837
- registrations.forEach(function (_a, index) {
838
- var initialValue = _a[0];
839
- return initKey(index, initialValue, prev[index]);
840
- });
841
- }
842
- function initKey(key, initialState, prevState) {
843
- current().push();
844
- set(key, optionalFunctionValue(initialState, prevState));
845
- return function useStateKey() {
846
- return [
847
- current()[key],
848
- function (nextState) {
849
- return set(key, optionalFunctionValue(nextState, current()[key]));
850
- },
851
- ];
852
- };
853
- }
854
- function current() {
855
- return state.references;
856
- }
857
- function set(index, value) {
858
- var prevValue = state.references[index];
859
- state.references[index] = value;
860
- var _a = registrations[index], onUpdate = _a[1];
861
- if (isFunction(onUpdate)) {
862
- onUpdate(value, prevValue);
863
- }
864
- if (isFunction(onStateChange)) {
865
- onStateChange();
866
- }
867
- }
868
- }
869
-
870
- var IsolateTypes;
871
- (function (IsolateTypes) {
872
- IsolateTypes[IsolateTypes["DEFAULT"] = 0] = "DEFAULT";
873
- IsolateTypes[IsolateTypes["SUITE"] = 1] = "SUITE";
874
- IsolateTypes[IsolateTypes["EACH"] = 2] = "EACH";
875
- IsolateTypes[IsolateTypes["SKIP_WHEN"] = 3] = "SKIP_WHEN";
876
- IsolateTypes[IsolateTypes["GROUP"] = 4] = "GROUP";
877
- })(IsolateTypes || (IsolateTypes = {}));
878
-
879
- function createStateRef(state, _a) {
880
- var suiteId = _a.suiteId;
881
- return {
882
- optionalFields: state.registerStateKey(function () { return ({}); }),
883
- suiteId: state.registerStateKey(suiteId),
884
- testCallbacks: state.registerStateKey(function () { return ({
885
- fieldCallbacks: {},
886
- doneCallbacks: []
887
- }); }),
888
- testObjects: state.registerStateKey(function (prev) {
889
- return {
890
- prev: (prev ? prev.current : []),
891
- current: []
892
- };
893
- })
894
- };
895
- }
896
-
897
- function asArray(possibleArg) {
898
- return [].concat(possibleArg);
899
- }
900
-
901
- function last(values) {
902
- var valuesArray = asArray(values);
903
- var _a = valuesArray, l = _a.length, _b = l - 1, lastValue = _a[_b];
904
- return lastValue;
905
- }
906
-
907
- function createCursor() {
908
- var storage = {
909
- cursor: []
910
- };
911
- function addLevel() {
912
- storage.cursor.push(0);
913
- }
914
- function removeLevel() {
915
- storage.cursor.pop();
916
- }
917
- function cursorAt() {
918
- return last(storage.cursor);
919
- }
920
- function getCursor() {
921
- return asArray(storage.cursor);
922
- }
923
- function next() {
924
- storage.cursor[storage.cursor.length - 1]++;
925
- return last(storage.cursor);
926
- }
927
- function reset() {
928
- storage.cursor = [0];
929
- }
930
- reset();
931
- return {
932
- addLevel: addLevel,
933
- cursorAt: cursorAt,
934
- getCursor: getCursor,
935
- next: next,
936
- removeLevel: removeLevel,
937
- reset: reset
938
- };
939
- }
940
-
941
- var ctx = createContext(function (ctxRef, parentContext) {
942
- return parentContext
943
- ? null
944
- : assign({}, {
945
- isolate: { type: IsolateTypes.DEFAULT },
946
- testCursor: createCursor(),
947
- exclusion: {
948
- tests: {},
949
- groups: {}
950
- }
951
- }, ctxRef);
952
- });
953
-
954
- // This is sort of a map/filter in one function.
955
- // Normally, behaves like a nested-array map
956
- // Returning `null` will drop the element from the array
957
- function transform(array, cb) {
958
- var res = [];
959
- for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
960
- var v = array_1[_i];
961
- if (isArray(v)) {
962
- res.push(transform(v, cb));
963
- }
964
- else {
965
- var output = cb(v);
966
- if (isNotNull(output)) {
967
- res.push(output);
968
- }
969
- }
970
- }
971
- return res;
972
- }
973
- function valueAtPath(array, path) {
974
- return getCurrent(array, path)[last(path)];
975
- }
976
- function setValueAtPath(array, path, value) {
977
- var current = getCurrent(array, path);
978
- current[last(path)] = value;
979
- return array;
980
- }
981
- function flatten(values) {
982
- return asArray(values).reduce(function (acc, value) {
983
- if (isArray(value)) {
984
- return acc.concat(flatten(value));
985
- }
986
- return asArray(acc).concat(value);
987
- }, []);
988
- }
989
- function getCurrent(array, path) {
990
- var current = array;
991
- for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
992
- var p = _a[_i];
993
- current[p] = defaultTo(current[p], []);
994
- current = current[p];
995
- }
996
- return current;
997
- }
998
-
999
- /**
1000
- * Creates a cache function
1001
- */
1002
- function createCache(maxSize) {
1003
- if (maxSize === void 0) { maxSize = 1; }
1004
- var cacheStorage = [];
1005
- var cache = function (deps, cacheAction) {
1006
- var cacheHit = cache.get(deps);
1007
- // cache hit is not null
1008
- if (cacheHit)
1009
- return cacheHit[1];
1010
- var result = cacheAction();
1011
- cacheStorage.unshift([deps.concat(), result]);
1012
- if (longerThan(cacheStorage, maxSize))
1013
- cacheStorage.length = maxSize;
1014
- return result;
1015
- };
1016
- // invalidate an item in the cache by its dependencies
1017
- cache.invalidate = function (deps) {
1018
- var index = cacheStorage.findIndex(function (_a) {
1019
- var cachedDeps = _a[0];
1020
- return lengthEquals(deps, cachedDeps.length) &&
1021
- deps.every(function (dep, i) { return dep === cachedDeps[i]; });
1022
- });
1023
- if (index > -1)
1024
- cacheStorage.splice(index, 1);
1025
- };
1026
- // Retrieves an item from the cache.
1027
- cache.get = function (deps) {
1028
- return cacheStorage[cacheStorage.findIndex(function (_a) {
1029
- var cachedDeps = _a[0];
1030
- return lengthEquals(deps, cachedDeps.length) &&
1031
- deps.every(function (dep, i) { return dep === cachedDeps[i]; });
1032
- })] || null;
1033
- };
1034
- return cache;
1035
- }
1036
-
1037
- // STATE REF
1038
- function useStateRef() {
1039
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1040
- return ctx.useX().stateRef; // I should revisit this
1041
- }
1042
- // STATE KEYS
1043
- function useSuiteId() {
1044
- return useStateRef().suiteId();
1045
- }
1046
- function useTestCallbacks() {
1047
- return useStateRef().testCallbacks();
1048
- }
1049
- function useOptionalFields() {
1050
- return useStateRef().optionalFields();
1051
- }
1052
- function useTestObjects() {
1053
- return useStateRef().testObjects();
1054
- }
1055
- // STATE ACTIONS
1056
- function useRefreshTestObjects() {
1057
- var _a = useTestObjects(), setTestObjects = _a[1];
1058
- setTestObjects(function (_a) {
1059
- var current = _a.current, prev = _a.prev;
1060
- return ({
1061
- prev: prev,
1062
- current: asArray(current)
1063
- });
1064
- });
1065
- }
1066
- function useSetTests(handler) {
1067
- var _a = useTestObjects(), testObjects = _a[1];
1068
- testObjects(function (_a) {
1069
- var current = _a.current, prev = _a.prev;
1070
- return ({
1071
- prev: prev,
1072
- current: asArray(handler(current))
1073
- });
1074
- });
1075
- }
1076
- // Derived state
1077
- function useAllIncomplete() {
1078
- var current = useTestObjects()[0].current;
1079
- return flatten(transform(current, function (testObject) {
1080
- return testObject.isPending() ? testObject : null;
1081
- }));
1082
- }
1083
- function useOmittedFields() {
1084
- var testObjects = useTestsFlat();
1085
- return testObjects.reduce(function (omittedFields, testObject) {
1086
- if (omittedFields[testObject.fieldName]) {
1087
- return omittedFields;
1088
- }
1089
- if (testObject.isOmitted()) {
1090
- omittedFields[testObject.fieldName] = true;
1091
- }
1092
- return omittedFields;
1093
- }, {});
1094
- }
1095
- var flatCache = createCache();
1096
- function useTestsFlat() {
1097
- var current = useTestObjects()[0].current;
1098
- return flatCache([current], function () { return flatten(current); });
1099
- }
1100
-
1101
- function usePath() {
1102
- var context = ctx.useX();
1103
- return context.testCursor.getCursor();
1104
- }
1105
- function useCursorAt() {
1106
- var context = ctx.useX();
1107
- return context.testCursor.cursorAt();
1108
- }
1109
- function moveForward() {
1110
- var context = ctx.useX();
1111
- return context.testCursor.next();
1112
- }
1113
- function addLevel() {
1114
- var context = ctx.useX();
1115
- context.testCursor.addLevel();
1116
- }
1117
- function removeLevel() {
1118
- var context = ctx.useX();
1119
- context.testCursor.removeLevel();
1120
- }
1121
-
1122
- function isolate(_a, callback) {
1123
- var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
1124
- if (!isFunction(callback)) {
1125
- return;
1126
- }
1127
- var path = usePath();
1128
- return ctx.run({ isolate: { type: type } }, function () {
1129
- addLevel();
1130
- useSetTests(function (tests) { return setValueAtPath(tests, path, []); });
1131
- var res = callback();
1132
- removeLevel();
1133
- moveForward();
1134
- return res;
1135
- });
1136
- }
1137
- function shouldAllowReorder() {
1138
- return ctx.useX().isolate.type === IsolateTypes.EACH;
1139
- }
1140
-
1141
- function nonMatchingFieldName(testObject, fieldName) {
1142
- return !!fieldName && !matchingFieldName(testObject, fieldName);
1143
- }
1144
- function matchingFieldName(testObject, fieldName) {
1145
- return !!(fieldName && testObject.fieldName === fieldName);
1146
- }
1147
-
1148
- function omitOptionalTests() {
1149
- var optionalFields = useOptionalFields()[0];
1150
- if (isEmpty(optionalFields)) {
1151
- return;
1152
- }
1153
- var shouldOmit = {};
1154
- useSetTests(function (tests) {
1155
- return transform(tests, function (testObject) {
1156
- var fieldName = testObject.fieldName;
1157
- if (shouldOmit.hasOwnProperty(fieldName)) {
1158
- omit(testObject);
1159
- }
1160
- else {
1161
- var optionalConfig = optionalFields[fieldName];
1162
- if (isFunction(optionalConfig)) {
1163
- shouldOmit[fieldName] = optionalConfig();
1164
- omit(testObject);
1165
- }
1166
- }
1167
- return testObject;
1168
- });
1169
- });
1170
- function omit(testObject) {
1171
- if (shouldOmit[testObject.fieldName]) {
1172
- testObject.omit();
1173
- }
1174
- }
1175
- }
1176
-
1177
- /**
1178
- * Checks if a given field, or the suite as a whole still have remaining tests.
1179
- */
1180
- function hasRemainingTests(fieldName) {
1181
- var allIncomplete = useAllIncomplete();
1182
- if (isEmpty(allIncomplete)) {
1183
- return false;
1184
- }
1185
- if (fieldName) {
1186
- return allIncomplete.some(function (testObject) {
1187
- return matchingFieldName(testObject, fieldName);
1188
- });
1189
- }
1190
- return isNotEmpty(allIncomplete);
1191
- }
1192
-
1193
- /**
1194
- * Reads the testObjects list and gets full validation result from it.
1195
- */
1196
- function genTestsSummary() {
1197
- var testObjects = useTestsFlat();
1198
- var summary = {
1199
- errorCount: 0,
1200
- groups: {},
1201
- testCount: 0,
1202
- tests: {},
1203
- warnCount: 0
1204
- };
1205
- appendSummary(testObjects);
1206
- return countFailures(summary);
1207
- function appendSummary(testObjects) {
1208
- testObjects.forEach(function (testObject) {
1209
- var fieldName = testObject.fieldName, groupName = testObject.groupName;
1210
- summary.tests[fieldName] = genTestObject(summary.tests, testObject);
1211
- if (groupName) {
1212
- summary.groups[groupName] = summary.groups[groupName] || {};
1213
- summary.groups[groupName][fieldName] = genTestObject(summary.groups[groupName], testObject);
1214
- }
1215
- });
1216
- }
1217
- }
1218
- /**
1219
- * Counts the failed tests and adds global counters
1220
- */
1221
- function countFailures(summary) {
1222
- for (var test in summary.tests) {
1223
- summary.errorCount += summary.tests[test].errorCount;
1224
- summary.warnCount += summary.tests[test].warnCount;
1225
- summary.testCount += summary.tests[test].testCount;
1226
- }
1227
- return summary;
1228
- }
1229
- // eslint-disable-next-line max-statements
1230
- function genTestObject(summaryKey, testObject) {
1231
- var fieldName = testObject.fieldName, message = testObject.message;
1232
- summaryKey[fieldName] = summaryKey[fieldName] || {
1233
- errorCount: 0,
1234
- warnCount: 0,
1235
- testCount: 0
1236
- };
1237
- var testKey = summaryKey[fieldName];
1238
- if (testObject.isSkipped())
1239
- return testKey;
1240
- summaryKey[fieldName].testCount++;
1241
- // Adds to severity group
1242
- function addTo(countKey, group) {
1243
- testKey[countKey]++;
1244
- if (message) {
1245
- testKey[group] = (testKey[group] || []).concat(message);
1246
- }
1247
- }
1248
- if (testObject.isFailing()) {
1249
- addTo('errorCount', 'errors');
1250
- }
1251
- else if (testObject.isWarning()) {
1252
- addTo('warnCount', 'warnings');
1253
- }
1254
- return testKey;
1255
- }
1256
-
1257
- function either(a, b) {
1258
- return !!a !== !!b;
1259
- }
1260
-
1261
- /**
1262
- * Checks that a given test object matches the currently specified severity level
1263
- */
1264
- function nonMatchingSeverityProfile(severity, testObject) {
1265
- return either(severity === 'warnings', testObject.warns);
1266
- }
1267
-
1268
- function collectFailureMessages(severity, testObjects, options) {
1269
- var _a;
1270
- if (options === void 0) { options = {}; }
1271
- var _b = options || {}, group = _b.group, fieldName = _b.fieldName;
1272
- var res = testObjects.reduce(function (collector, testObject) {
1273
- if (noMatch(testObject, severity, group, fieldName)) {
1274
- return collector;
1275
- }
1276
- if (!testObject.hasFailures()) {
1277
- return collector;
1278
- }
1279
- collector[testObject.fieldName] = (collector[testObject.fieldName] || []).concat(testObject.message || []);
1280
- return collector;
1281
- }, __assign({}, (fieldName && (_a = {}, _a[fieldName] = [], _a))));
1282
- return res;
1283
- }
1284
- function noGroupMatch(testObject, groupName) {
1285
- return !!(groupName && testObject.groupName !== groupName);
1286
- }
1287
- function noMatch(testObject, severity, group, fieldName) {
1288
- if (noGroupMatch(testObject, group)) {
1289
- return true;
1290
- }
1291
- if (nonMatchingFieldName(testObject, fieldName)) {
1292
- return true;
1293
- }
1294
- if (nonMatchingSeverityProfile(severity, testObject)) {
1295
- return true;
1296
- }
1297
- return false;
1298
- }
1299
-
1300
- function getFailuresArrayOrObject(group, fieldName) {
1301
- if (fieldName) {
1302
- return group[fieldName];
1303
- }
1304
- return group;
1305
- }
1306
-
1307
- function getErrors(fieldName) {
1308
- return getFailures('errors', fieldName);
1309
- }
1310
- function getWarnings(fieldName) {
1311
- return getFailures('warnings', fieldName);
1312
- }
1313
- /**
1314
- * @returns suite or field's errors or warnings.
1315
- */
1316
- function getFailures(severityKey, fieldName) {
1317
- var testObjects = useTestsFlat();
1318
- var failureMessages = collectFailureMessages(severityKey, testObjects, {
1319
- fieldName: fieldName
1320
- });
1321
- return getFailuresArrayOrObject(failureMessages, fieldName);
1322
- }
1323
-
1324
- function getErrorsByGroup(groupName, fieldName) {
1325
- var errors = getByGroup('errors', groupName, fieldName);
1326
- return getFailuresArrayOrObject(errors, fieldName);
1327
- }
1328
- function getWarningsByGroup(groupName, fieldName) {
1329
- var warnings = getByGroup('warnings', groupName, fieldName);
1330
- return getFailuresArrayOrObject(warnings, fieldName);
1331
- }
1332
- /**
1333
- * Gets failure messages by group.
1334
- */
1335
- function getByGroup(severityKey, group, fieldName) {
1336
- if (!group) {
1337
- throwError("get" + severityKey[0].toUpperCase() + severityKey.slice(1) + "ByGroup requires a group name. Received `" + group + "` instead.");
1338
- }
1339
- var testObjects = useTestsFlat();
1340
- var failureMessages = collectFailureMessages(severityKey, testObjects, {
1341
- group: group,
1342
- fieldName: fieldName
1343
- });
1344
- return failureMessages;
1345
- }
1346
-
1347
- /**
1348
- * Determines whether a certain test profile has failures.
1349
- */
1350
- function hasFailuresLogic(testObject, severityKey, fieldName) {
1351
- if (!testObject.hasFailures()) {
1352
- return false;
1353
- }
1354
- if (nonMatchingFieldName(testObject, fieldName)) {
1355
- return false;
1356
- }
1357
- if (nonMatchingSeverityProfile(severityKey, testObject)) {
1358
- return false;
1359
- }
1360
- return true;
1361
- }
1362
-
1363
- function hasErrors(fieldName) {
1364
- return has('errors', fieldName);
1365
- }
1366
- function hasWarnings(fieldName) {
1367
- return has('warnings', fieldName);
1368
- }
1369
- function has(severityKey, fieldName) {
1370
- var testObjects = useTestsFlat();
1371
- return testObjects.some(function (testObject) {
1372
- return hasFailuresLogic(testObject, severityKey, fieldName);
1373
- });
1374
- }
1375
-
1376
- function hasErrorsByGroup(groupName, fieldName) {
1377
- return hasByGroup('errors', groupName, fieldName);
1378
- }
1379
- function hasWarningsByGroup(groupName, fieldName) {
1380
- return hasByGroup('warnings', groupName, fieldName);
1381
- }
1382
- /**
1383
- * Checks whether there are failures in a given group.
1384
- */
1385
- function hasByGroup(severityKey, group, fieldName) {
1386
- var testObjects = useTestsFlat();
1387
- return testObjects.some(function (testObject) {
1388
- return group === testObject.groupName
1389
- ? hasFailuresLogic(testObject, severityKey, fieldName)
1390
- : false;
1391
- });
1392
- }
1393
-
1394
- // eslint-disable-next-line max-statements, complexity
1395
- function isValid(result, fieldName) {
1396
- if (fieldIsOmitted(fieldName)) {
1397
- return true;
1398
- }
1399
- if (result.hasErrors(fieldName)) {
1400
- return false;
1401
- }
1402
- var testObjects = useTestsFlat();
1403
- if (isEmpty(testObjects)) {
1404
- return false;
1405
- }
1406
- if (fieldDoesNotExist(result, fieldName)) {
1407
- return false;
1408
- }
1409
- if (hasNonOptionalIncomplete(fieldName)) {
1410
- return false;
1411
- }
1412
- return noMissingTests(fieldName);
1413
- }
1414
- function fieldIsOmitted(fieldName) {
1415
- var omittedFields = useOmittedFields();
1416
- if (!fieldName) {
1417
- return false;
1418
- }
1419
- return !!omittedFields[fieldName];
1420
- }
1421
- function hasNonOptionalIncomplete(fieldName) {
1422
- var optionalFields = useOptionalFields()[0];
1423
- return isNotEmpty(useAllIncomplete().filter(function (testObject) {
1424
- if (nonMatchingFieldName(testObject, fieldName)) {
1425
- return false;
1426
- }
1427
- return optionalFields[testObject.fieldName] !== true;
1428
- }));
1429
- }
1430
- function fieldDoesNotExist(result, fieldName) {
1431
- return !!fieldName && isEmpty(result.tests[fieldName]);
1432
- }
1433
- function noMissingTests(fieldName) {
1434
- var testObjects = useTestsFlat();
1435
- var optionalFields = useOptionalFields()[0];
1436
- return testObjects.every(function (testObject) {
1437
- if (nonMatchingFieldName(testObject, fieldName)) {
1438
- return true;
1439
- }
1440
- return (optionalFields[testObject.fieldName] === true ||
1441
- testObject.isTested() ||
1442
- testObject.isOmitted());
1443
- });
1444
- }
1445
-
1446
- var cache$1 = createCache(20);
1447
- function produceDraft() {
1448
- var testObjects = useTestsFlat();
1449
- var ctxRef = { stateRef: useStateRef() };
1450
- return cache$1([testObjects], ctx.bind(ctxRef, function () {
1451
- return assign(genTestsSummary(), {
1452
- getErrors: ctx.bind(ctxRef, getErrors),
1453
- getErrorsByGroup: ctx.bind(ctxRef, getErrorsByGroup),
1454
- getWarnings: ctx.bind(ctxRef, getWarnings),
1455
- getWarningsByGroup: ctx.bind(ctxRef, getWarningsByGroup),
1456
- hasErrors: ctx.bind(ctxRef, hasErrors),
1457
- hasErrorsByGroup: ctx.bind(ctxRef, hasErrorsByGroup),
1458
- hasWarnings: ctx.bind(ctxRef, hasWarnings),
1459
- hasWarningsByGroup: ctx.bind(ctxRef, hasWarningsByGroup),
1460
- isValid: ctx.bind(ctxRef, function (fieldName) {
1461
- return isValid(produceDraft(), fieldName);
1462
- })
1463
- });
1464
- }));
1465
- }
1466
-
1467
- var cache = createCache(20);
1468
- function produceFullResult() {
1469
- var testObjects = useTestsFlat();
1470
- var ctxRef = { stateRef: useStateRef() };
1471
- return cache([testObjects], ctx.bind(ctxRef, function () {
1472
- return assign({}, produceDraft(), {
1473
- done: ctx.bind(ctxRef, done)
1474
- });
1475
- }));
1476
- }
1477
- /**
1478
- * DONE is here and not in its own module to prevent circular dependency issues.
1479
- */
1480
- function shouldSkipDoneRegistration(callback, fieldName, output) {
1481
- // If we do not have any test runs for the current field
1482
- return !!(!isFunction(callback) ||
1483
- (fieldName &&
1484
- (!output.tests[fieldName] || output.tests[fieldName].testCount === 0)));
1485
- }
1486
- function shouldRunDoneCallback(fieldName) {
1487
- // is suite finished || field name exists, and test is finished;
1488
- return !!(!hasRemainingTests() ||
1489
- (fieldName && !hasRemainingTests(fieldName)));
1490
- }
1491
- /**
1492
- * Registers done callbacks.
1493
- * @register {Object} Vest output object.
1494
- */
1495
- var done = function done() {
1496
- var args = [];
1497
- for (var _i = 0; _i < arguments.length; _i++) {
1498
- args[_i] = arguments[_i];
1499
- }
1500
- var _a = args.reverse(), callback = _a[0], fieldName = _a[1];
1501
- var output = produceFullResult();
1502
- if (shouldSkipDoneRegistration(callback, fieldName, output)) {
1503
- return output;
1504
- }
1505
- var doneCallback = function () { return callback(produceDraft()); };
1506
- if (shouldRunDoneCallback(fieldName)) {
1507
- doneCallback();
1508
- return output;
1509
- }
1510
- deferDoneCallback(doneCallback, fieldName);
1511
- return output;
1512
- };
1513
- function deferDoneCallback(doneCallback, fieldName) {
1514
- var deferredCallback = ctx.bind({}, doneCallback);
1515
- var _a = useTestCallbacks(), setTestCallbacks = _a[1];
1516
- setTestCallbacks(function (current) {
1517
- if (fieldName) {
1518
- current.fieldCallbacks[fieldName] = (current.fieldCallbacks[fieldName] || []).concat(deferredCallback);
1519
- }
1520
- else {
1521
- current.doneCallbacks.push(deferredCallback);
1522
- }
1523
- return current;
1524
- });
1525
- }
1526
-
1527
- /**
1528
- * Removes test object from suite state
1529
- */
1530
- function removeTestFromState (testObject) {
1531
- useSetTests(function (tests) {
1532
- return transform(tests, function (test) { return (testObject !== test ? test : null); });
1533
- });
1534
- }
1535
-
1536
- function createBus() {
1537
- var listeners = {};
1538
- return {
1539
- emit: function (event, data) {
1540
- if (!listeners[event]) {
1541
- return;
1542
- }
1543
- listeners[event].forEach(function (listener) {
1544
- listener(data);
1545
- });
1546
- },
1547
- on: function (event, handler) {
1548
- if (!listeners[event]) {
1549
- listeners[event] = [];
1550
- }
1551
- listeners[event].push(handler);
1552
- return {
1553
- off: function () {
1554
- listeners[event] = listeners[event].filter(function (h) { return h !== handler; });
1555
- }
1556
- };
1557
- }
1558
- };
1559
- }
1560
-
1561
- function callEach(arr) {
1562
- return arr.forEach(function (fn) { return fn(); });
1563
- }
1564
-
1565
- /**
1566
- * Runs done callback per field when async tests are finished running.
1567
- */
1568
- function runFieldCallbacks(fieldName) {
1569
- var fieldCallbacks = useTestCallbacks()[0].fieldCallbacks;
1570
- if (fieldName) {
1571
- if (!hasRemainingTests(fieldName) && isArray(fieldCallbacks[fieldName])) {
1572
- callEach(fieldCallbacks[fieldName]);
1573
- }
1574
- }
1575
- }
1576
- /**
1577
- * Runs unlabelled done callback when async tests are finished running.
1578
- */
1579
- function runDoneCallbacks() {
1580
- var doneCallbacks = useTestCallbacks()[0].doneCallbacks;
1581
- if (!hasRemainingTests()) {
1582
- callEach(doneCallbacks);
1583
- }
1584
- }
1585
-
1586
- function initBus() {
1587
- var bus = createBus();
1588
- bus.on(Events.TEST_COMPLETED, function (testObject) {
1589
- if (testObject.isCanceled()) {
1590
- return;
1591
- }
1592
- testObject.done();
1593
- runFieldCallbacks(testObject.fieldName);
1594
- runDoneCallbacks();
1595
- });
1596
- return bus;
1597
- }
1598
- function useBus() {
1599
- var context = ctx.useX();
1600
- if (!context.bus) {
1601
- throwError();
1602
- }
1603
- return context.bus;
1604
- }
1605
- var Events;
1606
- (function (Events) {
1607
- Events["TEST_COMPLETED"] = "test_completed";
1608
- })(Events || (Events = {}));
1609
-
1610
- // eslint-disable-next-line max-lines-per-function
1611
- function create(suiteCallback) {
1612
- if (!isFunction(suiteCallback)) {
1613
- throwError('Suite initialization error. Expected `tests` to be a function.');
1614
- }
1615
- var bus = initBus();
1616
- var state = createState();
1617
- var stateRef = createStateRef(state, { suiteId: genId() });
1618
- var suite = assign(ctx.bind({ stateRef: stateRef, bus: bus }, function () {
1619
- var args = [];
1620
- for (var _i = 0; _i < arguments.length; _i++) {
1621
- args[_i] = arguments[_i];
1622
- }
1623
- state.reset();
1624
- // Run the consumer's callback
1625
- isolate({ type: IsolateTypes.SUITE }, function () {
1626
- suiteCallback.apply(void 0, args);
1627
- });
1628
- omitOptionalTests();
1629
- var res = produceFullResult();
1630
- return res;
1631
- }), {
1632
- get: ctx.bind({ stateRef: stateRef }, produceDraft),
1633
- remove: ctx.bind({ stateRef: stateRef }, function (name) {
1634
- var testObjects = useTestsFlat();
1635
- // We're mutating the array in `cancel`, so we have to first copy it.
1636
- testObjects.forEach(function (testObject) {
1637
- if (matchingFieldName(testObject, name)) {
1638
- testObject.cancel();
1639
- removeTestFromState(testObject);
1640
- }
1641
- });
1642
- }),
1643
- reset: state.reset
1644
- });
1645
- return suite;
1646
- }
1647
-
1648
- /**
1649
- * Error message to display when a hook was called outside of context.
1650
- */
1651
- var ERROR_HOOK_CALLED_OUTSIDE = 'hook called outside of a running suite.';
1652
-
1653
- /**
1654
- * Adds a field or multiple fields to inclusion group.
1655
- */
1656
- function only(item) {
1657
- return addTo('only', 'tests', item);
1658
- }
1659
- only.group = function (item) { return addTo('only', 'groups', item); };
1660
- /**
1661
- * Adds a field or multiple fields to exclusion group.
1662
- */
1663
- function skip(item) {
1664
- return addTo('skip', 'tests', item);
1665
- }
1666
- skip.group = function (item) { return addTo('skip', 'groups', item); };
1667
- //Checks whether a certain test profile excluded by any of the exclusion groups.
1668
- // eslint-disable-next-line complexity, max-statements
1669
- function isExcluded(testObject) {
1670
- var fieldName = testObject.fieldName, groupName = testObject.groupName;
1671
- var context = ctx.useX();
1672
- if (context.skipped)
1673
- return true;
1674
- var exclusion = context.exclusion;
1675
- var keyTests = exclusion.tests;
1676
- var testValue = keyTests[fieldName];
1677
- // if test is skipped
1678
- // no need to proceed
1679
- if (testValue === false)
1680
- return true;
1681
- var isTestIncluded = testValue === true;
1682
- // If inside a group
1683
- if (groupName) {
1684
- if (isGroupExcluded(groupName)) {
1685
- return true; // field excluded by group
1686
- // if group is `only`ed
1687
- }
1688
- else if (exclusion.groups[groupName] === true) {
1689
- if (isTestIncluded)
1690
- return false;
1691
- // If there is _ANY_ `only`ed test (and we already know this one isn't)
1692
- if (hasIncludedTests(keyTests))
1693
- return true; // Excluded implicitly
1694
- return keyTests[fieldName] === false;
1695
- }
1696
- }
1697
- // if field is only'ed
1698
- if (isTestIncluded)
1699
- return false;
1700
- // If there is _ANY_ `only`ed test (and we already know this one isn't) return true
1701
- // Otherwise return false
1702
- return hasIncludedTests(keyTests);
1703
- }
1704
- /**
1705
- * Checks whether a given group is excluded from running.
1706
- */
1707
- function isGroupExcluded(groupName) {
1708
- var context = ctx.useX();
1709
- var exclusion = context.exclusion;
1710
- var keyGroups = exclusion.groups;
1711
- var groupPresent = hasOwnProperty(keyGroups, groupName);
1712
- // When group is either only'ed or skipped
1713
- if (groupPresent) {
1714
- // Return true if group is skipped and false if only'ed
1715
- return keyGroups[groupName] === false;
1716
- }
1717
- // Group is not present
1718
- for (var group in keyGroups) {
1719
- // If any other group is only'ed
1720
- if (keyGroups[group] === true) {
1721
- return true;
1722
- }
1723
- }
1724
- return false;
1725
- }
1726
- /**
1727
- * Adds fields to a specified exclusion group.
1728
- */
1729
- function addTo(exclusionGroup, itemType, item) {
1730
- var context = ctx.useX(ERROR_HOOK_CALLED_OUTSIDE);
1731
- if (!item) {
1732
- return;
1733
- }
1734
- asArray(item).forEach(function (itemName) {
1735
- if (!isStringValue(itemName)) {
1736
- return;
1737
- }
1738
- context.exclusion[itemType][itemName] = exclusionGroup === 'only';
1739
- });
1740
- }
1741
- /**
1742
- * Checks if context has included tests
1743
- */
1744
- function hasIncludedTests(keyTests) {
1745
- for (var test in keyTests) {
1746
- if (keyTests[test] === true) {
1747
- return true; // excluded implicitly
1748
- }
1749
- }
1750
- return false;
1751
- }
1752
-
1753
- function skipWhen(conditional, callback) {
1754
- isolate({ type: IsolateTypes.SKIP_WHEN }, function () {
1755
- ctx.run({ skipped: optionalFunctionValue(conditional) }, function () { return callback(); });
1756
- });
1757
- }
1758
-
1759
- var ERROR_OUTSIDE_OF_TEST = "warn hook called outside of a test callback. It won't have an effect."
1760
- ;
1761
- /**
1762
- * Sets a running test to warn only mode.
1763
- */
1764
- function warn() {
1765
- var ctx$1 = ctx.useX('warn ' + ERROR_HOOK_CALLED_OUTSIDE);
1766
- if (!ctx$1.currentTest) {
1767
- throwError(ERROR_OUTSIDE_OF_TEST);
1768
- }
1769
- ctx$1.currentTest.warn();
1770
- }
1771
-
1772
- /**
1773
- * Runs a group callback.
1774
- */
1775
- function group(groupName, tests) {
1776
- if (!isStringValue(groupName)) {
1777
- throwGroupError('name must be a string');
1778
- }
1779
- if (!isFunction(tests)) {
1780
- throwGroupError('callback must be a function');
1781
- }
1782
- // Running with the context applied
1783
- isolate({ type: IsolateTypes.GROUP }, function () {
1784
- ctx.run({ groupName: groupName }, tests);
1785
- });
1786
- }
1787
- function throwGroupError(error) {
1788
- throwError("Wrong arguments passed to group. Group " + error + ".");
1789
- }
1790
-
1791
- function optional(optionals) {
1792
- var _a = useOptionalFields(), setOptionalFields = _a[1];
1793
- setOptionalFields(function (state) {
1794
- if (!isArray(optionals) && !isStringValue(optionals)) {
1795
- var optionalFunctions = optionals;
1796
- for (var field in optionalFunctions) {
1797
- var predicate = optionalFunctions[field];
1798
- state[field] = predicate;
1799
- }
1800
- }
1801
- else {
1802
- asArray(optionals).forEach(function (optionalField) {
1803
- state[optionalField] = true;
1804
- });
1805
- }
1806
- return state;
1807
- });
1808
- }
1809
-
1810
- function shouldUseErrorAsMessage(message, error) {
1811
- // kind of cheating with this safe guard, but it does the job
1812
- return isUndefined(message) && isStringValue(error);
1813
- }
1814
-
1815
- var VestTest = /** @class */ (function () {
1816
- function VestTest(fieldName, testFn, _a) {
1817
- var _b = _a === void 0 ? {} : _a, message = _b.message, groupName = _b.groupName;
1818
- this.id = genId();
1819
- this.warns = false;
1820
- this.status = STATUS_UNTESTED;
1821
- this.fieldName = fieldName;
1822
- this.testFn = testFn;
1823
- if (groupName) {
1824
- this.groupName = groupName;
1825
- }
1826
- if (message) {
1827
- this.message = message;
1828
- }
1829
- }
1830
- VestTest.prototype.run = function () {
1831
- var result;
1832
- try {
1833
- result = this.testFn();
1834
- }
1835
- catch (error) {
1836
- if (shouldUseErrorAsMessage(this.message, error)) {
1837
- this.message = error;
1838
- }
1839
- result = false;
1840
- }
1841
- if (result === false) {
1842
- this.fail();
1843
- }
1844
- return result;
1845
- };
1846
- VestTest.prototype.setStatus = function (status) {
1847
- if (this.isFinalStatus() && status !== STATUS_OMITTED) {
1848
- return;
1849
- }
1850
- this.status = status;
1851
- };
1852
- VestTest.prototype.setPending = function () {
1853
- this.setStatus(STATUS_PENDING);
1854
- };
1855
- VestTest.prototype.fail = function () {
1856
- this.setStatus(this.warns ? STATUS_WARNING : STATUS_FAILED);
1857
- };
1858
- VestTest.prototype.done = function () {
1859
- if (this.isFinalStatus()) {
1860
- return;
1861
- }
1862
- this.setStatus(STATUS_PASSING);
1863
- };
1864
- VestTest.prototype.warn = function () {
1865
- this.warns = true;
1866
- };
1867
- VestTest.prototype.isFinalStatus = function () {
1868
- return this.hasFailures() || this.isCanceled() || this.isPassing();
1869
- };
1870
- VestTest.prototype.skip = function () {
1871
- if (this.isPending()) {
1872
- // Without this condition, the test will be marked as skipped even if it is pending.
1873
- // This means that it will not be counted in "allIncomplete" and its done callbacks
1874
- // will not be called, or will be called prematurely.
1875
- return;
1876
- }
1877
- this.setStatus(STATUS_SKIPPED);
1878
- };
1879
- VestTest.prototype.cancel = function () {
1880
- this.setStatus(STATUS_CANCELED);
1881
- useRefreshTestObjects();
1882
- };
1883
- VestTest.prototype.omit = function () {
1884
- this.setStatus(STATUS_OMITTED);
1885
- };
1886
- VestTest.prototype.valueOf = function () {
1887
- return !this.isFailing();
1888
- };
1889
- VestTest.prototype.hasFailures = function () {
1890
- return this.isFailing() || this.isWarning();
1891
- };
1892
- VestTest.prototype.isPending = function () {
1893
- return this.status === STATUS_PENDING;
1894
- };
1895
- VestTest.prototype.isTested = function () {
1896
- return this.hasFailures() || this.isPassing();
1897
- };
1898
- VestTest.prototype.isOmitted = function () {
1899
- return this.status === STATUS_OMITTED;
1900
- };
1901
- VestTest.prototype.isUntested = function () {
1902
- return this.status === STATUS_UNTESTED;
1903
- };
1904
- VestTest.prototype.isFailing = function () {
1905
- return this.status === STATUS_FAILED;
1906
- };
1907
- VestTest.prototype.isCanceled = function () {
1908
- return this.status === STATUS_CANCELED;
1909
- };
1910
- VestTest.prototype.isSkipped = function () {
1911
- return this.status === STATUS_SKIPPED;
1912
- };
1913
- VestTest.prototype.isPassing = function () {
1914
- return this.status === STATUS_PASSING;
1915
- };
1916
- VestTest.prototype.isWarning = function () {
1917
- return this.status === STATUS_WARNING;
1918
- };
1919
- return VestTest;
1920
- }());
1921
- var STATUS_UNTESTED = 'UNTESTED';
1922
- var STATUS_SKIPPED = 'SKIPPED';
1923
- var STATUS_FAILED = 'FAILED';
1924
- var STATUS_WARNING = 'WARNING';
1925
- var STATUS_PASSING = 'PASSING';
1926
- var STATUS_PENDING = 'PENDING';
1927
- var STATUS_CANCELED = 'CANCELED';
1928
- var STATUS_OMITTED = 'OMITTED';
1929
-
1930
- function isPromise(value) {
1931
- return value && isFunction(value.then);
1932
- }
1933
-
1934
- function isSameProfileTest(testObject1, testObject2) {
1935
- return (testObject1.fieldName === testObject2.fieldName &&
1936
- testObject1.groupName === testObject2.groupName);
1937
- }
1938
-
1939
- function cancelOverriddenPendingTest(prevRunTestObject, currentRunTestObject) {
1940
- if (currentRunTestObject !== prevRunTestObject &&
1941
- isSameProfileTest(prevRunTestObject, currentRunTestObject) &&
1942
- prevRunTestObject.isPending()) {
1943
- prevRunTestObject.cancel();
1944
- }
1945
- }
1946
-
1947
- /**
1948
- * Runs async test.
1949
- */
1950
- function runAsyncTest(testObject) {
1951
- var asyncTest = testObject.asyncTest, message = testObject.message;
1952
- if (!isPromise(asyncTest))
1953
- return;
1954
- var emit = useBus().emit;
1955
- var stateRef = useStateRef();
1956
- var done = ctx.bind({ stateRef: stateRef }, function () {
1957
- // invalidating the "produce" cache
1958
- useRefreshTestObjects();
1959
- emit(Events.TEST_COMPLETED, testObject);
1960
- });
1961
- var fail = ctx.bind({ stateRef: stateRef }, function (rejectionMessage) {
1962
- if (testObject.isCanceled()) {
1963
- return;
1964
- }
1965
- testObject.message = isStringValue(rejectionMessage)
1966
- ? rejectionMessage
1967
- : message;
1968
- testObject.fail();
1969
- done();
1970
- });
1971
- try {
1972
- asyncTest.then(done, fail);
1973
- }
1974
- catch (e) {
1975
- fail();
1976
- }
1977
- }
1978
-
1979
- /**
1980
- * Runs sync tests - or extracts promise.
1981
- */
1982
- function runSyncTest(testObject) {
1983
- return ctx.run({ currentTest: testObject }, function () {
1984
- var result;
1985
- try {
1986
- result = testObject.testFn();
1987
- }
1988
- catch (e) {
1989
- if (shouldUseErrorAsMessage(testObject.message, e)) {
1990
- testObject.message = e;
1991
- }
1992
- result = false;
1993
- }
1994
- if (result === false) {
1995
- testObject.fail();
1996
- }
1997
- return result;
1998
- });
1999
- }
2000
-
2001
- /**
2002
- * Registers test, if async - adds to pending array
2003
- */
2004
- function registerTest(testObject) {
2005
- var emit = useBus().emit;
2006
- // Run test callback.
2007
- // If a promise is returned, set as async and
2008
- // Move to pending list.
2009
- var result = runSyncTest(testObject);
2010
- try {
2011
- // try catch for safe property access
2012
- // in case object is an enforce chain
2013
- if (isPromise(result)) {
2014
- testObject.asyncTest = result;
2015
- testObject.setPending();
2016
- runAsyncTest(testObject);
2017
- }
2018
- else {
2019
- emit(Events.TEST_COMPLETED, testObject);
2020
- }
2021
- }
2022
- catch (e) {
2023
- throwError("Your test function " + testObject.fieldName + " returned " + JSON.stringify(result) + ". Only \"false\" or a Promise are supported. Return values may cause unexpected behavior.");
2024
- }
2025
- }
2026
-
2027
- /**
2028
- * This module serves as the "collision detection" mechanism for Vest.
2029
- * It is used to ensure that tests are not called in a different order than
2030
- * they were called in the previous run.
2031
- * If they are, it will throw a deferred error unless explicitly allowed.
2032
- *
2033
- * For now it seems pretty safe, and it covers most common use cases, but it can
2034
- * be improved in the future both in terms of performance and scenarios it covers.
2035
- */
2036
- // eslint-disable-next-line max-statements, max-lines-per-function
2037
- function useTestAtCursor(newTestObject) {
2038
- var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
2039
- var prevTests = testObjects.prev;
2040
- if (isEmpty(prevTests)) {
2041
- useSetTestAtCursor(newTestObject);
2042
- return newTestObject;
2043
- }
2044
- var prevTest = useGetTestAtCursor(prevTests);
2045
- if (shouldPurgePrevTest(prevTest, newTestObject)) {
2046
- throwTestOrderError(prevTest, newTestObject);
2047
- // Here we handle just the omission of tests in the middle of the test suite.
2048
- // We need to also handle a case in which tests are added in between other tests.
2049
- // At the moment all we can do is just splice the tests out of the array when this happens.
2050
- // A viable solution would be to use something like React's key prop to identify tests regardless
2051
- // of their position in the suite. https://reactjs.org/docs/lists-and-keys.html#keys
2052
- var current = getCurrent(prevTests, usePath());
2053
- var cursorAt = useCursorAt();
2054
- current.splice(cursorAt);
2055
- // We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
2056
- // since we're only touching the "prev" state. The reason we still use the setter function is
2057
- // to prevent future headaches if we ever do need to rely on prev-state immutability.
2058
- setTestObjects(function (_a) {
2059
- var current = _a.current;
2060
- return ({
2061
- prev: prevTests,
2062
- current: current
2063
- });
2064
- });
2065
- // Need to see if this has any effect at all.
2066
- prevTest = null;
2067
- }
2068
- var nextTest = defaultTo(prevTest, newTestObject);
2069
- useSetTestAtCursor(nextTest);
2070
- return nextTest;
2071
- }
2072
- function useSetTestAtCursor(testObject) {
2073
- var cursorPath = usePath();
2074
- useSetTests(function (tests) {
2075
- return setValueAtPath(tests, cursorPath, testObject);
2076
- });
2077
- }
2078
- function useGetTestAtCursor(tests) {
2079
- var cursorPath = usePath();
2080
- return valueAtPath(tests, cursorPath);
2081
- }
2082
- function shouldPurgePrevTest(prevTest, newTest) {
2083
- return isNotEmpty(prevTest) && !isSameProfileTest(prevTest, newTest);
2084
- }
2085
- function throwTestOrderError(prevTest, newTestObject) {
2086
- if (shouldAllowReorder()) {
2087
- return;
2088
- }
2089
- throwErrorDeferred("Vest Critical Error: Tests called in different order than previous run.\n expected: " + prevTest.fieldName + "\n received: " + newTestObject.fieldName + "\n This happens when you conditionally call your tests using if/else.\n This might lead to incorrect validation results.\n Replacing if/else with skipWhen solves these issues.");
2090
- }
2091
-
2092
- function registerPrevRunTest(testObject) {
2093
- var prevRunTest = useTestAtCursor(testObject);
2094
- if (isExcluded(testObject)) {
2095
- testObject.skip();
2096
- moveForward();
2097
- return prevRunTest;
2098
- }
2099
- cancelOverriddenPendingTest(prevRunTest, testObject);
2100
- useSetTestAtCursor(testObject);
2101
- moveForward();
2102
- registerTestObjectByTier(testObject);
2103
- return testObject;
2104
- }
2105
- function registerTestObjectByTier(testObject) {
2106
- if (testObject.isUntested()) {
2107
- registerTest(testObject);
2108
- }
2109
- else if (isPromise(testObject.asyncTest)) {
2110
- testObject.setPending();
2111
- runAsyncTest(testObject);
2112
- }
2113
- }
2114
-
2115
- function bindTestEach(test) {
2116
- /**
2117
- * Run multiple tests using a parameter table
2118
- */
2119
- function each(table) {
2120
- if (!isArray(table)) {
2121
- throwError('test.each: Expected table to be an array.');
2122
- }
2123
- function eachReturn(fieldName) {
2124
- var args = [];
2125
- for (var _i = 1; _i < arguments.length; _i++) {
2126
- args[_i - 1] = arguments[_i];
2127
- }
2128
- var _a = args.reverse(), testFn = _a[0], message = _a[1];
2129
- return isolate({ type: IsolateTypes.EACH }, function () {
2130
- return table.map(function (item) {
2131
- item = asArray(item);
2132
- return test(optionalFunctionValue.apply(void 0, __spreadArray([fieldName], item)), optionalFunctionValue.apply(void 0, __spreadArray([message], item)), function () { return testFn.apply(void 0, item); } // eslint-disable-line max-nested-callbacks
2133
- );
2134
- });
2135
- });
2136
- }
2137
- return eachReturn;
2138
- }
2139
- return each;
2140
- }
2141
-
2142
- // eslint-disable-next-line max-lines-per-function
2143
- function bindTestMemo(test) {
2144
- var cache = createCache(100); // arbitrary cache size
2145
- // eslint-disable-next-line max-statements
2146
- function memo(fieldName) {
2147
- var args = [];
2148
- for (var _i = 1; _i < arguments.length; _i++) {
2149
- args[_i - 1] = arguments[_i];
2150
- }
2151
- var suiteId = useSuiteId()[0];
2152
- var cursorAt = useCursorAt();
2153
- var _a = args.reverse(), deps = _a[0], testFn = _a[1], msg = _a[2];
2154
- // Implicit dependency for more specificity
2155
- var dependencies = [suiteId, fieldName, cursorAt].concat(deps);
2156
- var cached = cache.get(dependencies);
2157
- if (isNull(cached)) {
2158
- // cache miss
2159
- return cache(dependencies, function () { return test(fieldName, msg, testFn); });
2160
- }
2161
- if (cached[1].isCanceled()) {
2162
- // cache hit, but test is canceled
2163
- cache.invalidate(dependencies);
2164
- return cache(dependencies, function () { return test(fieldName, msg, testFn); });
2165
- }
2166
- return registerPrevRunTest(cached[1]);
2167
- }
2168
- return memo;
2169
- }
2170
-
2171
- function testBase(fieldName) {
2172
- var args = [];
2173
- for (var _i = 1; _i < arguments.length; _i++) {
2174
- args[_i - 1] = arguments[_i];
2175
- }
2176
- var _a = args.reverse(), testFn = _a[0], message = _a[1];
2177
- var context = ctx.useX();
2178
- var testObject = new VestTest(fieldName, testFn, {
2179
- message: message,
2180
- groupName: context === null || context === void 0 ? void 0 : context.groupName
2181
- });
2182
- return registerPrevRunTest(testObject);
2183
- }
2184
- var test = assign(testBase, {
2185
- each: bindTestEach(testBase),
2186
- memo: bindTestMemo(testBase)
2187
- });
2188
-
2189
- var VERSION = "4.0.0-dev-7acb76";
2190
-
2191
- exports.VERSION = VERSION;
2192
- exports.create = create;
2193
- exports.enforce = enforce;
2194
- exports.group = group;
2195
- exports.only = only;
2196
- exports.optional = optional;
2197
- exports.skip = skip;
2198
- exports.skipWhen = skipWhen;
2199
- exports.test = test;
2200
- exports.warn = warn;
2201
-
2202
- Object.defineProperty(exports, '__esModule', { value: true });
744
+ function __spreadArray(to, from, pack) {
745
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
746
+ if (ar || !(i in from)) {
747
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
748
+ ar[i] = from[i];
749
+ }
750
+ }
751
+ return to.concat(ar || from);
752
+ }
753
+
754
+ function either(a, b) {
755
+ return !!a !== !!b;
756
+ }
757
+
758
+ /**
759
+ * Checks that a given test object matches the currently specified severity level
760
+ */
761
+ function nonMatchingSeverityProfile(severity, testObject) {
762
+ return either(severity === 'warnings', testObject.warns());
763
+ }
764
+
765
+ function collectFailureMessages(severity, testObjects, options) {
766
+ var _a;
767
+ if (options === void 0) { options = {}; }
768
+ var _b = options || {}, group = _b.group, fieldName = _b.fieldName;
769
+ var res = testObjects.reduce(function (collector, testObject) {
770
+ if (noMatch(testObject, severity, group, fieldName)) {
771
+ return collector;
772
+ }
773
+ if (!testObject.hasFailures()) {
774
+ return collector;
775
+ }
776
+ collector[testObject.fieldName] = (collector[testObject.fieldName] || []).concat(testObject.message || []);
777
+ return collector;
778
+ }, __assign({}, (fieldName && (_a = {}, _a[fieldName] = [], _a))));
779
+ return res;
780
+ }
781
+ function noGroupMatch(testObject, groupName) {
782
+ return !!(groupName && testObject.groupName !== groupName);
783
+ }
784
+ function noMatch(testObject, severity, group, fieldName) {
785
+ if (noGroupMatch(testObject, group)) {
786
+ return true;
787
+ }
788
+ if (nonMatchingFieldName(testObject, fieldName)) {
789
+ return true;
790
+ }
791
+ if (nonMatchingSeverityProfile(severity, testObject)) {
792
+ return true;
793
+ }
794
+ return false;
795
+ }
796
+
797
+ function getFailuresArrayOrObject(group, fieldName) {
798
+ if (fieldName) {
799
+ return group[fieldName];
800
+ }
801
+ return group;
802
+ }
803
+
804
+ function getErrors(fieldName) {
805
+ return getFailures('errors', fieldName);
806
+ }
807
+ function getWarnings(fieldName) {
808
+ return getFailures('warnings', fieldName);
809
+ }
810
+ /**
811
+ * @returns suite or field's errors or warnings.
812
+ */
813
+ function getFailures(severityKey, fieldName) {
814
+ var testObjects = useTestsFlat();
815
+ var failureMessages = collectFailureMessages(severityKey, testObjects, {
816
+ fieldName: fieldName
817
+ });
818
+ return getFailuresArrayOrObject(failureMessages, fieldName);
819
+ }
820
+
821
+ function getErrorsByGroup(groupName, fieldName) {
822
+ var errors = getByGroup('errors', groupName, fieldName);
823
+ return getFailuresArrayOrObject(errors, fieldName);
824
+ }
825
+ function getWarningsByGroup(groupName, fieldName) {
826
+ var warnings = getByGroup('warnings', groupName, fieldName);
827
+ return getFailuresArrayOrObject(warnings, fieldName);
828
+ }
829
+ /**
830
+ * Gets failure messages by group.
831
+ */
832
+ function getByGroup(severityKey, group, fieldName) {
833
+ if (!group) {
834
+ throwError("get" + severityKey[0].toUpperCase() + severityKey.slice(1) + "ByGroup requires a group name. Received `" + group + "` instead.");
835
+ }
836
+ var testObjects = useTestsFlat();
837
+ var failureMessages = collectFailureMessages(severityKey, testObjects, {
838
+ group: group,
839
+ fieldName: fieldName
840
+ });
841
+ return failureMessages;
842
+ }
843
+
844
+ /**
845
+ * Determines whether a certain test profile has failures.
846
+ */
847
+ function hasFailuresLogic(testObject, severityKey, fieldName) {
848
+ if (!testObject.hasFailures()) {
849
+ return false;
850
+ }
851
+ if (nonMatchingFieldName(testObject, fieldName)) {
852
+ return false;
853
+ }
854
+ if (nonMatchingSeverityProfile(severityKey, testObject)) {
855
+ return false;
856
+ }
857
+ return true;
858
+ }
859
+
860
+ function hasErrors(fieldName) {
861
+ return has('errors', fieldName);
862
+ }
863
+ function hasWarnings(fieldName) {
864
+ return has('warnings', fieldName);
865
+ }
866
+ function has(severityKey, fieldName) {
867
+ var testObjects = useTestsFlat();
868
+ return testObjects.some(function (testObject) {
869
+ return hasFailuresLogic(testObject, severityKey, fieldName);
870
+ });
871
+ }
872
+
873
+ function hasErrorsByGroup(groupName, fieldName) {
874
+ return hasByGroup('errors', groupName, fieldName);
875
+ }
876
+ function hasWarningsByGroup(groupName, fieldName) {
877
+ return hasByGroup('warnings', groupName, fieldName);
878
+ }
879
+ /**
880
+ * Checks whether there are failures in a given group.
881
+ */
882
+ function hasByGroup(severityKey, group, fieldName) {
883
+ var testObjects = useTestsFlat();
884
+ return testObjects.some(function (testObject) {
885
+ return group === testObject.groupName
886
+ ? hasFailuresLogic(testObject, severityKey, fieldName)
887
+ : false;
888
+ });
889
+ }
890
+
891
+ // eslint-disable-next-line max-statements, complexity
892
+ function isValid(result, fieldName) {
893
+ if (fieldIsOmitted(fieldName)) {
894
+ return true;
895
+ }
896
+ if (result.hasErrors(fieldName)) {
897
+ return false;
898
+ }
899
+ var testObjects = useTestsFlat();
900
+ if (isEmpty(testObjects)) {
901
+ return false;
902
+ }
903
+ if (fieldDoesNotExist(result, fieldName)) {
904
+ return false;
905
+ }
906
+ if (hasNonOptionalIncomplete(fieldName)) {
907
+ return false;
908
+ }
909
+ return noMissingTests(fieldName);
910
+ }
911
+ function fieldIsOmitted(fieldName) {
912
+ var omittedFields = useOmittedFields();
913
+ if (!fieldName) {
914
+ return false;
915
+ }
916
+ return !!omittedFields[fieldName];
917
+ }
918
+ function hasNonOptionalIncomplete(fieldName) {
919
+ var optionalFields = useOptionalFields()[0];
920
+ return isNotEmpty(useAllIncomplete().filter(function (testObject) {
921
+ if (nonMatchingFieldName(testObject, fieldName)) {
922
+ return false;
923
+ }
924
+ return optionalFields[testObject.fieldName] !== true;
925
+ }));
926
+ }
927
+ function fieldDoesNotExist(result, fieldName) {
928
+ return !!fieldName && isEmpty(result.tests[fieldName]);
929
+ }
930
+ function noMissingTests(fieldName) {
931
+ var testObjects = useTestsFlat();
932
+ var optionalFields = useOptionalFields()[0];
933
+ return testObjects.every(function (testObject) {
934
+ if (nonMatchingFieldName(testObject, fieldName)) {
935
+ return true;
936
+ }
937
+ return (optionalFields[testObject.fieldName] === true ||
938
+ testObject.isTested() ||
939
+ testObject.isOmitted());
940
+ });
941
+ }
942
+
943
+ var cache$1 = createCache(20);
944
+ function produceDraft() {
945
+ var testObjects = useTestsFlat();
946
+ var ctxRef = { stateRef: useStateRef() };
947
+ return cache$1([testObjects], context.bind(ctxRef, function () {
948
+ var suiteName = useSuiteName();
949
+ return assign(genTestsSummary(), {
950
+ getErrors: context.bind(ctxRef, getErrors),
951
+ getErrorsByGroup: context.bind(ctxRef, getErrorsByGroup),
952
+ getWarnings: context.bind(ctxRef, getWarnings),
953
+ getWarningsByGroup: context.bind(ctxRef, getWarningsByGroup),
954
+ hasErrors: context.bind(ctxRef, hasErrors),
955
+ hasErrorsByGroup: context.bind(ctxRef, hasErrorsByGroup),
956
+ hasWarnings: context.bind(ctxRef, hasWarnings),
957
+ hasWarningsByGroup: context.bind(ctxRef, hasWarningsByGroup),
958
+ isValid: context.bind(ctxRef, function (fieldName) {
959
+ return isValid(produceDraft(), fieldName);
960
+ }),
961
+ suiteName: suiteName
962
+ });
963
+ }));
964
+ }
965
+
966
+ var cache = createCache(20);
967
+ function produceFullResult() {
968
+ var testObjects = useTestsFlat();
969
+ var ctxRef = { stateRef: useStateRef() };
970
+ return cache([testObjects], context.bind(ctxRef, function () {
971
+ return assign({}, produceDraft(), {
972
+ done: context.bind(ctxRef, done)
973
+ });
974
+ }));
975
+ }
976
+ /**
977
+ * DONE is here and not in its own module to prevent circular dependency issues.
978
+ */
979
+ function shouldSkipDoneRegistration(callback, fieldName, output) {
980
+ // If we do not have any test runs for the current field
981
+ return !!(!isFunction(callback) ||
982
+ (fieldName &&
983
+ (!output.tests[fieldName] || isEmpty(output.tests[fieldName].testCount))));
984
+ }
985
+ function shouldRunDoneCallback(fieldName) {
986
+ // is suite finished || field name exists, and test is finished;
987
+ return !!(!hasRemainingTests() ||
988
+ (fieldName && !hasRemainingTests(fieldName)));
989
+ }
990
+ /**
991
+ * Registers done callbacks.
992
+ * @register {Object} Vest output object.
993
+ */
994
+ var done = function done() {
995
+ var args = [];
996
+ for (var _i = 0; _i < arguments.length; _i++) {
997
+ args[_i] = arguments[_i];
998
+ }
999
+ var _a = args.reverse(), callback = _a[0], fieldName = _a[1];
1000
+ var output = produceFullResult();
1001
+ if (shouldSkipDoneRegistration(callback, fieldName, output)) {
1002
+ return output;
1003
+ }
1004
+ var doneCallback = function () { return callback(produceDraft()); };
1005
+ if (shouldRunDoneCallback(fieldName)) {
1006
+ doneCallback();
1007
+ return output;
1008
+ }
1009
+ deferDoneCallback(doneCallback, fieldName);
1010
+ return output;
1011
+ };
1012
+ function deferDoneCallback(doneCallback, fieldName) {
1013
+ var deferredCallback = context.bind({}, doneCallback);
1014
+ var _a = useTestCallbacks(), setTestCallbacks = _a[1];
1015
+ setTestCallbacks(function (current) {
1016
+ if (fieldName) {
1017
+ current.fieldCallbacks[fieldName] = (current.fieldCallbacks[fieldName] || []).concat(deferredCallback);
1018
+ }
1019
+ else {
1020
+ current.doneCallbacks.push(deferredCallback);
1021
+ }
1022
+ return current;
1023
+ });
1024
+ }
1025
+
1026
+ function createBus() {
1027
+ var listeners = {};
1028
+ return {
1029
+ emit: function (event, data) {
1030
+ if (!listeners[event]) {
1031
+ return;
1032
+ }
1033
+ listeners[event].forEach(function (listener) {
1034
+ listener(data);
1035
+ });
1036
+ },
1037
+ on: function (event, handler) {
1038
+ if (!listeners[event]) {
1039
+ listeners[event] = [];
1040
+ }
1041
+ listeners[event].push(handler);
1042
+ return {
1043
+ off: function () {
1044
+ listeners[event] = listeners[event].filter(function (h) { return h !== handler; });
1045
+ }
1046
+ };
1047
+ }
1048
+ };
1049
+ }
1050
+
1051
+ function omitOptionalTests() {
1052
+ var optionalFields = useOptionalFields()[0];
1053
+ if (isEmpty(optionalFields)) {
1054
+ return;
1055
+ }
1056
+ var shouldOmit = {};
1057
+ useSetTests(function (tests) {
1058
+ return transform(tests, function (testObject) {
1059
+ var fieldName = testObject.fieldName;
1060
+ if (shouldOmit.hasOwnProperty(fieldName)) {
1061
+ omit(testObject);
1062
+ }
1063
+ else {
1064
+ var optionalConfig = optionalFields[fieldName];
1065
+ if (isFunction(optionalConfig)) {
1066
+ shouldOmit[fieldName] = optionalConfig();
1067
+ omit(testObject);
1068
+ }
1069
+ }
1070
+ return testObject;
1071
+ });
1072
+ });
1073
+ function omit(testObject) {
1074
+ if (shouldOmit[testObject.fieldName]) {
1075
+ testObject.omit();
1076
+ }
1077
+ }
1078
+ }
1079
+
1080
+ /**
1081
+ * Removes test object from suite state
1082
+ */
1083
+ function removeTestFromState (testObject) {
1084
+ useSetTests(function (tests) {
1085
+ return transform(tests, function (test) { return (testObject !== test ? test : null); });
1086
+ });
1087
+ }
1088
+
1089
+ function callEach(arr) {
1090
+ return arr.forEach(function (fn) { return fn(); });
1091
+ }
1092
+
1093
+ /**
1094
+ * Runs done callback per field when async tests are finished running.
1095
+ */
1096
+ function runFieldCallbacks(fieldName) {
1097
+ var fieldCallbacks = useTestCallbacks()[0].fieldCallbacks;
1098
+ if (fieldName) {
1099
+ if (!hasRemainingTests(fieldName) && isArray(fieldCallbacks[fieldName])) {
1100
+ callEach(fieldCallbacks[fieldName]);
1101
+ }
1102
+ }
1103
+ }
1104
+ /**
1105
+ * Runs unlabelled done callback when async tests are finished running.
1106
+ */
1107
+ function runDoneCallbacks() {
1108
+ var doneCallbacks = useTestCallbacks()[0].doneCallbacks;
1109
+ if (!hasRemainingTests()) {
1110
+ callEach(doneCallbacks);
1111
+ }
1112
+ }
1113
+
1114
+ function initBus() {
1115
+ var bus = createBus();
1116
+ // Report a the completion of a test. There may be other tests with the same
1117
+ // name that are still running, or not yet started.
1118
+ bus.on(Events.TEST_COMPLETED, function (testObject) {
1119
+ if (testObject.isCanceled()) {
1120
+ return;
1121
+ }
1122
+ testObject.done();
1123
+ runFieldCallbacks(testObject.fieldName);
1124
+ runDoneCallbacks();
1125
+ });
1126
+ // Report that the suite completed its synchronous test run.
1127
+ // Async operations may still be running.
1128
+ bus.on(Events.SUITE_COMPLETED, function () {
1129
+ // Remove tests that are optional and need to be omitted
1130
+ omitOptionalTests();
1131
+ });
1132
+ // Removes a certain field from the state.
1133
+ bus.on(Events.REMOVE_FIELD, function (fieldName) {
1134
+ var testObjects = useTestsFlat();
1135
+ testObjects.forEach(function (testObject) {
1136
+ if (matchingFieldName(testObject, fieldName)) {
1137
+ testObject.cancel();
1138
+ removeTestFromState(testObject);
1139
+ }
1140
+ });
1141
+ });
1142
+ return bus;
1143
+ }
1144
+ function useBus() {
1145
+ var context$1 = context.useX();
1146
+ if (!context$1.bus) {
1147
+ throwError();
1148
+ }
1149
+ return context$1.bus;
1150
+ }
1151
+ var Events;
1152
+ (function (Events) {
1153
+ Events["TEST_COMPLETED"] = "test_completed";
1154
+ Events["REMOVE_FIELD"] = "remove_field";
1155
+ Events["SUITE_COMPLETED"] = "suite_completed";
1156
+ })(Events || (Events = {}));
1157
+
1158
+ // eslint-disable-next-line max-lines-per-function
1159
+ function create() {
1160
+ var args = [];
1161
+ for (var _i = 0; _i < arguments.length; _i++) {
1162
+ args[_i] = arguments[_i];
1163
+ }
1164
+ var _a = args.reverse(), suiteCallback = _a[0], suiteName = _a[1];
1165
+ if (!isFunction(suiteCallback)) {
1166
+ throwError('vest.create: Expected callback to be a function.');
1167
+ }
1168
+ // Event bus initialization
1169
+ var bus = initBus();
1170
+ // State initialization
1171
+ var state = createState();
1172
+ // State reference - this holds the actual state values
1173
+ var stateRef = createStateRef(state, { suiteId: genId(), suiteName: suiteName });
1174
+ // Create base context reference. All hooks will derive their data from this
1175
+ var ctxRef = { stateRef: stateRef, bus: bus };
1176
+ var suite = assign(
1177
+ // Bind the suite body to the context
1178
+ context.bind(ctxRef, function () {
1179
+ var args = [];
1180
+ for (var _i = 0; _i < arguments.length; _i++) {
1181
+ args[_i] = arguments[_i];
1182
+ }
1183
+ // Reset the state. Migrates current test objects to `prev` array.
1184
+ state.reset();
1185
+ // Create a top level isolate
1186
+ isolate({ type: IsolateTypes.SUITE }, function () {
1187
+ // Run the consumer's callback
1188
+ suiteCallback.apply(void 0, args);
1189
+ });
1190
+ // Report the suite is done registering tests
1191
+ // Async tests may still be running
1192
+ bus.emit(Events.SUITE_COMPLETED);
1193
+ // Return the result
1194
+ return produceFullResult();
1195
+ }), {
1196
+ get: context.bind(ctxRef, produceDraft),
1197
+ reset: state.reset,
1198
+ remove: context.bind(ctxRef, function (fieldName) {
1199
+ bus.emit(Events.REMOVE_FIELD, fieldName);
1200
+ })
1201
+ });
1202
+ return suite;
1203
+ }
1204
+
1205
+ function each(list, callback) {
1206
+ if (!isFunction(callback)) {
1207
+ throwError('callback must be a function');
1208
+ }
1209
+ isolate({ type: IsolateTypes.EACH }, function () {
1210
+ list.forEach(function (arg, index) {
1211
+ callback(arg, index);
1212
+ });
1213
+ });
1214
+ }
1215
+
1216
+ /**
1217
+ * Error message to display when a hook was called outside of context.
1218
+ */
1219
+ var ERROR_HOOK_CALLED_OUTSIDE = 'hook called outside of a running suite.';
1220
+
1221
+ /**
1222
+ * Adds a field or multiple fields to inclusion group.
1223
+ */
1224
+ function only(item) {
1225
+ return addTo(0 /* ONLY */, 'tests', item);
1226
+ }
1227
+ only.group = function (item) {
1228
+ return addTo(0 /* ONLY */, 'groups', item);
1229
+ };
1230
+ /**
1231
+ * Adds a field or multiple fields to exclusion group.
1232
+ */
1233
+ function skip(item) {
1234
+ return addTo(1 /* SKIP */, 'tests', item);
1235
+ }
1236
+ skip.group = function (item) {
1237
+ return addTo(1 /* SKIP */, 'groups', item);
1238
+ };
1239
+ function isExcludedIndividually() {
1240
+ return !!context.useX().skipped;
1241
+ }
1242
+ //Checks whether a certain test profile excluded by any of the exclusion groups.
1243
+ // eslint-disable-next-line complexity, max-statements
1244
+ function isExcluded(testObject) {
1245
+ var fieldName = testObject.fieldName, groupName = testObject.groupName;
1246
+ if (isExcludedIndividually())
1247
+ return true;
1248
+ var context$1 = context.useX();
1249
+ var exclusion = context$1.exclusion;
1250
+ var keyTests = exclusion.tests;
1251
+ var testValue = keyTests[fieldName];
1252
+ // if test is skipped
1253
+ // no need to proceed
1254
+ if (testValue === false)
1255
+ return true;
1256
+ var isTestIncluded = testValue === true;
1257
+ // If inside a group
1258
+ if (groupName) {
1259
+ if (isGroupExcluded(groupName)) {
1260
+ return true; // field excluded by group
1261
+ // if group is `only`ed
1262
+ }
1263
+ else if (exclusion.groups[groupName] === true) {
1264
+ if (isTestIncluded)
1265
+ return false;
1266
+ // If there is _ANY_ `only`ed test (and we already know this one isn't)
1267
+ if (hasIncludedTests(keyTests))
1268
+ return true; // Excluded implicitly
1269
+ return keyTests[fieldName] === false;
1270
+ }
1271
+ }
1272
+ if (isMissingFromIncludedGroup(groupName)) {
1273
+ return true;
1274
+ }
1275
+ // if field is only'ed
1276
+ if (isTestIncluded)
1277
+ return false;
1278
+ // If there is _ANY_ `only`ed test (and we already know this one isn't) return true
1279
+ // Otherwise return false
1280
+ return hasIncludedTests(keyTests);
1281
+ }
1282
+ // eslint-disable-next-line max-statements
1283
+ function isMissingFromIncludedGroup(groupName) {
1284
+ var context$1 = context.useX();
1285
+ var exclusion = context$1.exclusion;
1286
+ if (!hasIncludedGroups()) {
1287
+ return false;
1288
+ }
1289
+ if (!groupName) {
1290
+ return true;
1291
+ }
1292
+ if (groupName in exclusion.groups) {
1293
+ if (exclusion.groups[groupName]) {
1294
+ return false;
1295
+ }
1296
+ return true;
1297
+ }
1298
+ return true;
1299
+ }
1300
+ function hasIncludedGroups() {
1301
+ var context$1 = context.useX();
1302
+ var exclusion = context$1.exclusion;
1303
+ for (var group in exclusion.groups) {
1304
+ if (exclusion.groups[group]) {
1305
+ return true;
1306
+ }
1307
+ }
1308
+ return false;
1309
+ }
1310
+ /**
1311
+ * Checks whether a given group is excluded from running.
1312
+ */
1313
+ function isGroupExcluded(groupName) {
1314
+ var context$1 = context.useX();
1315
+ var exclusion = context$1.exclusion;
1316
+ var keyGroups = exclusion.groups;
1317
+ var groupPresent = hasOwnProperty(keyGroups, groupName);
1318
+ // When group is either only'ed or skipped
1319
+ if (groupPresent) {
1320
+ // Return true if group is skipped and false if only'ed
1321
+ return keyGroups[groupName] === false;
1322
+ }
1323
+ // Group is not present
1324
+ for (var group in keyGroups) {
1325
+ // If any other group is only'ed
1326
+ if (keyGroups[group] === true) {
1327
+ return true;
1328
+ }
1329
+ }
1330
+ return false;
1331
+ }
1332
+ /**
1333
+ * Adds fields to a specified exclusion group.
1334
+ */
1335
+ function addTo(exclusionGroup, itemType, item) {
1336
+ var context$1 = context.useX(ERROR_HOOK_CALLED_OUTSIDE);
1337
+ if (!item) {
1338
+ return;
1339
+ }
1340
+ asArray(item).forEach(function (itemName) {
1341
+ if (!isStringValue(itemName)) {
1342
+ return;
1343
+ }
1344
+ context$1.exclusion[itemType][itemName] =
1345
+ exclusionGroup === 0 /* ONLY */;
1346
+ });
1347
+ }
1348
+ /**
1349
+ * Checks if context has included tests
1350
+ */
1351
+ function hasIncludedTests(keyTests) {
1352
+ for (var test in keyTests) {
1353
+ if (keyTests[test] === true) {
1354
+ return true; // excluded implicitly
1355
+ }
1356
+ }
1357
+ return false;
1358
+ }
1359
+
1360
+ /**
1361
+ * Runs a group callback.
1362
+ */
1363
+ function group(groupName, tests) {
1364
+ if (!isStringValue(groupName)) {
1365
+ throwGroupError('name must be a string');
1366
+ }
1367
+ if (!isFunction(tests)) {
1368
+ throwGroupError('callback must be a function');
1369
+ }
1370
+ // Running with the context applied
1371
+ isolate({ type: IsolateTypes.GROUP }, function () {
1372
+ context.run({ groupName: groupName }, tests);
1373
+ });
1374
+ }
1375
+ function throwGroupError(error) {
1376
+ throwError("Wrong arguments passed to group. Group " + error + ".");
1377
+ }
1378
+
1379
+ function optional(optionals) {
1380
+ var _a = useOptionalFields(), setOptionalFields = _a[1];
1381
+ setOptionalFields(function (state) {
1382
+ if (!isArray(optionals) && !isStringValue(optionals)) {
1383
+ var optionalFunctions = optionals;
1384
+ for (var field in optionalFunctions) {
1385
+ var predicate = optionalFunctions[field];
1386
+ state[field] = predicate;
1387
+ }
1388
+ }
1389
+ else {
1390
+ asArray(optionals).forEach(function (optionalField) {
1391
+ state[optionalField] = true;
1392
+ });
1393
+ }
1394
+ return state;
1395
+ });
1396
+ }
1397
+
1398
+ function skipWhen(conditional, callback) {
1399
+ isolate({ type: IsolateTypes.SKIP_WHEN }, function () {
1400
+ context.run({
1401
+ skipped: optionalFunctionValue(conditional, optionalFunctionValue(produceDraft))
1402
+ }, function () { return callback(); });
1403
+ });
1404
+ }
1405
+
1406
+ var isNotString = bindNot(isStringValue);
1407
+
1408
+ function isPromise(value) {
1409
+ return value && isFunction(value.then);
1410
+ }
1411
+
1412
+ function isSameProfileTest(testObject1, testObject2) {
1413
+ return (testObject1.fieldName === testObject2.fieldName &&
1414
+ testObject1.groupName === testObject2.groupName);
1415
+ }
1416
+
1417
+ function cancelOverriddenPendingTest(prevRunTestObject, currentRunTestObject) {
1418
+ if (currentRunTestObject !== prevRunTestObject &&
1419
+ isSameProfileTest(prevRunTestObject, currentRunTestObject) &&
1420
+ prevRunTestObject.isPending()) {
1421
+ prevRunTestObject.cancel();
1422
+ }
1423
+ }
1424
+
1425
+ /**
1426
+ * Runs async test.
1427
+ */
1428
+ function runAsyncTest(testObject) {
1429
+ var asyncTest = testObject.asyncTest, message = testObject.message;
1430
+ if (!isPromise(asyncTest))
1431
+ return;
1432
+ var emit = useBus().emit;
1433
+ var stateRef = useStateRef();
1434
+ var done = context.bind({ stateRef: stateRef }, function () {
1435
+ // invalidating the "produce" cache
1436
+ useRefreshTestObjects();
1437
+ emit(Events.TEST_COMPLETED, testObject);
1438
+ });
1439
+ var fail = context.bind({ stateRef: stateRef }, function (rejectionMessage) {
1440
+ if (testObject.isCanceled()) {
1441
+ return;
1442
+ }
1443
+ testObject.message = isStringValue(rejectionMessage)
1444
+ ? rejectionMessage
1445
+ : message;
1446
+ testObject.fail();
1447
+ done();
1448
+ });
1449
+ try {
1450
+ asyncTest.then(done, fail);
1451
+ }
1452
+ catch (e) {
1453
+ fail();
1454
+ }
1455
+ }
1456
+
1457
+ /**
1458
+ * Runs sync tests - or extracts promise.
1459
+ */
1460
+ function runSyncTest(testObject) {
1461
+ return context.run({ currentTest: testObject }, function () {
1462
+ var result;
1463
+ try {
1464
+ result = testObject.testFn();
1465
+ }
1466
+ catch (e) {
1467
+ if (shouldUseErrorAsMessage(testObject.message, e)) {
1468
+ testObject.message = e;
1469
+ }
1470
+ result = false;
1471
+ }
1472
+ if (result === false) {
1473
+ testObject.fail();
1474
+ }
1475
+ return result;
1476
+ });
1477
+ }
1478
+
1479
+ /**
1480
+ * Registers test, if async - adds to pending array
1481
+ */
1482
+ function registerTest(testObject) {
1483
+ var bus = useBus();
1484
+ // Run test callback.
1485
+ // If a promise is returned, set as async and
1486
+ // Move to pending list.
1487
+ var result = runSyncTest(testObject);
1488
+ try {
1489
+ // try catch for safe property access
1490
+ // in case object is an enforce chain
1491
+ if (isPromise(result)) {
1492
+ testObject.asyncTest = result;
1493
+ testObject.setPending();
1494
+ runAsyncTest(testObject);
1495
+ }
1496
+ else {
1497
+ bus.emit(Events.TEST_COMPLETED, testObject);
1498
+ }
1499
+ }
1500
+ catch (e) {
1501
+ throwError("Your test function " + testObject.fieldName + " returned a value. Only \"false\" or Promise returns are supported.");
1502
+ }
1503
+ }
1504
+
1505
+ /**
1506
+ * This module serves as the "collision detection" mechanism for Vest.
1507
+ * It is used to ensure that tests are not called in a different order than
1508
+ * they were called in the previous run.
1509
+ * If they are, it will throw a deferred error unless explicitly allowed.
1510
+ *
1511
+ * For now it seems pretty safe, and it covers most common use cases, but it can
1512
+ * be improved in the future both in terms of performance and scenarios it covers.
1513
+ */
1514
+ // eslint-disable-next-line max-statements, max-lines-per-function
1515
+ function useTestAtCursor(newTestObject) {
1516
+ var testObjects = useTestObjects()[0];
1517
+ var prevTests = testObjects.prev;
1518
+ if (isEmpty(prevTests)) {
1519
+ useSetTestAtCursor(newTestObject);
1520
+ return newTestObject;
1521
+ }
1522
+ var prevTest = useGetTestAtCursor(prevTests);
1523
+ if (!isNullish(newTestObject.key)) {
1524
+ var nextTest_1 = handleKeyTest(newTestObject.key, newTestObject);
1525
+ useSetTestAtCursor(nextTest_1);
1526
+ return nextTest_1;
1527
+ }
1528
+ if (shouldPurgePrevTest(prevTest, newTestObject)) {
1529
+ throwTestOrderError(prevTest, newTestObject);
1530
+ removeAllNextTestsInIsolate();
1531
+ // Need to see if this has any effect at all.
1532
+ prevTest = null;
1533
+ }
1534
+ var nextTest = defaultTo(prevTest, newTestObject);
1535
+ useSetTestAtCursor(nextTest);
1536
+ return nextTest;
1537
+ }
1538
+ function removeAllNextTestsInIsolate() {
1539
+ var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
1540
+ var prevTests = testObjects.prev;
1541
+ var current = getCurrent(prevTests, usePath());
1542
+ var cursorAt = useCursorAt();
1543
+ current.splice(cursorAt);
1544
+ // We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
1545
+ // since we're only touching the "prev" state. The reason we still use the setter function is
1546
+ // to prevent future headaches if we ever do need to rely on prev-state immutability.
1547
+ setTestObjects(function (_a) {
1548
+ var current = _a.current;
1549
+ return ({
1550
+ prev: prevTests,
1551
+ current: current
1552
+ });
1553
+ });
1554
+ }
1555
+ function useSetTestAtCursor(testObject) {
1556
+ var cursorPath = usePath();
1557
+ useSetTests(function (tests) {
1558
+ return setValueAtPath(tests, cursorPath, testObject);
1559
+ });
1560
+ }
1561
+ function useGetTestAtCursor(tests) {
1562
+ var cursorPath = usePath();
1563
+ return valueAtPath(tests, cursorPath);
1564
+ }
1565
+ function shouldPurgePrevTest(prevTest, newTest) {
1566
+ return isNotEmpty(prevTest) && !isSameProfileTest(prevTest, newTest);
1567
+ }
1568
+ function throwTestOrderError(prevTest, newTestObject) {
1569
+ if (shouldAllowReorder()) {
1570
+ return;
1571
+ }
1572
+ throwErrorDeferred("Vest Critical Error: Tests called in different order than previous run.\n expected: " + prevTest.fieldName + "\n received: " + 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.");
1573
+ }
1574
+ function handleKeyTest(key, newTestObject) {
1575
+ var prevTestByKey = usePrevTestByKey(key);
1576
+ var nextTest = newTestObject;
1577
+ if (prevTestByKey) {
1578
+ nextTest = prevTestByKey;
1579
+ }
1580
+ useRetainTestKey(key, nextTest);
1581
+ return nextTest;
1582
+ }
1583
+
1584
+ function registerPrevRunTest(testObject) {
1585
+ var prevRunTest = useTestAtCursor(testObject);
1586
+ if (isExcluded(testObject)) {
1587
+ // We're forcing skipping the pending test
1588
+ // if we're directly within a skipWhen block
1589
+ // This mostly means that we're probably giving
1590
+ // up on this async test intentionally.
1591
+ prevRunTest.skip(isExcludedIndividually());
1592
+ moveForward();
1593
+ return prevRunTest;
1594
+ }
1595
+ cancelOverriddenPendingTest(prevRunTest, testObject);
1596
+ useSetTestAtCursor(testObject);
1597
+ moveForward();
1598
+ registerTestObjectByTier(testObject);
1599
+ return testObject;
1600
+ }
1601
+ function registerTestObjectByTier(testObject) {
1602
+ if (testObject.isUntested()) {
1603
+ registerTest(testObject);
1604
+ }
1605
+ else if (isPromise(testObject.asyncTest)) {
1606
+ testObject.setPending();
1607
+ runAsyncTest(testObject);
1608
+ }
1609
+ }
1610
+
1611
+ // eslint-disable-next-line max-lines-per-function
1612
+ function bindTestMemo(test) {
1613
+ var cache = createCache(100); // arbitrary cache size
1614
+ // eslint-disable-next-line max-statements
1615
+ function memo(fieldName) {
1616
+ var args = [];
1617
+ for (var _i = 1; _i < arguments.length; _i++) {
1618
+ args[_i - 1] = arguments[_i];
1619
+ }
1620
+ var cursorAt = useCursorAt();
1621
+ var _a = args.reverse(), deps = _a[0], testFn = _a[1], msg = _a[2];
1622
+ // Implicit dependency for more specificity
1623
+ var dependencies = [useSuiteId(), fieldName, cursorAt].concat(deps);
1624
+ var cached = cache.get(dependencies);
1625
+ if (isNull(cached)) {
1626
+ // cache miss
1627
+ return cache(dependencies, function () { return test(fieldName, msg, testFn); });
1628
+ }
1629
+ if (cached[1].isCanceled()) {
1630
+ // cache hit, but test is canceled
1631
+ cache.invalidate(dependencies);
1632
+ return cache(dependencies, function () { return test(fieldName, msg, testFn); });
1633
+ }
1634
+ return registerPrevRunTest(cached[1]);
1635
+ }
1636
+ return memo;
1637
+ }
1638
+
1639
+ function testBase(fieldName) {
1640
+ var args = [];
1641
+ for (var _i = 1; _i < arguments.length; _i++) {
1642
+ args[_i - 1] = arguments[_i];
1643
+ }
1644
+ var _a = (isFunction(args[1]) ? args : __spreadArray([undefined], args)), message = _a[0], testFn = _a[1], key = _a[2];
1645
+ if (isNotString(fieldName)) {
1646
+ throwIncompatibleParamsError('fieldName', 'string');
1647
+ }
1648
+ if (!isFunction(testFn)) {
1649
+ throwIncompatibleParamsError('Test callback', 'function');
1650
+ }
1651
+ var context$1 = context.useX();
1652
+ var testObject = new VestTest(fieldName, testFn, {
1653
+ message: message,
1654
+ groupName: context$1.groupName,
1655
+ key: key
1656
+ });
1657
+ return registerPrevRunTest(testObject);
1658
+ }
1659
+ var test = assign(testBase, {
1660
+ memo: bindTestMemo(testBase)
1661
+ });
1662
+ function throwIncompatibleParamsError(name, expected) {
1663
+ throwError("Incompatible params passed to test function. " + name + " must be a " + expected);
1664
+ }
1665
+
1666
+ var ERROR_OUTSIDE_OF_TEST = "warn hook called outside of a test callback. It won't have an effect."
1667
+ ;
1668
+ /**
1669
+ * Sets a running test to warn only mode.
1670
+ */
1671
+ function warn() {
1672
+ var ctx = context.useX('warn ' + ERROR_HOOK_CALLED_OUTSIDE);
1673
+ if (!ctx.currentTest) {
1674
+ throwError(ERROR_OUTSIDE_OF_TEST);
1675
+ }
1676
+ ctx.currentTest.warn();
1677
+ }
1678
+
1679
+ var VERSION = "4.0.0-dev-1aae50";
1680
+
1681
+ Object.defineProperty(exports, 'enforce', {
1682
+ enumerable: true,
1683
+ get: function () {
1684
+ return n4s.enforce;
1685
+ }
1686
+ });
1687
+ exports.VERSION = VERSION;
1688
+ exports.create = create;
1689
+ exports.each = each;
1690
+ exports.group = group;
1691
+ exports.only = only;
1692
+ exports.optional = optional;
1693
+ exports.skip = skip;
1694
+ exports.skipWhen = skipWhen;
1695
+ exports.test = test;
1696
+ exports.warn = warn;
1697
+
1698
+ Object.defineProperty(exports, '__esModule', { value: true });
2203
1699
 
2204
1700
  })));