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