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