vest 4.0.0-dev-deabb8 → 4.0.0-dev-8851ff

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.
@@ -228,8 +228,16 @@ function greaterThanOrEquals(value, gte) {
228
228
  return isNumeric(value) && isNumeric(gte) && Number(value) >= Number(gte);
229
229
  }
230
230
 
231
+ // The module is named "isArrayValue" since it
232
+ // is conflicting with a nested npm dependency.
233
+ // We may need to revisit this in the future.
234
+ function isArray(value) {
235
+ return Boolean(Array.isArray(value));
236
+ }
237
+ var isNotArray = bindNot(isArray);
238
+
231
239
  function inside(value, arg1) {
232
- if (Array.isArray(arg1)) {
240
+ if (isArray(arg1)) {
233
241
  return arg1.indexOf(value) !== -1;
234
242
  }
235
243
  // both value and arg1 are strings
@@ -240,14 +248,6 @@ function inside(value, arg1) {
240
248
  }
241
249
  var notInside = bindNot(inside);
242
250
 
243
- // The module is named "isArrayValue" since it
244
- // is conflicting with a nested npm dependency.
245
- // We may need to revisit this in the future.
246
- function isArray(value) {
247
- return Boolean(Array.isArray(value));
248
- }
249
- var isNotArray = bindNot(isArray);
250
-
251
251
  function lessThanOrEquals(value, lte) {
252
252
  return isNumeric(value) && isNumeric(lte) && Number(value) <= Number(lte);
253
253
  }
@@ -257,6 +257,11 @@ function isBetween(value, min, max) {
257
257
  }
258
258
  var isNotBetween = bindNot(isBetween);
259
259
 
260
+ function isBlank(value) {
261
+ return isStringValue(value) && !value.trim();
262
+ }
263
+ var isNotBlank = bindNot(isBlank);
264
+
260
265
  function isBoolean(value) {
261
266
  return !!value === value;
262
267
  }
@@ -395,6 +400,7 @@ function rules() {
395
400
  inside: inside,
396
401
  isArray: isArray,
397
402
  isBetween: isBetween,
403
+ isBlank: isBlank,
398
404
  isBoolean: isBoolean,
399
405
  isEmpty: isEmpty,
400
406
  isEven: isEven,
@@ -403,6 +409,7 @@ function rules() {
403
409
  isNegative: isNegative,
404
410
  isNotArray: isNotArray,
405
411
  isNotBetween: isNotBetween,
412
+ isNotBlank: isNotBlank,
406
413
  isNotBoolean: isNotBoolean,
407
414
  isNotEmpty: isNotEmpty,
408
415
  isNotNaN: isNotNaN,
@@ -445,6 +452,11 @@ function rules() {
445
452
  function throwError(devMessage, productionMessage) {
446
453
  throw new Error(devMessage );
447
454
  }
455
+ function throwErrorDeferred(devMessage, productionMessage) {
456
+ setTimeout(function () {
457
+ throwError(devMessage);
458
+ }, 0);
459
+ }
448
460
 
449
461
  // eslint-disable-next-line max-lines-per-function
450
462
  function createContext(init) {
@@ -609,7 +621,7 @@ function transformResult(result, ruleName, value) {
609
621
  return ruleReturn(result);
610
622
  }
611
623
  else {
612
- return ruleReturn(result.pass, optionalFunctionValue.apply(void 0, __spreadArray([result.message, ruleName, value], args, false)));
624
+ return ruleReturn(result.pass, optionalFunctionValue.apply(void 0, __spreadArray([result.message, ruleName, value], args)));
613
625
  }
614
626
  }
615
627
  function validateResult(result) {
@@ -643,9 +655,9 @@ function enforceEager(value) {
643
655
  for (var _i = 0; _i < arguments.length; _i++) {
644
656
  args[_i] = arguments[_i];
645
657
  }
646
- var transformedResult = transformResult.apply(void 0, __spreadArray([ctx$1.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args, false)); }),
658
+ var transformedResult = transformResult.apply(void 0, __spreadArray([ctx$1.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args)); }),
647
659
  ruleName,
648
- value], args, false));
660
+ value], args));
649
661
  if (!transformedResult.pass) {
650
662
  if (isEmpty(transformedResult.message)) {
651
663
  throwError("enforce/" + ruleName + " failed with " + JSON.stringify(value));
@@ -675,7 +687,7 @@ function genEnforceLazy(key) {
675
687
  }
676
688
  var rule = getRule(ruleName);
677
689
  registeredRules.push(function (value) {
678
- return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args, false)), ruleName, value], args, false));
690
+ return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args)), ruleName, value], args));
679
691
  });
