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.
@@ -224,8 +224,16 @@ function greaterThanOrEquals(value, gte) {
224
224
  return isNumeric(value) && isNumeric(gte) && Number(value) >= Number(gte);
225
225
  }
226
226
 
227
+ // The module is named "isArrayValue" since it
228
+ // is conflicting with a nested npm dependency.
229
+ // We may need to revisit this in the future.
230
+ function isArray(value) {
231
+ return Boolean(Array.isArray(value));
232
+ }
233
+ var isNotArray = bindNot(isArray);
234
+
227
235
  function inside(value, arg1) {
228
- if (Array.isArray(arg1)) {
236
+ if (isArray(arg1)) {
229
237
  return arg1.indexOf(value) !== -1;
230
238
  }
231
239
  // both value and arg1 are strings
@@ -236,14 +244,6 @@ function inside(value, arg1) {
236
244
  }
237
245
  var notInside = bindNot(inside);
238
246
 
239
- // The module is named "isArrayValue" since it
240
- // is conflicting with a nested npm dependency.
241
- // We may need to revisit this in the future.
242
- function isArray(value) {
243
- return Boolean(Array.isArray(value));
244
- }
245
- var isNotArray = bindNot(isArray);
246
-
247
247
  function lessThanOrEquals(value, lte) {
248
248
  return isNumeric(value) && isNumeric(lte) && Number(value) <= Number(lte);
249
249
  }
@@ -253,6 +253,11 @@ function isBetween(value, min, max) {
253
253
  }
254
254
  var isNotBetween = bindNot(isBetween);
255
255
 
256
+ function isBlank(value) {
257
+ return isStringValue(value) && !value.trim();
258
+ }
259
+ var isNotBlank = bindNot(isBlank);
260
+
256
261
  function isBoolean(value) {
257
262
  return !!value === value;
258
263
  }
@@ -391,6 +396,7 @@ function rules() {
391
396
  inside: inside,
392
397
  isArray: isArray,
393
398
  isBetween: isBetween,
399
+ isBlank: isBlank,
394
400
  isBoolean: isBoolean,
395
401
  isEmpty: isEmpty,
396
402
  isEven: isEven,
@@ -399,6 +405,7 @@ function rules() {
399
405
  isNegative: isNegative,
400
406
  isNotArray: isNotArray,
401
407
  isNotBetween: isNotBetween,
408
+ isNotBlank: isNotBlank,
402
409
  isNotBoolean: isNotBoolean,
403
410
  isNotEmpty: isNotEmpty,
404
411
  isNotNaN: isNotNaN,
@@ -441,6 +448,11 @@ function rules() {
441
448
  function throwError(devMessage, productionMessage) {
442
449
  throw new Error(devMessage );
443
450
  }
451
+ function throwErrorDeferred(devMessage, productionMessage) {
452
+ setTimeout(function () {
453
+ throwError(devMessage);
454
+ }, 0);
455
+ }
444
456
 
445
457
  // eslint-disable-next-line max-lines-per-function
446
458
  function createContext(init) {
@@ -605,7 +617,7 @@ function transformResult(result, ruleName, value) {
605
617
  return ruleReturn(result);
606
618
  }
607
619
  else {
608
- return ruleReturn(result.pass, optionalFunctionValue.apply(void 0, __spreadArray([result.message, ruleName, value], args, false)));
620
+ return ruleReturn(result.pass, optionalFunctionValue.apply(void 0, __spreadArray([result.message, ruleName, value], args)));
609
621
  }
610
622
  }
611
623
  function validateResult(result) {
@@ -639,9 +651,9 @@ function enforceEager(value) {
639
651
  for (var _i = 0; _i < arguments.length; _i++) {
640
652
  args[_i] = arguments[_i];
641
653
  }
642
- var transformedResult = transformResult.apply(void 0, __spreadArray([ctx$1.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args, false)); }),
654
+ var transformedResult = transformResult.apply(void 0, __spreadArray([ctx$1.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args)); }),
643
655
  ruleName,
644
- value], args, false));
656
+ value], args));
645
657
  if (!transformedResult.pass) {
646
658
  if (isEmpty(transformedResult.message)) {
647
659
  throwError("enforce/" + ruleName + " failed with " + JSON.stringify(value));
@@ -671,7 +683,7 @@ function genEnforceLazy(key) {
671
683
  }
672
684
  var rule = getRule(ruleName);
673
685
  registeredRules.push(function (value) {
674
- return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args, false)), ruleName, value], args, false));
686
+ return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args)), ruleName, value], args));
675
687
  });