680
692
  var proxy = {
681
693
  run: function (value) {
@@ -782,10 +794,6 @@ function genEnforce() {
782
794
  }
783
795
  var enforce = genEnforce();
784
796
 
785
- function asArray(possibleArg) {
786
- return [].concat(possibleArg);
787
- }
788
-
789
797
  /**
790
798
  * @returns a unique numeric id.
791
799
  */
@@ -822,15 +830,16 @@ function createState(onStateChange) {
822
830
  return initKey(key, initialState);
823
831
  }
824
832
  function reset() {
833
+ var prev = current();
825
834
  state.references = [];
826
835
  registrations.forEach(function (_a, index) {
827
836
  var initialValue = _a[0];
828
- return initKey(index, initialValue);
837
+ return initKey(index, initialValue, prev[index]);
829
838
  });
830
839
  }
831
- function initKey(key, initialState) {
840
+ function initKey(key, initialState, prevState) {
832
841
  current().push();
833
- set(key, optionalFunctionValue(initialState));
842
+ set(key, optionalFunctionValue(initialState, prevState));
834
843
  return function useStateKey() {
835
844
  return [
836
845
  current()[key],
@@ -856,18 +865,74 @@ function createState(onStateChange) {
856
865
  }
857
866
  }
858
867
 
868
+ var IsolateTypes;
869
+ (function (IsolateTypes) {
870
+ IsolateTypes[IsolateTypes["DEFAULT"] = 0] = "DEFAULT";
871
+ IsolateTypes[IsolateTypes["SUITE"] = 1] = "SUITE";
872
+ IsolateTypes[IsolateTypes["EACH"] = 2] = "EACH";
873
+ IsolateTypes[IsolateTypes["SKIP_WHEN"] = 3] = "SKIP_WHEN";
874
+ IsolateTypes[IsolateTypes["GROUP"] = 4] = "GROUP";
875
+ })(IsolateTypes || (IsolateTypes = {}));
876
+
859
877
  function createStateRef(state, _a) {
860
878
  var suiteId = _a.suiteId;
861
879
  return {
862
880
  optionalFields: state.registerStateKey(function () { return ({}); }),
863
- prevTestObjects: state.registerStateKey(function () { return []; }),
864
- suiteId: state.registerStateKey(function () { return suiteId; }),
881
+ suiteId: state.registerStateKey(suiteId),
865
882
  testCallbacks: state.registerStateKey(function () { return ({
866
883
  fieldCallbacks: {},
867
884
  doneCallbacks: []
868
885
  }); }),
869
- testObjects: state.registerStateKey(function () { return []; }),
870
- testObjectsCursor: state.registerStateKey(function () { return 0; })
886
+ testObjects: state.registerStateKey(function (prev) {
887
+ return {
888
+ prev: (prev ? prev.current : []),
889
+ current: []
890
+ };
891
+ })
892
+ };
893
+ }
894
+
895
+ function asArray(possibleArg) {
896
+ return [].concat(possibleArg);
897
+ }
898
+
899
+ function last(values) {
900
+ var valuesArray = asArray(values);
901
+ var _a = valuesArray, l = _a.length, _b = l - 1, lastValue = _a[_b];
902
+ return lastValue;
903
+ }
904
+
905
+ function createCursor() {
906
+ var storage = {
907
+ cursor: []
908
+ };
909
+ function addLevel() {
910
+ storage.cursor.push(0);
911
+ }
912
+ function removeLevel() {
913
+ storage.cursor.pop();
914
+ }
915
+ function cursorAt() {
916
+ return last(storage.cursor);
917
+ }
918
+ function getCursor() {
919
+ return asArray(storage.cursor);
920
+ }
921
+ function next() {
922
+ storage.cursor[storage.cursor.length - 1]++;
923
+ return last(storage.cursor);
924
+ }
925
+ function reset() {
926
+ storage.cursor = [0];
927
+ }
928
+ reset();
929
+ return {
930
+ addLevel: addLevel,
931
+ cursorAt: cursorAt,
932
+ getCursor: getCursor,
933
+ next: next,
934
+ removeLevel: removeLevel,
935
+ reset: reset
871
936
  };
872
937
  }
873
938
 
@@ -875,6 +940,8 @@ var ctx = createContext(function (ctxRef, parentContext) {
875
940
  return parentContext
876
941
  ? null
877
942
  : assign({}, {
943
+ isolate: { type: IsolateTypes.DEFAULT },
944
+ testCursor: createCursor(),
878
945
  exclusion: {
879
946
  tests: {},
880
947
  groups: {}
@@ -882,18 +949,56 @@ var ctx = createContext(function (ctxRef, parentContext) {
882
949
  }, ctxRef);
883
950
  });
884
951
 
885
- function nonMatchingFieldName(testObject, fieldName) {
886
- return !!fieldName && !matchingFieldName(testObject, fieldName);
952
+ // This is sort of a map/filter in one function.
953
+ // Normally, behaves like a nested-array map
954
+ // Returning `null` will drop the element from the array
955
+ function transform(array, cb) {
956
+ var res = [];
957
+ for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
958
+ var v = array_1[_i];
959
+ if (isArray(v)) {
960
+ res.push(transform(v, cb));
961
+ }
962
+ else {
963
+ var output = cb(v);
964
+ if (isNotNull(output)) {
965
+ res.push(output);
966
+ }
967
+ }
968
+ }
969
+ return res;
887
970
  }
888
- function matchingFieldName(testObject, fieldName) {
889
- return !!(fieldName && testObject.fieldName === fieldName);
971
+ function valueAtPath(array, path) {
972
+ return getCurrent(array, path)[last(path)];
973
+ }
974
+ function setValueAtPath(array, path, value) {
975
+ var current = getCurrent(array, path);
976
+ current[last(path)] = value;
977
+ return array;
978
+ }
979
+ function flatten(values) {
980
+ return asArray(values).reduce(function (acc, value) {
981
+ if (isArray(value)) {
982
+ return acc.concat(flatten(value));
983
+ }
984
+ return asArray(acc).concat(value);
985
+ }, []);
986
+ }
987
+ function getCurrent(array, path) {
988
+ var current = array;
989
+ for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
990
+ var p = _a[_i];
991
+ current[p] = defaultTo(current[p], []);
992
+ current = current[p];
993
+ }
994
+ return current;
890
995
  }
891
996
 
892
997
  /**
893
998
  * Creates a cache function
894
999
  */
895
1000
  function createCache(maxSize) {
896
- if (maxSize === void 0) { maxSize = 10; }
1001
+ if (maxSize === void 0) { maxSize = 1; }
897
1002
  var cacheStorage = [];
898
1003
  var cache = function (deps, cacheAction) {
899
1004
  var cacheHit = cache.get(deps);
@@ -902,9 +1007,8 @@ function createCache(maxSize) {
902
1007
  return cacheHit[1];
903
1008
  var result = cacheAction();
904
1009
  cacheStorage.unshift([deps.concat(), result]);
905
- if (cacheStorage.length > maxSize) {
1010
+ if (longerThan(cacheStorage, maxSize))
906
1011
  cacheStorage.length = maxSize;
907
- }
908
1012
  return result;
909
1013
  };
910
1014
  // invalidate an item in the cache by its dependencies
@@ -928,6 +1032,12 @@ function createCache(maxSize) {
928
1032
  return cache;
929
1033
  }
930
1034
 
1035
+ // STATE REF
1036
+ function useStateRef() {
1037
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1038
+ return ctx.useX().stateRef; // I should revisit this
1039
+ }
1040
+ // STATE KEYS
931
1041
  function useSuiteId() {
932
1042
  return useStateRef().suiteId();
933
1043
  }
@@ -937,58 +1047,133 @@ function useTestCallbacks() {
937
1047
  function useOptionalFields() {
938
1048
  return useStateRef().optionalFields();
939
1049
  }
940
- function useStateRef() {
941
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
942
- return ctx.useX().stateRef; // I should revisit this
943
- }
944
1050
  function useTestObjects() {
945
1051
  return useStateRef().testObjects();
946
1052
  }
947
- function usePrevTestObjects() {
948
- return useStateRef().prevTestObjects();
1053
+ // STATE ACTIONS
1054
+ function useRefreshTestObjects() {
1055
+ var _a = useTestObjects(), setTestObjects = _a[1];
1056
+ setTestObjects(function (_a) {
1057
+ var current = _a.current, prev = _a.prev;
1058
+ return ({
1059
+ prev: prev,
1060
+ current: asArray(current)
1061
+ });
1062
+ });
949
1063
  }
950
- function useTestAtCursor(initialValue) {
951
- var cursorAt = useCursorAt()[0];
952
- var prevTestObjects = usePrevTestObjects()[0];
953
- var nextTest = defaultTo(prevTestObjects[cursorAt], initialValue);
954
- useSetTestAtCursor(nextTest);
955
- return nextTest;
1064
+ function useSetTests(handler) {
1065
+ var _a = useTestObjects(), testObjects = _a[1];
1066
+ testObjects(function (_a) {
1067
+ var current = _a.current, prev = _a.prev;
1068
+ return ({
1069
+ prev: prev,
1070
+ current: asArray(handler(current))
1071
+ });
1072
+ });
956
1073
  }
957
- function useSetTestAtCursor(testObject) {
958
- var cursorAt = useCursorAt()[0];
959
- var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
960
- if (testObject === testObjects[cursorAt]) {
1074
+ // Derived state
1075
+ function useAllIncomplete() {
1076
+ var current = useTestObjects()[0].current;
1077
+ return flatten(transform(current, function (testObject) {
1078
+ return testObject.isPending() ? testObject : null;
1079
+ }));
1080
+ }
1081
+ function useOmittedFields() {
1082
+ var testObjects = useTestsFlat();
1083
+ return testObjects.reduce(function (omittedFields, testObject) {
1084
+ if (omittedFields[testObject.fieldName]) {
1085
+ return omittedFields;
1086
+ }
1087
+ if (testObject.isOmitted()) {
1088
+ omittedFields[testObject.fieldName] = true;
1089
+ }
1090
+ return omittedFields;
1091
+ }, {});
1092
+ }
1093
+ var flatCache = createCache();
1094
+ function useTestsFlat() {
1095
+ var current = useTestObjects()[0].current;
1096
+ return flatCache([current], function () { return flatten(current); });
1097
+ }
1098
+
1099
+ function usePath() {
1100
+ var context = ctx.useX();
1101
+ return context.testCursor.getCursor();
1102
+ }
1103
+ function useCursorAt() {
1104
+ var context = ctx.useX();
1105
+ return context.testCursor.cursorAt();
1106
+ }
1107
+ function moveForward() {
1108
+ var context = ctx.useX();
1109
+ return context.testCursor.next();
1110
+ }
1111
+ function addLevel() {
1112
+ var context = ctx.useX();
1113
+ context.testCursor.addLevel();
1114
+ }
1115
+ function removeLevel() {
1116
+ var context = ctx.useX();
1117
+ context.testCursor.removeLevel();
1118
+ }
1119
+
1120
+ function isolate(_a, callback) {
1121
+ var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
1122
+ if (!isFunction(callback)) {
961
1123
  return;
962
1124
  }
963
- setTestObjects(function (testObjects) {
964
- var newTestsOrder = testObjects.slice(0);
965
- newTestsOrder[cursorAt] = testObject;
966
- return newTestsOrder;
1125
+ var path = usePath();
1126
+ return ctx.run({ isolate: { type: type } }, function () {
1127
+ addLevel();
1128
+ useSetTests(function (tests) { return setValueAtPath(tests, path, []); });
1129
+ var res = callback();
1130
+ removeLevel();
1131
+ moveForward();
1132
+ return res;
967
1133
  });
968
1134
  }
969
- function useSetNextCursorAt() {
970
- var _a = useCursorAt(), setCursorAt = _a[1];
971
- setCursorAt(function (cursorAt) { return cursorAt + 1; });
1135
+ function shouldAllowReorder() {
1136
+ return ctx.useX().isolate.type === IsolateTypes.EACH;
972
1137
  }
973
- function useRefreshTestObjects() {
974
- var _a = useTestObjects(), setTestObjects = _a[1];
975
- setTestObjects(function (testObjects) { return testObjects.slice(0); });
1138
+
1139
+ function nonMatchingFieldName(testObject, fieldName) {
1140
+ return !!fieldName && !matchingFieldName(testObject, fieldName);
976
1141
  }
977
- function useCursorAt() {
978
- return useStateRef().testObjectsCursor();
1142
+ function matchingFieldName(testObject, fieldName) {
1143
+ return !!(fieldName && testObject.fieldName === fieldName);
979
1144
  }
980
- function isOptionalField(fieldName) {
1145
+
1146
+ function omitOptionalTests() {
981
1147
  var optionalFields = useOptionalFields()[0];
982
- return !!optionalFields[fieldName];
983
- }
984
- function useAllIncomplete() {
985
- var testObjects = useTestObjects()[0];
986
- // TODO: CACHE?
987
- return testObjects.filter(function (testObject) { return testObject.isPending(); });
1148
+ if (isEmpty(optionalFields)) {
1149
+ return;
1150
+ }
1151
+ var shouldOmit = {};
1152
+ useSetTests(function (tests) {
1153
+ return transform(tests, function (testObject) {
1154
+ var fieldName = testObject.fieldName;
1155
+ if (shouldOmit.hasOwnProperty(fieldName)) {
1156
+ omit(testObject);
1157
+ }
1158
+ else {
1159
+ var optionalConfig = optionalFields[fieldName];
1160
+ if (isFunction(optionalConfig)) {
1161
+ shouldOmit[fieldName] = optionalConfig();
1162
+ omit(testObject);
1163
+ }
1164
+ }
1165
+ return testObject;
1166
+ });
1167
+ });
1168
+ function omit(testObject) {
1169
+ if (shouldOmit[testObject.fieldName]) {
1170
+ testObject.omit();
1171
+ }
1172
+ }
988
1173
  }
989
1174
 
990
1175
  /**
991
- * Checks if a given tests, or the suite as a whole still have remaining tests.
1176
+ * Checks if a given field, or the suite as a whole still have remaining tests.
992
1177
  */
993
1178
  function hasRemainingTests(fieldName) {
994
1179
  var allIncomplete = useAllIncomplete();
@@ -1007,7 +1192,7 @@ function hasRemainingTests(fieldName) {
1007
1192
  * Reads the testObjects list and gets full validation result from it.
1008
1193
  */
1009
1194
  function genTestsSummary() {
1010
- var testObjects = useTestObjects()[0];
1195
+ var testObjects = useTestsFlat();
1011
1196
  var summary = {
1012
1197
  errorCount: 0,
1013
1198
  groups: {},
@@ -1127,7 +1312,7 @@ function getWarnings(fieldName) {
1127
1312
  * @returns suite or field's errors or warnings.
1128
1313
  */
1129
1314
  function getFailures(severityKey, fieldName) {
1130
- var testObjects = useTestObjects()[0];
1315
+ var testObjects = useTestsFlat();
1131
1316
  var failureMessages = collectFailureMessages(severityKey, testObjects, {
1132
1317
  fieldName: fieldName
1133
1318
  });
@@ -1149,7 +1334,7 @@ function getByGroup(severityKey, group, fieldName) {
1149
1334
  if (!group) {
1150
1335
  throwError("get" + severityKey[0].toUpperCase() + severityKey.slice(1) + "ByGroup requires a group name. Received `" + group + "` instead.");
1151
1336
  }
1152
- var testObjects = useTestObjects()[0];
1337
+ var testObjects = useTestsFlat();
1153
1338
  var failureMessages = collectFailureMessages(severityKey, testObjects, {
1154
1339
  group: group,
1155
1340
  fieldName: fieldName
@@ -1180,7 +1365,7 @@ function hasWarnings(fieldName) {
1180
1365
  return has('warnings', fieldName);
1181
1366
  }
1182
1367
  function has(severityKey, fieldName) {
1183
- var testObjects = useTestObjects()[0];
1368
+ var testObjects = useTestsFlat();
1184
1369
  return testObjects.some(function (testObject) {
1185
1370
  return hasFailuresLogic(testObject, severityKey, fieldName);
1186
1371
  });
@@ -1196,7 +1381,7 @@ function hasWarningsByGroup(groupName, fieldName) {
1196
1381
  * Checks whether there are failures in a given group.
1197
1382
  */
1198
1383
  function hasByGroup(severityKey, group, fieldName) {
1199
- var testObjects = useTestObjects()[0];
1384
+ var testObjects = useTestsFlat();
1200
1385
  return testObjects.some(function (testObject) {
1201
1386
  return group === testObject.groupName
1202
1387
  ? hasFailuresLogic(testObject, severityKey, fieldName)
@@ -1204,46 +1389,61 @@ function hasByGroup(severityKey, group, fieldName) {
1204
1389
  });
1205
1390
  }
1206
1391
 
1392
+ // eslint-disable-next-line max-statements, complexity
1207
1393
  function isValid(result, fieldName) {
1394
+ if (fieldIsOmitted(fieldName)) {
1395
+ return true;
1396
+ }
1208
1397
  if (result.hasErrors(fieldName)) {
1209
1398
  return false;
1210
1399
  }
1211
- var testObjects = useTestObjects()[0];
1400
+ var testObjects = useTestsFlat();
1212
1401
  if (isEmpty(testObjects)) {
1213
1402
  return false;
1214
1403
  }
1215
1404
  if (fieldDoesNotExist(result, fieldName)) {
1216
1405
  return false;
1217
1406
  }
1218
- if (isNotEmpty(useAllIncomplete().filter(function (testObject) {
1219
- if (nonMatchingFieldName(testObject, fieldName)) {
1220
- return false;
1221
- }
1222
- return !isOptionalField(testObject.fieldName);
1223
- }))) {
1407
+ if (hasNonOptionalIncomplete(fieldName)) {
1224
1408
  return false;
1225
1409
  }
1226
1410
  return noMissingTests(fieldName);
1227
1411
  }
1412
+ function fieldIsOmitted(fieldName) {
1413
+ var omittedFields = useOmittedFields();
1414
+ if (!fieldName) {
1415
+ return false;
1416
+ }
1417
+ return !!omittedFields[fieldName];
1418
+ }
1419
+ function hasNonOptionalIncomplete(fieldName) {
1420
+ var optionalFields = useOptionalFields()[0];
1421
+ return isNotEmpty(useAllIncomplete().filter(function (testObject) {
1422
+ if (nonMatchingFieldName(testObject, fieldName)) {
1423
+ return false;
1424
+ }
1425
+ return optionalFields[testObject.fieldName] !== true;
1426
+ }));
1427
+ }
1228
1428
  function fieldDoesNotExist(result, fieldName) {
1229
1429
  return !!fieldName && isEmpty(result.tests[fieldName]);
1230
1430
  }
1231
1431
  function noMissingTests(fieldName) {
1232
- var testObjects = useTestObjects()[0];
1432
+ var testObjects = useTestsFlat();
1433
+ var optionalFields = useOptionalFields()[0];
1233
1434
  return testObjects.every(function (testObject) {
1234
1435
  if (nonMatchingFieldName(testObject, fieldName)) {
1235
1436
  return true;
1236
1437
  }
1237
- if (isOptionalField(testObject.fieldName)) {
1238
- return true;
1239
- }
1240
- return testObject.isTested();
1438
+ return (optionalFields[testObject.fieldName] === true ||
1439
+ testObject.isTested() ||
1440
+ testObject.isOmitted());
1241
1441
  });
1242
1442
  }
1243
1443
 
1244
1444
  var cache$1 = createCache(20);
1245
1445
  function produceDraft() {
1246
- var testObjects = useTestObjects()[0];
1446
+ var testObjects = useTestsFlat();
1247
1447
  var ctxRef = { stateRef: useStateRef() };
1248
1448
  return cache$1([testObjects], ctx.bind(ctxRef, function () {
1249
1449
  return assign(genTestsSummary(), {
@@ -1264,7 +1464,7 @@ function produceDraft() {
1264
1464
 
1265
1465
  var cache = createCache(20);
1266
1466
  function produceFullResult() {
1267
- var testObjects = useTestObjects()[0];
1467
+ var testObjects = useTestsFlat();
1268
1468
  var ctxRef = { stateRef: useStateRef() };
1269
1469
  return cache([testObjects], ctx.bind(ctxRef, function () {
1270
1470
  return assign({}, produceDraft(), {
@@ -1322,6 +1522,15 @@ function deferDoneCallback(doneCallback, fieldName) {
1322
1522
  });
1323
1523
  }
1324
1524
 
1525
+ /**
1526
+ * Removes test object from suite state
1527
+ */
1528
+ function removeTestFromState (testObject) {
1529
+ useSetTests(function (tests) {
1530
+ return transform(tests, function (test) { return (testObject !== test ? test : null); });
1531
+ });
1532
+ }
1533
+
1325
1534
  function createBus() {
1326
1535
  var listeners = {};
1327
1536
  return {
@@ -1357,8 +1566,7 @@ function callEach(arr) {
1357
1566
  function runFieldCallbacks(fieldName) {
1358
1567
  var fieldCallbacks = useTestCallbacks()[0].fieldCallbacks;
1359
1568
  if (fieldName) {
1360
- if (!hasRemainingTests(fieldName) &&
1361
- Array.isArray(fieldCallbacks[fieldName])) {
1569
+ if (!hasRemainingTests(fieldName) && isArray(fieldCallbacks[fieldName])) {
1362
1570
  callEach(fieldCallbacks[fieldName]);
1363
1571
  }
1364
1572
  }
@@ -1410,22 +1618,23 @@ function create(suiteCallback) {
1410
1618
  for (var _i = 0; _i < arguments.length; _i++) {
1411
1619
  args[_i] = arguments[_i];
1412
1620
  }
1413
- var prevTestObjects = useTestObjects()[0];
1414
- var _a = usePrevTestObjects(), setPrevTestObjects = _a[1];
1415
1621
  state.reset();
1416
- setPrevTestObjects(function () { return prevTestObjects; });
1417
1622
  // Run the consumer's callback
1418
- suiteCallback.apply(void 0, args);
1623
+ isolate({ type: IsolateTypes.SUITE }, function () {
1624
+ suiteCallback.apply(void 0, args);
1625
+ });
1626
+ omitOptionalTests();
1419
1627
  var res = produceFullResult();
1420
1628
  return res;
1421
1629
  }), {
1422
1630
  get: ctx.bind({ stateRef: stateRef }, produceDraft),
1423
1631
  remove: ctx.bind({ stateRef: stateRef }, function (name) {
1424
- var testObjects = useTestObjects()[0];
1632
+ var testObjects = useTestsFlat();
1425
1633
  // We're mutating the array in `cancel`, so we have to first copy it.
1426
- asArray(testObjects).forEach(function (testObject) {
1634
+ testObjects.forEach(function (testObject) {
1427
1635
  if (matchingFieldName(testObject, name)) {
1428
1636
  testObject.cancel();
1637
+ removeTestFromState(testObject);
1429
1638
  }
1430
1639
  });
1431
1640
  }),
@@ -1539,6 +1748,12 @@ function hasIncludedTests(keyTests) {
1539
1748
  return false;
1540
1749
  }
1541
1750
 
1751
+ function skipWhen(conditional, callback) {
1752
+ isolate({ type: IsolateTypes.SKIP_WHEN }, function () {
1753
+ ctx.run({ skipped: optionalFunctionValue(conditional) }, function () { return callback(); });
1754
+ });
1755
+ }
1756
+
1542
1757
  var ERROR_OUTSIDE_OF_TEST = "warn hook called outside of a test callback. It won't have an effect."
1543
1758
  ;
1544
1759
  /**
@@ -1552,10 +1767,6 @@ function warn() {
1552
1767
  ctx$1.currentTest.warn();
1553
1768
  }
1554
1769
 
1555
- function skipWhen(conditional, callback) {
1556
- ctx.run({ skipped: optionalFunctionValue(conditional) }, function () { return callback(); });
1557
- }
1558
-
1559
1770
  /**
1560
1771
  * Runs a group callback.
1561
1772
  */
@@ -1567,7 +1778,9 @@ function group(groupName, tests) {
1567
1778
  throwGroupError('callback must be a function');
1568
1779
  }
1569
1780
  // Running with the context applied
1570
- ctx.run({ groupName: groupName }, tests);
1781
+ isolate({ type: IsolateTypes.GROUP }, function () {
1782
+ ctx.run({ groupName: groupName }, tests);
1783
+ });
1571
1784
  }
1572
1785
  function throwGroupError(error) {
1573
1786
  throwError("Wrong arguments passed to group. Group " + error + ".");
@@ -1576,36 +1789,22 @@ function throwGroupError(error) {
1576
1789
  function optional(optionals) {
1577
1790
  var _a = useOptionalFields(), setOptionalFields = _a[1];
1578
1791
  setOptionalFields(function (state) {
1579
- asArray(optionals).forEach(function (optionalField) {
1580
- state[optionalField] = true;
1581
- });
1792
+ if (!isArray(optionals) && !isStringValue(optionals)) {
1793
+ var optionalFunctions = optionals;
1794
+ for (var field in optionalFunctions) {
1795
+ var predicate = optionalFunctions[field];
1796
+ state[field] = predicate;
1797
+ }
1798
+ }
1799
+ else {
1800
+ asArray(optionals).forEach(function (optionalField) {
1801
+ state[optionalField] = true;
1802
+ });
1803
+ }
1582
1804
  return state;
1583
1805
  });
1584
1806
  }
1585
1807
 
1586
- /**
1587
- * Removes first found element from array
1588
- * WARNING: Mutates array
1589
- */
1590
- function removeElementFromArray(array, element) {
1591
- var index = array.indexOf(element);
1592
- if (index !== -1) {
1593
- array.splice(index, 1);
1594
- }
1595
- return array;
1596
- }
1597
-
1598
- /**
1599
- * Removes test object from suite state
1600
- */
1601
- function removeTestFromState (testObject) {
1602
- var _a = useTestObjects(), setTestObjects = _a[1];
1603
- setTestObjects(function (testObjects) {
1604
- // using asArray to clear the cache.
1605
- return asArray(removeElementFromArray(testObjects, testObject));
1606
- });
1607
- }
1608
-
1609
1808
  function shouldUseErrorAsMessage(message, error) {
1610
1809
  // kind of cheating with this safe guard, but it does the job
1611
1810
  return isUndefined(message) && isStringValue(error);
@@ -1643,7 +1842,7 @@ var VestTest = /** @class */ (function () {
1643
1842
  return result;
1644
1843
  };
1645
1844
  VestTest.prototype.setStatus = function (status) {
1646
- if (this.isCanceled()) {
1845
+ if (this.isFinalStatus() && status !== STATUS_OMITTED) {
1647
1846
  return;
1648
1847
  }
1649
1848
  this.status = status;
@@ -1655,7 +1854,7 @@ var VestTest = /** @class */ (function () {
1655
1854
  this.setStatus(this.warns ? STATUS_WARNING : STATUS_FAILED);
1656
1855
  };
1657
1856
  VestTest.prototype.done = function () {
1658
- if (this.isWarning() || this.isCanceled() || this.isFailing()) {
1857
+ if (this.isFinalStatus()) {
1659
1858
  return;
1660
1859
  }
1661
1860
  this.setStatus(STATUS_PASSING);
@@ -1663,12 +1862,18 @@ var VestTest = /** @class */ (function () {
1663
1862
  VestTest.prototype.warn = function () {
1664
1863
  this.warns = true;
1665
1864
  };
1865
+ VestTest.prototype.isFinalStatus = function () {
1866
+ return this.hasFailures() || this.isCanceled() || this.isPassing();
1867
+ };
1666
1868
  VestTest.prototype.skip = function () {
1667
1869
  this.setStatus(STATUS_SKIPPED);
1668
1870
  };
1669
1871
  VestTest.prototype.cancel = function () {
1670
1872
  this.setStatus(STATUS_CANCELED);
1671
- removeTestFromState(this);
1873
+ useRefreshTestObjects();
1874
+ };
1875
+ VestTest.prototype.omit = function () {
1876
+ this.setStatus(STATUS_OMITTED);
1672
1877
  };
1673
1878
  VestTest.prototype.valueOf = function () {
1674
1879
  return !this.isFailing();
@@ -1682,6 +1887,9 @@ var VestTest = /** @class */ (function () {
1682
1887
  VestTest.prototype.isTested = function () {
1683
1888
  return this.hasFailures() || this.isPassing();
1684
1889
  };
1890
+ VestTest.prototype.isOmitted = function () {
1891
+ return this.status === STATUS_OMITTED;
1892
+ };
1685
1893
  VestTest.prototype.isUntested = function () {
1686
1894
  return this.status === STATUS_UNTESTED;
1687
1895
  };
@@ -1709,6 +1917,7 @@ var STATUS_WARNING = 'WARNING';
1709
1917
  var STATUS_PASSING = 'PASSING';
1710
1918
  var STATUS_PENDING = 'PENDING';
1711
1919
  var STATUS_CANCELED = 'CANCELED';
1920
+ var STATUS_OMITTED = 'OMITTED';
1712
1921
 
1713
1922
  function isPromise(value) {
1714
1923
  return value && isFunction(value.then);
@@ -1737,6 +1946,8 @@ function runAsyncTest(testObject) {
1737
1946
  var emit = useBus().emit;
1738
1947
  var stateRef = useStateRef();
1739
1948
  var done = ctx.bind({ stateRef: stateRef }, function () {
1949
+ // invalidating the "produce" cache
1950
+ useRefreshTestObjects();
1740
1951
  emit(Events.TEST_COMPLETED, testObject);
1741
1952
  });
1742
1953
  var fail = ctx.bind({ stateRef: stateRef }, function (rejectionMessage) {
@@ -1747,8 +1958,6 @@ function runAsyncTest(testObject) {
1747
1958
  ? rejectionMessage
1748
1959
  : message;
1749
1960
  testObject.fail();
1750
- // invalidating the "produce" cache
1751
- useRefreshTestObjects();
1752
1961
  done();
1753
1962
  });
1754
1963
  try {
@@ -1802,21 +2011,86 @@ function registerTest(testObject) {
1802
2011
  emit(Events.TEST_COMPLETED, testObject);
1803
2012
  }
1804
2013
  }
1805
- catch (_a) {
2014
+ catch (e) {
1806
2015
  throwError("Your test function " + testObject.fieldName + " returned " + JSON.stringify(result) + ". Only \"false\" or a Promise are supported. Return values may cause unexpected behavior.");
1807
2016
  }
1808
2017
  }
1809
2018
 
2019
+ /**
2020
+ * This module serves as the "collision detection" mechanism for Vest.
2021
+ * It is used to ensure that tests are not called in a different order than
2022
+ * they were called in the previous run.
2023
+ * If they are, it will throw a deferred error unless explicitly allowed.
2024
+ *
2025
+ * For now it seems pretty safe, and it covers most common use cases, but it can
2026
+ * be improved in the future both in terms of performance and scenarios it covers.
2027
+ */
2028
+ // eslint-disable-next-line max-statements, max-lines-per-function
2029
+ function useTestAtCursor(newTestObject) {
2030
+ var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
2031
+ var prevTests = testObjects.prev;
2032
+ if (isEmpty(prevTests)) {
2033
+ useSetTestAtCursor(newTestObject);
2034
+ return newTestObject;
2035
+ }
2036
+ var prevTest = useGetTestAtCursor(prevTests);
2037
+ if (shouldPurgePrevTest(prevTest, newTestObject)) {
2038
+ throwTestOrderError(prevTest, newTestObject);
2039
+ // Here we handle just the omission of tests in the middle of the test suite.
2040
+ // We need to also handle a case in which tests are added in between other tests.
2041
+ // At the moment all we can do is just splice the tests out of the array when this happens.
2042
+ // A viable solution would be to use something like React's key prop to identify tests regardless
2043
+ // of their position in the suite. https://reactjs.org/docs/lists-and-keys.html#keys
2044
+ var current = getCurrent(prevTests, usePath());
2045
+ var cursorAt = useCursorAt();
2046
+ current.splice(cursorAt);
2047
+ // We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
2048
+ // since we're only touching the "prev" state. The reason we still use the setter function is
2049
+ // to prevent future headaches if we ever do need to rely on prev-state immutability.
2050
+ setTestObjects(function (_a) {
2051
+ var current = _a.current;
2052
+ return ({
2053
+ prev: prevTests,
2054
+ current: current
2055
+ });
2056
+ });
2057
+ // Need to see if this has any effect at all.
2058
+ prevTest = null;
2059
+ }
2060
+ var nextTest = defaultTo(prevTest, newTestObject);
2061
+ useSetTestAtCursor(nextTest);
2062
+ return nextTest;
2063
+ }
2064
+ function useSetTestAtCursor(testObject) {
2065
+ var cursorPath = usePath();
2066
+ useSetTests(function (tests) {
2067
+ return setValueAtPath(tests, cursorPath, testObject);
2068
+ });
2069
+ }
2070
+ function useGetTestAtCursor(tests) {
2071
+ var cursorPath = usePath();
2072
+ return valueAtPath(tests, cursorPath);
2073
+ }
2074
+ function shouldPurgePrevTest(prevTest, newTest) {
2075
+ return isNotEmpty(prevTest) && !isSameProfileTest(prevTest, newTest);
2076
+ }
2077
+ function throwTestOrderError(prevTest, newTestObject) {
2078
+ if (shouldAllowReorder()) {
2079
+ return;
2080
+ }
2081
+ 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.");
2082
+ }
2083
+
1810
2084
  function registerPrevRunTest(testObject) {
1811
2085
  var prevRunTest = useTestAtCursor(testObject);
1812
2086
  if (isExcluded(testObject)) {
1813
2087
  testObject.skip();
1814
- useSetNextCursorAt();
2088
+ moveForward();
1815
2089
  return prevRunTest;
1816
2090
  }
1817
2091
  cancelOverriddenPendingTest(prevRunTest, testObject);
1818
2092
  useSetTestAtCursor(testObject);
1819
- useSetNextCursorAt();
2093
+ moveForward();
1820
2094
  registerTestObjectByTier(testObject);
1821
2095
  return testObject;
1822
2096
  }
@@ -1835,7 +2109,7 @@ function bindTestEach(test) {
1835
2109
  * Run multiple tests using a parameter table
1836
2110
  */
1837
2111
  function each(table) {
1838
- if (!Array.isArray(table)) {
2112
+ if (!isArray(table)) {
1839
2113
  throwError('test.each: Expected table to be an array.');
1840
2114
  }
1841
2115
  function eachReturn(fieldName) {
@@ -1844,9 +2118,12 @@ function bindTestEach(test) {
1844
2118
  args[_i - 1] = arguments[_i];
1845
2119
  }
1846
2120
  var _a = args.reverse(), testFn = _a[0], message = _a[1];
1847
- return table.map(function (item) {
1848
- item = asArray(item);
1849
- return test(optionalFunctionValue.apply(void 0, __spreadArray([fieldName], item, false)), optionalFunctionValue.apply(void 0, __spreadArray([message], item, false)), function () { return testFn.apply(void 0, item); });
2121
+ return isolate({ type: IsolateTypes.EACH }, function () {
2122
+ return table.map(function (item) {
2123
+ item = asArray(item);
2124
+ 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
2125
+ );
2126
+ });
1850
2127
  });
1851
2128
  }
1852
2129
  return eachReturn;
@@ -1864,7 +2141,7 @@ function bindTestMemo(test) {
1864
2141
  args[_i - 1] = arguments[_i];
1865
2142
  }
1866
2143
  var suiteId = useSuiteId()[0];
1867
- var cursorAt = useCursorAt()[0];
2144
+ var cursorAt = useCursorAt();
1868
2145
  var _a = args.reverse(), deps = _a[0], testFn = _a[1], msg = _a[2];
1869
2146
  // Implicit dependency for more specificity
1870
2147
  var dependencies = [suiteId, fieldName, cursorAt].concat(deps);
@@ -1901,7 +2178,7 @@ var test = assign(testBase, {
1901
2178
  memo: bindTestMemo(testBase)
1902
2179
  });
1903
2180
 
1904
- var VERSION = "4.0.0-dev-deabb8";
2181
+ var VERSION = "4.0.0-dev-8851ff";
1905
2182
 
1906
2183
  exports.VERSION = VERSION;
1907
2184
  exports.create = create;