676
688
  var proxy = {
677
689
  run: function (value) {
@@ -778,10 +790,6 @@ function genEnforce() {
778
790
  }
779
791
  var enforce = genEnforce();
780
792
 
781
- function asArray(possibleArg) {
782
- return [].concat(possibleArg);
783
- }
784
-
785
793
  /**
786
794
  * @returns a unique numeric id.
787
795
  */
@@ -818,15 +826,16 @@ function createState(onStateChange) {
818
826
  return initKey(key, initialState);
819
827
  }
820
828
  function reset() {
829
+ var prev = current();
821
830
  state.references = [];
822
831
  registrations.forEach(function (_a, index) {
823
832
  var initialValue = _a[0];
824
- return initKey(index, initialValue);
833
+ return initKey(index, initialValue, prev[index]);
825
834
  });
826
835
  }
827
- function initKey(key, initialState) {
836
+ function initKey(key, initialState, prevState) {
828
837
  current().push();
829
- set(key, optionalFunctionValue(initialState));
838
+ set(key, optionalFunctionValue(initialState, prevState));
830
839
  return function useStateKey() {
831
840
  return [
832
841
  current()[key],
@@ -852,18 +861,74 @@ function createState(onStateChange) {
852
861
  }
853
862
  }
854
863
 
864
+ var IsolateTypes;
865
+ (function (IsolateTypes) {
866
+ IsolateTypes[IsolateTypes["DEFAULT"] = 0] = "DEFAULT";
867
+ IsolateTypes[IsolateTypes["SUITE"] = 1] = "SUITE";
868
+ IsolateTypes[IsolateTypes["EACH"] = 2] = "EACH";
869
+ IsolateTypes[IsolateTypes["SKIP_WHEN"] = 3] = "SKIP_WHEN";
870
+ IsolateTypes[IsolateTypes["GROUP"] = 4] = "GROUP";
871
+ })(IsolateTypes || (IsolateTypes = {}));
872
+
855
873
  function createStateRef(state, _a) {
856
874
  var suiteId = _a.suiteId;
857
875
  return {
858
876
  optionalFields: state.registerStateKey(function () { return ({}); }),
859
- prevTestObjects: state.registerStateKey(function () { return []; }),
860
- suiteId: state.registerStateKey(function () { return suiteId; }),
877
+ suiteId: state.registerStateKey(suiteId),
861
878
  testCallbacks: state.registerStateKey(function () { return ({
862
879
  fieldCallbacks: {},
863
880
  doneCallbacks: []
864
881
  }); }),
865
- testObjects: state.registerStateKey(function () { return []; }),
866
- testObjectsCursor: state.registerStateKey(function () { return 0; })
882
+ testObjects: state.registerStateKey(function (prev) {
883
+ return {
884
+ prev: (prev ? prev.current : []),
885
+ current: []
886
+ };
887
+ })
888
+ };
889
+ }
890
+
891
+ function asArray(possibleArg) {
892
+ return [].concat(possibleArg);
893
+ }
894
+
895
+ function last(values) {
896
+ var valuesArray = asArray(values);
897
+ var _a = valuesArray, l = _a.length, _b = l - 1, lastValue = _a[_b];
898
+ return lastValue;
899
+ }
900
+
901
+ function createCursor() {
902
+ var storage = {
903
+ cursor: []
904
+ };
905
+ function addLevel() {
906
+ storage.cursor.push(0);
907
+ }
908
+ function removeLevel() {
909
+ storage.cursor.pop();
910
+ }
911
+ function cursorAt() {
912
+ return last(storage.cursor);
913
+ }
914
+ function getCursor() {
915
+ return asArray(storage.cursor);
916
+ }
917
+ function next() {
918
+ storage.cursor[storage.cursor.length - 1]++;
919
+ return last(storage.cursor);
920
+ }
921
+ function reset() {
922
+ storage.cursor = [0];
923
+ }
924
+ reset();
925
+ return {
926
+ addLevel: addLevel,
927
+ cursorAt: cursorAt,
928
+ getCursor: getCursor,
929
+ next: next,
930
+ removeLevel: removeLevel,
931
+ reset: reset
867
932
  };
868
933
  }
869
934
 
@@ -871,6 +936,8 @@ var ctx = createContext(function (ctxRef, parentContext) {
871
936
  return parentContext
872
937
  ? null
873
938
  : assign({}, {
939
+ isolate: { type: IsolateTypes.DEFAULT },
940
+ testCursor: createCursor(),
874
941
  exclusion: {
875
942
  tests: {},
876
943
  groups: {}
@@ -878,18 +945,56 @@ var ctx = createContext(function (ctxRef, parentContext) {
878
945
  }, ctxRef);
879
946
  });
880
947
 
881
- function nonMatchingFieldName(testObject, fieldName) {
882
- return !!fieldName && !matchingFieldName(testObject, fieldName);
948
+ // This is sort of a map/filter in one function.
949
+ // Normally, behaves like a nested-array map
950
+ // Returning `null` will drop the element from the array
951
+ function transform(array, cb) {
952
+ var res = [];
953
+ for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
954
+ var v = array_1[_i];
955
+ if (isArray(v)) {
956
+ res.push(transform(v, cb));
957
+ }
958
+ else {
959
+ var output = cb(v);
960
+ if (isNotNull(output)) {
961
+ res.push(output);
962
+ }
963
+ }
964
+ }
965
+ return res;
883
966
  }
884
- function matchingFieldName(testObject, fieldName) {
885
- return !!(fieldName && testObject.fieldName === fieldName);
967
+ function valueAtPath(array, path) {
968
+ return getCurrent(array, path)[last(path)];
969
+ }
970
+ function setValueAtPath(array, path, value) {
971
+ var current = getCurrent(array, path);
972
+ current[last(path)] = value;
973
+ return array;
974
+ }
975
+ function flatten(values) {
976
+ return asArray(values).reduce(function (acc, value) {
977
+ if (isArray(value)) {
978
+ return acc.concat(flatten(value));
979
+ }
980
+ return asArray(acc).concat(value);
981
+ }, []);
982
+ }
983
+ function getCurrent(array, path) {
984
+ var current = array;
985
+ for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
986
+ var p = _a[_i];
987
+ current[p] = defaultTo(current[p], []);
988
+ current = current[p];
989
+ }
990
+ return current;
886
991
  }
887
992
 
888
993
  /**
889
994
  * Creates a cache function
890
995
  */
891
996
  function createCache(maxSize) {
892
- if (maxSize === void 0) { maxSize = 10; }
997
+ if (maxSize === void 0) { maxSize = 1; }
893
998
  var cacheStorage = [];
894
999
  var cache = function (deps, cacheAction) {
895
1000
  var cacheHit = cache.get(deps);
@@ -898,9 +1003,8 @@ function createCache(maxSize) {
898
1003
  return cacheHit[1];
899
1004
  var result = cacheAction();
900
1005
  cacheStorage.unshift([deps.concat(), result]);
901
- if (cacheStorage.length > maxSize) {
1006
+ if (longerThan(cacheStorage, maxSize))
902
1007
  cacheStorage.length = maxSize;
903
- }
904
1008
  return result;
905
1009
  };
906
1010
  // invalidate an item in the cache by its dependencies
@@ -924,6 +1028,12 @@ function createCache(maxSize) {
924
1028
  return cache;
925
1029
  }
926
1030
 
1031
+ // STATE REF
1032
+ function useStateRef() {
1033
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1034
+ return ctx.useX().stateRef; // I should revisit this
1035
+ }
1036
+ // STATE KEYS
927
1037
  function useSuiteId() {
928
1038
  return useStateRef().suiteId();
929
1039
  }
@@ -933,58 +1043,133 @@ function useTestCallbacks() {
933
1043
  function useOptionalFields() {
934
1044
  return useStateRef().optionalFields();
935
1045
  }
936
- function useStateRef() {
937
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
938
- return ctx.useX().stateRef; // I should revisit this
939
- }
940
1046
  function useTestObjects() {
941
1047
  return useStateRef().testObjects();
942
1048
  }
943
- function usePrevTestObjects() {
944
- return useStateRef().prevTestObjects();
1049
+ // STATE ACTIONS
1050
+ function useRefreshTestObjects() {
1051
+ var _a = useTestObjects(), setTestObjects = _a[1];
1052
+ setTestObjects(function (_a) {
1053
+ var current = _a.current, prev = _a.prev;
1054
+ return ({
1055
+ prev: prev,
1056
+ current: asArray(current)
1057
+ });
1058
+ });
945
1059
  }
946
- function useTestAtCursor(initialValue) {
947
- var cursorAt = useCursorAt()[0];
948
- var prevTestObjects = usePrevTestObjects()[0];
949
- var nextTest = defaultTo(prevTestObjects[cursorAt], initialValue);
950
- useSetTestAtCursor(nextTest);
951
- return nextTest;
1060
+ function useSetTests(handler) {
1061
+ var _a = useTestObjects(), testObjects = _a[1];
1062
+ testObjects(function (_a) {
1063
+ var current = _a.current, prev = _a.prev;
1064
+ return ({
1065
+ prev: prev,
1066
+ current: asArray(handler(current))
1067
+ });
1068
+ });
952
1069
  }
953
- function useSetTestAtCursor(testObject) {
954
- var cursorAt = useCursorAt()[0];
955
- var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
956
- if (testObject === testObjects[cursorAt]) {
1070
+ // Derived state
1071
+ function useAllIncomplete() {
1072
+ var current = useTestObjects()[0].current;
1073
+ return flatten(transform(current, function (testObject) {
1074
+ return testObject.isPending() ? testObject : null;
1075
+ }));
1076
+ }
1077
+ function useOmittedFields() {
1078
+ var testObjects = useTestsFlat();
1079
+ return testObjects.reduce(function (omittedFields, testObject) {
1080
+ if (omittedFields[testObject.fieldName]) {
1081
+ return omittedFields;
1082
+ }
1083
+ if (testObject.isOmitted()) {
1084
+ omittedFields[testObject.fieldName] = true;
1085
+ }
1086
+ return omittedFields;
1087
+ }, {});
1088
+ }
1089
+ var flatCache = createCache();
1090
+ function useTestsFlat() {
1091
+ var current = useTestObjects()[0].current;
1092
+ return flatCache([current], function () { return flatten(current); });
1093
+ }
1094
+
1095
+ function usePath() {
1096
+ var context = ctx.useX();
1097
+ return context.testCursor.getCursor();
1098
+ }
1099
+ function useCursorAt() {
1100
+ var context = ctx.useX();
1101
+ return context.testCursor.cursorAt();
1102
+ }
1103
+ function moveForward() {
1104
+ var context = ctx.useX();
1105
+ return context.testCursor.next();
1106
+ }
1107
+ function addLevel() {
1108
+ var context = ctx.useX();
1109
+ context.testCursor.addLevel();
1110
+ }
1111
+ function removeLevel() {
1112
+ var context = ctx.useX();
1113
+ context.testCursor.removeLevel();
1114
+ }
1115
+
1116
+ function isolate(_a, callback) {
1117
+ var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
1118
+ if (!isFunction(callback)) {
957
1119
  return;
958
1120
  }
959
- setTestObjects(function (testObjects) {
960
- var newTestsOrder = testObjects.slice(0);
961
- newTestsOrder[cursorAt] = testObject;
962
- return newTestsOrder;
1121
+ var path = usePath();
1122
+ return ctx.run({ isolate: { type: type } }, function () {
1123
+ addLevel();
1124
+ useSetTests(function (tests) { return setValueAtPath(tests, path, []); });
1125
+ var res = callback();
1126
+ removeLevel();
1127
+ moveForward();
1128
+ return res;
963
1129
  });
964
1130
  }
965
- function useSetNextCursorAt() {
966
- var _a = useCursorAt(), setCursorAt = _a[1];
967
- setCursorAt(function (cursorAt) { return cursorAt + 1; });
1131
+ function shouldAllowReorder() {
1132
+ return ctx.useX().isolate.type === IsolateTypes.EACH;
968
1133
  }
969
- function useRefreshTestObjects() {
970
- var _a = useTestObjects(), setTestObjects = _a[1];
971
- setTestObjects(function (testObjects) { return testObjects.slice(0); });
1134
+
1135
+ function nonMatchingFieldName(testObject, fieldName) {
1136
+ return !!fieldName && !matchingFieldName(testObject, fieldName);
972
1137
  }
973
- function useCursorAt() {
974
- return useStateRef().testObjectsCursor();
1138
+ function matchingFieldName(testObject, fieldName) {
1139
+ return !!(fieldName && testObject.fieldName === fieldName);
975
1140
  }
976
- function isOptionalField(fieldName) {
1141
+
1142
+ function omitOptionalTests() {
977
1143
  var optionalFields = useOptionalFields()[0];
978
- return !!optionalFields[fieldName];
979
- }
980
- function useAllIncomplete() {
981
- var testObjects = useTestObjects()[0];
982
- // TODO: CACHE?
983
- return testObjects.filter(function (testObject) { return testObject.isPending(); });
1144
+ if (isEmpty(optionalFields)) {
1145
+ return;
1146
+ }
1147
+ var shouldOmit = {};
1148
+ useSetTests(function (tests) {
1149
+ return transform(tests, function (testObject) {
1150
+ var fieldName = testObject.fieldName;
1151
+ if (shouldOmit.hasOwnProperty(fieldName)) {
1152
+ omit(testObject);
1153
+ }
1154
+ else {
1155
+ var optionalConfig = optionalFields[fieldName];
1156
+ if (isFunction(optionalConfig)) {
1157
+ shouldOmit[fieldName] = optionalConfig();
1158
+ omit(testObject);
1159
+ }
1160
+ }
1161
+ return testObject;
1162
+ });
1163
+ });
1164
+ function omit(testObject) {
1165
+ if (shouldOmit[testObject.fieldName]) {
1166
+ testObject.omit();
1167
+ }
1168
+ }
984
1169
  }
985
1170
 
986
1171
  /**
987
- * Checks if a given tests, or the suite as a whole still have remaining tests.
1172
+ * Checks if a given field, or the suite as a whole still have remaining tests.
988
1173
  */
989
1174
  function hasRemainingTests(fieldName) {
990
1175
  var allIncomplete = useAllIncomplete();
@@ -1003,7 +1188,7 @@ function hasRemainingTests(fieldName) {
1003
1188
  * Reads the testObjects list and gets full validation result from it.
1004
1189
  */
1005
1190
  function genTestsSummary() {
1006
- var testObjects = useTestObjects()[0];
1191
+ var testObjects = useTestsFlat();
1007
1192
  var summary = {
1008
1193
  errorCount: 0,
1009
1194
  groups: {},
@@ -1123,7 +1308,7 @@ function getWarnings(fieldName) {
1123
1308
  * @returns suite or field's errors or warnings.
1124
1309
  */
1125
1310
  function getFailures(severityKey, fieldName) {
1126
- var testObjects = useTestObjects()[0];
1311
+ var testObjects = useTestsFlat();
1127
1312
  var failureMessages = collectFailureMessages(severityKey, testObjects, {
1128
1313
  fieldName: fieldName
1129
1314
  });
@@ -1145,7 +1330,7 @@ function getByGroup(severityKey, group, fieldName) {
1145
1330
  if (!group) {
1146
1331
  throwError("get" + severityKey[0].toUpperCase() + severityKey.slice(1) + "ByGroup requires a group name. Received `" + group + "` instead.");
1147
1332
  }
1148
- var testObjects = useTestObjects()[0];
1333
+ var testObjects = useTestsFlat();
1149
1334
  var failureMessages = collectFailureMessages(severityKey, testObjects, {
1150
1335
  group: group,
1151
1336
  fieldName: fieldName
@@ -1176,7 +1361,7 @@ function hasWarnings(fieldName) {
1176
1361
  return has('warnings', fieldName);
1177
1362
  }
1178
1363
  function has(severityKey, fieldName) {
1179
- var testObjects = useTestObjects()[0];
1364
+ var testObjects = useTestsFlat();
1180
1365
  return testObjects.some(function (testObject) {
1181
1366
  return hasFailuresLogic(testObject, severityKey, fieldName);
1182
1367
  });
@@ -1192,7 +1377,7 @@ function hasWarningsByGroup(groupName, fieldName) {
1192
1377
  * Checks whether there are failures in a given group.
1193
1378
  */
1194
1379
  function hasByGroup(severityKey, group, fieldName) {
1195
- var testObjects = useTestObjects()[0];
1380
+ var testObjects = useTestsFlat();
1196
1381
  return testObjects.some(function (testObject) {
1197
1382
  return group === testObject.groupName
1198
1383
  ? hasFailuresLogic(testObject, severityKey, fieldName)
@@ -1200,46 +1385,61 @@ function hasByGroup(severityKey, group, fieldName) {
1200
1385
  });
1201
1386
  }
1202
1387
 
1388
+ // eslint-disable-next-line max-statements, complexity
1203
1389
  function isValid(result, fieldName) {
1390
+ if (fieldIsOmitted(fieldName)) {
1391
+ return true;
1392
+ }
1204
1393
  if (result.hasErrors(fieldName)) {
1205
1394
  return false;
1206
1395
  }
1207
- var testObjects = useTestObjects()[0];
1396
+ var testObjects = useTestsFlat();
1208
1397
  if (isEmpty(testObjects)) {
1209
1398
  return false;
1210
1399
  }
1211
1400
  if (fieldDoesNotExist(result, fieldName)) {
1212
1401
  return false;
1213
1402
  }
1214
- if (isNotEmpty(useAllIncomplete().filter(function (testObject) {
1215
- if (nonMatchingFieldName(testObject, fieldName)) {
1216
- return false;
1217
- }
1218
- return !isOptionalField(testObject.fieldName);
1219
- }))) {
1403
+ if (hasNonOptionalIncomplete(fieldName)) {
1220
1404
  return false;
1221
1405
  }
1222
1406
  return noMissingTests(fieldName);
1223
1407
  }
1408
+ function fieldIsOmitted(fieldName) {
1409
+ var omittedFields = useOmittedFields();
1410
+ if (!fieldName) {
1411
+ return false;
1412
+ }
1413
+ return !!omittedFields[fieldName];
1414
+ }
1415
+ function hasNonOptionalIncomplete(fieldName) {
1416
+ var optionalFields = useOptionalFields()[0];
1417
+ return isNotEmpty(useAllIncomplete().filter(function (testObject) {
1418
+ if (nonMatchingFieldName(testObject, fieldName)) {
1419
+ return false;
1420
+ }
1421
+ return optionalFields[testObject.fieldName] !== true;
1422
+ }));
1423
+ }
1224
1424
  function fieldDoesNotExist(result, fieldName) {
1225
1425
  return !!fieldName && isEmpty(result.tests[fieldName]);
1226
1426
  }
1227
1427
  function noMissingTests(fieldName) {
1228
- var testObjects = useTestObjects()[0];
1428
+ var testObjects = useTestsFlat();
1429
+ var optionalFields = useOptionalFields()[0];
1229
1430
  return testObjects.every(function (testObject) {
1230
1431
  if (nonMatchingFieldName(testObject, fieldName)) {
1231
1432
  return true;
1232
1433
  }
1233
- if (isOptionalField(testObject.fieldName)) {
1234
- return true;
1235
- }
1236
- return testObject.isTested();
1434
+ return (optionalFields[testObject.fieldName] === true ||
1435
+ testObject.isTested() ||
1436
+ testObject.isOmitted());
1237
1437
  });
1238
1438
  }
1239
1439
 
1240
1440
  var cache$1 = createCache(20);
1241
1441
  function produceDraft() {
1242
- var testObjects = useTestObjects()[0];
1442
+ var testObjects = useTestsFlat();
1243
1443
  var ctxRef = { stateRef: useStateRef() };
1244
1444
  return cache$1([testObjects], ctx.bind(ctxRef, function () {
1245
1445
  return assign(genTestsSummary(), {
@@ -1260,7 +1460,7 @@ function produceDraft() {
1260
1460
 
1261
1461
  var cache = createCache(20);
1262
1462
  function produceFullResult() {
1263
- var testObjects = useTestObjects()[0];
1463
+ var testObjects = useTestsFlat();
1264
1464
  var ctxRef = { stateRef: useStateRef() };
1265
1465
  return cache([testObjects], ctx.bind(ctxRef, function () {
1266
1466
  return assign({}, produceDraft(), {
@@ -1318,6 +1518,15 @@ function deferDoneCallback(doneCallback, fieldName) {
1318
1518
  });
1319
1519
  }
1320
1520
 
1521
+ /**
1522
+ * Removes test object from suite state
1523
+ */
1524
+ function removeTestFromState (testObject) {
1525
+ useSetTests(function (tests) {
1526
+ return transform(tests, function (test) { return (testObject !== test ? test : null); });
1527
+ });
1528
+ }
1529
+
1321
1530
  function createBus() {
1322
1531
  var listeners = {};
1323
1532
  return {
@@ -1353,8 +1562,7 @@ function callEach(arr) {
1353
1562
  function runFieldCallbacks(fieldName) {
1354
1563
  var fieldCallbacks = useTestCallbacks()[0].fieldCallbacks;
1355
1564
  if (fieldName) {
1356
- if (!hasRemainingTests(fieldName) &&
1357
- Array.isArray(fieldCallbacks[fieldName])) {
1565
+ if (!hasRemainingTests(fieldName) && isArray(fieldCallbacks[fieldName])) {
1358
1566
  callEach(fieldCallbacks[fieldName]);
1359
1567
  }
1360
1568
  }
@@ -1406,22 +1614,23 @@ function create(suiteCallback) {
1406
1614
  for (var _i = 0; _i < arguments.length; _i++) {
1407
1615
  args[_i] = arguments[_i];
1408
1616
  }
1409
- var prevTestObjects = useTestObjects()[0];
1410
- var _a = usePrevTestObjects(), setPrevTestObjects = _a[1];
1411
1617
  state.reset();
1412
- setPrevTestObjects(function () { return prevTestObjects; });
1413
1618
  // Run the consumer's callback
1414
- suiteCallback.apply(void 0, args);
1619
+ isolate({ type: IsolateTypes.SUITE }, function () {
1620
+ suiteCallback.apply(void 0, args);
1621
+ });
1622
+ omitOptionalTests();
1415
1623
  var res = produceFullResult();
1416
1624
  return res;
1417
1625
  }), {
1418
1626
  get: ctx.bind({ stateRef: stateRef }, produceDraft),
1419
1627
  remove: ctx.bind({ stateRef: stateRef }, function (name) {
1420
- var testObjects = useTestObjects()[0];
1628
+ var testObjects = useTestsFlat();
1421
1629
  // We're mutating the array in `cancel`, so we have to first copy it.
1422
- asArray(testObjects).forEach(function (testObject) {
1630
+ testObjects.forEach(function (testObject) {
1423
1631
  if (matchingFieldName(testObject, name)) {
1424
1632
  testObject.cancel();
1633
+ removeTestFromState(testObject);
1425
1634
  }
1426
1635
  });
1427
1636
  }),
@@ -1535,6 +1744,12 @@ function hasIncludedTests(keyTests) {
1535
1744
  return false;
1536
1745
  }
1537
1746
 
1747
+ function skipWhen(conditional, callback) {
1748
+ isolate({ type: IsolateTypes.SKIP_WHEN }, function () {
1749
+ ctx.run({ skipped: optionalFunctionValue(conditional) }, function () { return callback(); });
1750
+ });
1751
+ }
1752
+
1538
1753
  var ERROR_OUTSIDE_OF_TEST = "warn hook called outside of a test callback. It won't have an effect."
1539
1754
  ;
1540
1755
  /**
@@ -1548,10 +1763,6 @@ function warn() {
1548
1763
  ctx$1.currentTest.warn();
1549
1764
  }
1550
1765
 
1551
- function skipWhen(conditional, callback) {
1552
- ctx.run({ skipped: optionalFunctionValue(conditional) }, function () { return callback(); });
1553
- }
1554
-
1555
1766
  /**
1556
1767
  * Runs a group callback.
1557
1768
  */
@@ -1563,7 +1774,9 @@ function group(groupName, tests) {
1563
1774
  throwGroupError('callback must be a function');
1564
1775
  }
1565
1776
  // Running with the context applied
1566
- ctx.run({ groupName: groupName }, tests);
1777
+ isolate({ type: IsolateTypes.GROUP }, function () {
1778
+ ctx.run({ groupName: groupName }, tests);
1779
+ });
1567
1780
  }
1568
1781
  function throwGroupError(error) {
1569
1782
  throwError("Wrong arguments passed to group. Group " + error + ".");
@@ -1572,36 +1785,22 @@ function throwGroupError(error) {
1572
1785
  function optional(optionals) {
1573
1786
  var _a = useOptionalFields(), setOptionalFields = _a[1];
1574
1787
  setOptionalFields(function (state) {
1575
- asArray(optionals).forEach(function (optionalField) {
1576
- state[optionalField] = true;
1577
- });
1788
+ if (!isArray(optionals) && !isStringValue(optionals)) {
1789
+ var optionalFunctions = optionals;
1790
+ for (var field in optionalFunctions) {
1791
+ var predicate = optionalFunctions[field];
1792
+ state[field] = predicate;
1793
+ }
1794
+ }
1795
+ else {
1796
+ asArray(optionals).forEach(function (optionalField) {
1797
+ state[optionalField] = true;
1798
+ });
1799
+ }
1578
1800
  return state;
1579
1801
  });
1580
1802
  }
1581
1803
 
1582
- /**
1583
- * Removes first found element from array
1584
- * WARNING: Mutates array
1585
- */
1586
- function removeElementFromArray(array, element) {
1587
- var index = array.indexOf(element);
1588
- if (index !== -1) {
1589
- array.splice(index, 1);
1590
- }
1591
- return array;
1592
- }
1593
-
1594
- /**
1595
- * Removes test object from suite state
1596
- */
1597
- function removeTestFromState (testObject) {
1598
- var _a = useTestObjects(), setTestObjects = _a[1];
1599
- setTestObjects(function (testObjects) {
1600
- // using asArray to clear the cache.
1601
- return asArray(removeElementFromArray(testObjects, testObject));
1602
- });
1603
- }
1604
-
1605
1804
  function shouldUseErrorAsMessage(message, error) {
1606
1805
  // kind of cheating with this safe guard, but it does the job
1607
1806
  return isUndefined(message) && isStringValue(error);
@@ -1639,7 +1838,7 @@ var VestTest = /** @class */ (function () {
1639
1838
  return result;
1640
1839
  };
1641
1840
  VestTest.prototype.setStatus = function (status) {
1642
- if (this.isCanceled()) {
1841
+ if (this.isFinalStatus() && status !== STATUS_OMITTED) {
1643
1842
  return;
1644
1843
  }
1645
1844
  this.status = status;
@@ -1651,7 +1850,7 @@ var VestTest = /** @class */ (function () {
1651
1850
  this.setStatus(this.warns ? STATUS_WARNING : STATUS_FAILED);
1652
1851
  };
1653
1852
  VestTest.prototype.done = function () {
1654
- if (this.isWarning() || this.isCanceled() || this.isFailing()) {
1853
+ if (this.isFinalStatus()) {
1655
1854
  return;
1656
1855
  }
1657
1856
  this.setStatus(STATUS_PASSING);
@@ -1659,12 +1858,18 @@ var VestTest = /** @class */ (function () {
1659
1858
  VestTest.prototype.warn = function () {
1660
1859
  this.warns = true;
1661
1860
  };
1861
+ VestTest.prototype.isFinalStatus = function () {
1862
+ return this.hasFailures() || this.isCanceled() || this.isPassing();
1863
+ };
1662
1864
  VestTest.prototype.skip = function () {
1663
1865
  this.setStatus(STATUS_SKIPPED);
1664
1866
  };
1665
1867
  VestTest.prototype.cancel = function () {
1666
1868
  this.setStatus(STATUS_CANCELED);
1667
- removeTestFromState(this);
1869
+ useRefreshTestObjects();
1870
+ };
1871
+ VestTest.prototype.omit = function () {
1872
+ this.setStatus(STATUS_OMITTED);
1668
1873
  };
1669
1874
  VestTest.prototype.valueOf = function () {
1670
1875
  return !this.isFailing();
@@ -1678,6 +1883,9 @@ var VestTest = /** @class */ (function () {
1678
1883
  VestTest.prototype.isTested = function () {
1679
1884
  return this.hasFailures() || this.isPassing();
1680
1885
  };
1886
+ VestTest.prototype.isOmitted = function () {
1887
+ return this.status === STATUS_OMITTED;
1888
+ };
1681
1889
  VestTest.prototype.isUntested = function () {
1682
1890
  return this.status === STATUS_UNTESTED;
1683
1891
  };
@@ -1705,6 +1913,7 @@ var STATUS_WARNING = 'WARNING';
1705
1913
  var STATUS_PASSING = 'PASSING';
1706
1914
  var STATUS_PENDING = 'PENDING';
1707
1915
  var STATUS_CANCELED = 'CANCELED';
1916
+ var STATUS_OMITTED = 'OMITTED';
1708
1917
 
1709
1918
  function isPromise(value) {
1710
1919
  return value && isFunction(value.then);
@@ -1733,6 +1942,8 @@ function runAsyncTest(testObject) {
1733
1942
  var emit = useBus().emit;
1734
1943
  var stateRef = useStateRef();
1735
1944
  var done = ctx.bind({ stateRef: stateRef }, function () {
1945
+ // invalidating the "produce" cache
1946
+ useRefreshTestObjects();
1736
1947
  emit(Events.TEST_COMPLETED, testObject);
1737
1948
  });
1738
1949
  var fail = ctx.bind({ stateRef: stateRef }, function (rejectionMessage) {
@@ -1743,8 +1954,6 @@ function runAsyncTest(testObject) {
1743
1954
  ? rejectionMessage
1744
1955
  : message;
1745
1956
  testObject.fail();
1746
- // invalidating the "produce" cache
1747
- useRefreshTestObjects();
1748
1957
  done();
1749
1958
  });
1750
1959
  try {
@@ -1798,21 +2007,86 @@ function registerTest(testObject) {
1798
2007
  emit(Events.TEST_COMPLETED, testObject);
1799
2008
  }
1800
2009
  }
1801
- catch (_a) {
2010
+ catch (e) {
1802
2011
  throwError("Your test function " + testObject.fieldName + " returned " + JSON.stringify(result) + ". Only \"false\" or a Promise are supported. Return values may cause unexpected behavior.");
1803
2012
  }
1804
2013
  }
1805
2014
 
2015
+ /**
2016
+ * This module serves as the "collision detection" mechanism for Vest.
2017
+ * It is used to ensure that tests are not called in a different order than
2018
+ * they were called in the previous run.
2019
+ * If they are, it will throw a deferred error unless explicitly allowed.
2020
+ *
2021
+ * For now it seems pretty safe, and it covers most common use cases, but it can
2022
+ * be improved in the future both in terms of performance and scenarios it covers.
2023
+ */
2024
+ // eslint-disable-next-line max-statements, max-lines-per-function
2025
+ function useTestAtCursor(newTestObject) {
2026
+ var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
2027
+ var prevTests = testObjects.prev;
2028
+ if (isEmpty(prevTests)) {
2029
+ useSetTestAtCursor(newTestObject);
2030
+ return newTestObject;
2031
+ }
2032
+ var prevTest = useGetTestAtCursor(prevTests);
2033
+ if (shouldPurgePrevTest(prevTest, newTestObject)) {
2034
+ throwTestOrderError(prevTest, newTestObject);
2035
+ // Here we handle just the omission of tests in the middle of the test suite.
2036
+ // We need to also handle a case in which tests are added in between other tests.
2037
+ // At the moment all we can do is just splice the tests out of the array when this happens.
2038
+ // A viable solution would be to use something like React's key prop to identify tests regardless
2039
+ // of their position in the suite. https://reactjs.org/docs/lists-and-keys.html#keys
2040
+ var current = getCurrent(prevTests, usePath());
2041
+ var cursorAt = useCursorAt();
2042
+ current.splice(cursorAt);
2043
+ // We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
2044
+ // since we're only touching the "prev" state. The reason we still use the setter function is
2045
+ // to prevent future headaches if we ever do need to rely on prev-state immutability.
2046
+ setTestObjects(function (_a) {
2047
+ var current = _a.current;
2048
+ return ({
2049
+ prev: prevTests,
2050
+ current: current
2051
+ });
2052
+ });
2053
+ // Need to see if this has any effect at all.
2054
+ prevTest = null;
2055
+ }
2056
+ var nextTest = defaultTo(prevTest, newTestObject);
2057
+ useSetTestAtCursor(nextTest);
2058
+ return nextTest;
2059
+ }
2060
+ function useSetTestAtCursor(testObject) {
2061
+ var cursorPath = usePath();
2062
+ useSetTests(function (tests) {
2063
+ return setValueAtPath(tests, cursorPath, testObject);
2064
+ });
2065
+ }
2066
+ function useGetTestAtCursor(tests) {
2067
+ var cursorPath = usePath();
2068
+ return valueAtPath(tests, cursorPath);
2069
+ }
2070
+ function shouldPurgePrevTest(prevTest, newTest) {
2071
+ return isNotEmpty(prevTest) && !isSameProfileTest(prevTest, newTest);
2072
+ }
2073
+ function throwTestOrderError(prevTest, newTestObject) {
2074
+ if (shouldAllowReorder()) {
2075
+ return;
2076
+ }
2077
+ 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.");
2078
+ }
2079
+
1806
2080
  function registerPrevRunTest(testObject) {
1807
2081
  var prevRunTest = useTestAtCursor(testObject);
1808
2082
  if (isExcluded(testObject)) {
1809
2083
  testObject.skip();
1810
- useSetNextCursorAt();
2084
+ moveForward();
1811
2085
  return prevRunTest;
1812
2086
  }
1813
2087
  cancelOverriddenPendingTest(prevRunTest, testObject);
1814
2088
  useSetTestAtCursor(testObject);
1815
- useSetNextCursorAt();
2089
+ moveForward();
1816
2090
  registerTestObjectByTier(testObject);
1817
2091
  return testObject;
1818
2092
  }
@@ -1831,7 +2105,7 @@ function bindTestEach(test) {
1831
2105
  * Run multiple tests using a parameter table
1832
2106
  */
1833
2107
  function each(table) {
1834
- if (!Array.isArray(table)) {
2108
+ if (!isArray(table)) {
1835
2109
  throwError('test.each: Expected table to be an array.');
1836
2110
  }
1837
2111
  function eachReturn(fieldName) {
@@ -1840,9 +2114,12 @@ function bindTestEach(test) {
1840
2114
  args[_i - 1] = arguments[_i];
1841
2115
  }
1842
2116
  var _a = args.reverse(), testFn = _a[0], message = _a[1];
1843
- return table.map(function (item) {
1844
- item = asArray(item);
1845
- 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); });
2117
+ return isolate({ type: IsolateTypes.EACH }, function () {
2118
+ return table.map(function (item) {
2119
+ item = asArray(item);
2120
+ 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
2121
+ );
2122
+ });
1846
2123
  });
1847
2124
  }
1848
2125
  return eachReturn;
@@ -1860,7 +2137,7 @@ function bindTestMemo(test) {
1860
2137
  args[_i - 1] = arguments[_i];
1861
2138
  }
1862
2139
  var suiteId = useSuiteId()[0];
1863
- var cursorAt = useCursorAt()[0];
2140
+ var cursorAt = useCursorAt();
1864
2141
  var _a = args.reverse(), deps = _a[0], testFn = _a[1], msg = _a[2];
1865
2142
  // Implicit dependency for more specificity
1866
2143
  var dependencies = [suiteId, fieldName, cursorAt].concat(deps);
@@ -1897,6 +2174,6 @@ var test = assign(testBase, {
1897
2174
  memo: bindTestMemo(testBase)
1898
2175
  });
1899
2176
 
1900
- var VERSION = "4.0.0-dev-deabb8";
2177
+ var VERSION = "4.0.0-dev-8851ff";
1901
2178
 
1902
2179
  export { VERSION, create, enforce, group, only, optional, skip, skipWhen, test, warn };