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
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { dummyTest } from '../../../testUtils/testDummy';
|
|
2
|
+
|
|
3
|
+
import { TTestSuite } from 'testUtils/TVestMock';
|
|
4
|
+
import * as vest from 'vest';
|
|
5
|
+
|
|
6
|
+
describe('skipWhen', () => {
|
|
7
|
+
let fn = jest.fn();
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
fn = jest.fn();
|
|
10
|
+
suite.reset();
|
|
11
|
+
});
|
|
12
|
+
it('Should run callback both when condition is true or false', () => {
|
|
13
|
+
let counter = 0;
|
|
14
|
+
const suite = vest.create(() => {
|
|
15
|
+
vest.skipWhen(counter === 1, fn);
|
|
16
|
+
|
|
17
|
+
counter++;
|
|
18
|
+
});
|
|
19
|
+
expect(fn).toHaveBeenCalledTimes(0);
|
|
20
|
+
suite();
|
|
21
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
22
|
+
suite();
|
|
23
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('Should respect both boolean and function conditions', () => {
|
|
27
|
+
const suite = vest.create(() => {
|
|
28
|
+
vest.skipWhen(false, fn);
|
|
29
|
+
vest.skipWhen(true, fn);
|
|
30
|
+
vest.skipWhen(() => false, fn);
|
|
31
|
+
vest.skipWhen(() => true, fn);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
suite();
|
|
35
|
+
|
|
36
|
+
expect(fn).toHaveBeenCalledTimes(4);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('Should pass result draft to the functional condition', () => {
|
|
40
|
+
const f = jest.fn();
|
|
41
|
+
const control = jest.fn();
|
|
42
|
+
|
|
43
|
+
vest.create(() => {
|
|
44
|
+
vest.skipWhen(draft => {
|
|
45
|
+
expect(draft.hasErrors()).toBe(false);
|
|
46
|
+
expect(draft).toMatchSnapshot();
|
|
47
|
+
control();
|
|
48
|
+
return false;
|
|
49
|
+
}, f);
|
|
50
|
+
dummyTest.failing('f1', 'msg');
|
|
51
|
+
vest.skipWhen(draft => {
|
|
52
|
+
expect(draft.hasErrors()).toBe(true);
|
|
53
|
+
expect(draft.hasErrors('f1')).toBe(true);
|
|
54
|
+
expect(draft.hasErrors('f2')).toBe(false);
|
|
55
|
+
expect(draft.hasErrors('f3')).toBe(false);
|
|
56
|
+
expect(draft).toMatchSnapshot();
|
|
57
|
+
control();
|
|
58
|
+
return false;
|
|
59
|
+
}, f);
|
|
60
|
+
dummyTest.failing('f2', 'msg');
|
|
61
|
+
vest.skipWhen(draft => {
|
|
62
|
+
expect(draft.hasErrors()).toBe(true);
|
|
63
|
+
expect(draft.hasErrors('f1')).toBe(true);
|
|
64
|
+
expect(draft.hasErrors('f2')).toBe(true);
|
|
65
|
+
expect(draft.hasErrors('f3')).toBe(false);
|
|
66
|
+
expect(draft).toMatchSnapshot();
|
|
67
|
+
control();
|
|
68
|
+
return false;
|
|
69
|
+
}, f);
|
|
70
|
+
dummyTest.failing('f3', 'msg');
|
|
71
|
+
})();
|
|
72
|
+
|
|
73
|
+
expect(control).toHaveBeenCalledTimes(3);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('Should skip tests when the condition is truthy', () => {
|
|
77
|
+
const res = suite(true);
|
|
78
|
+
expect(res.tests.username.testCount).toBe(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('Should run tests when the condition is falsy', () => {
|
|
82
|
+
const res = suite(false);
|
|
83
|
+
expect(res.tests.username.testCount).toBe(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('Should correctly refill the state when field is skipped', () => {
|
|
87
|
+
const res = suite(false);
|
|
88
|
+
expect(res.tests.username.testCount).toBe(1);
|
|
89
|
+
suite(true);
|
|
90
|
+
|
|
91
|
+
expect(suite.get().tests.username.testCount).toBe(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('nested calls', () => {
|
|
95
|
+
let suite: TTestSuite;
|
|
96
|
+
|
|
97
|
+
describe('skipped in non-skipped', () => {
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
suite = vest.create(() => {
|
|
100
|
+
vest.skipWhen(false, () => {
|
|
101
|
+
vest.test('outer', () => false);
|
|
102
|
+
|
|
103
|
+
vest.skipWhen(true, () => {
|
|
104
|
+
vest.test('inner', () => false);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
suite();
|
|
109
|
+
});
|
|
110
|
+
it('Should run `outer` and skip `inner`', () => {
|
|
111
|
+
expect(suite.get().testCount).toBe(1);
|
|
112
|
+
expect(suite.get().hasErrors('outer')).toBe(true);
|
|
113
|
+
expect(suite.get().hasErrors('inner')).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('skipped in skipped', () => {
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
suite = vest.create(() => {
|
|
120
|
+
vest.skipWhen(true, () => {
|
|
121
|
+
vest.test('outer', () => false);
|
|
122
|
+
|
|
123
|
+
vest.skipWhen(true, () => {
|
|
124
|
+
vest.test('inner', () => false);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
suite();
|
|
129
|
+
});
|
|
130
|
+
it('Should skip both `outer` and `inner`', () => {
|
|
131
|
+
expect(suite.get().testCount).toBe(0);
|
|
132
|
+
expect(suite.get().hasErrors('outer')).toBe(false);
|
|
133
|
+
expect(suite.get().hasErrors('inner')).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('non-skipped in skipped', () => {
|
|
137
|
+
beforeEach(() => {
|
|
138
|
+
suite = vest.create(() => {
|
|
139
|
+
vest.skipWhen(true, () => {
|
|
140
|
+
vest.test('outer', () => false);
|
|
141
|
+
|
|
142
|
+
vest.skipWhen(false, () => {
|
|
143
|
+
vest.test('inner', () => false);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
suite();
|
|
148
|
+
});
|
|
149
|
+
it('Should skip both', () => {
|
|
150
|
+
expect(suite.get().testCount).toBe(0);
|
|
151
|
+
expect(suite.get().hasErrors('outer')).toBe(false);
|
|
152
|
+
expect(suite.get().hasErrors('inner')).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const suite = vest.create((skipTest: boolean) => {
|
|
159
|
+
vest.skipWhen(skipTest, () => {
|
|
160
|
+
vest.test('username', () => false);
|
|
161
|
+
});
|
|
162
|
+
vest.test('control', () => false);
|
|
163
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { invariant, isFunction } from 'vest-utils';
|
|
2
|
+
|
|
3
|
+
import { IsolateTypes } from 'IsolateTypes';
|
|
4
|
+
import { Isolate } from 'isolate';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Iterates over an array of items, allowing to run tests individually per item.
|
|
8
|
+
*
|
|
9
|
+
* Requires setting a "key" property on each item tested.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
*
|
|
13
|
+
* each(itemsArray, (item) => {
|
|
14
|
+
* test(item.name, 'Item value must not be empty', () => {
|
|
15
|
+
* enforce(item.value).isNotEmpty();
|
|
16
|
+
* }, item.id)
|
|
17
|
+
* })
|
|
18
|
+
*/
|
|
19
|
+
export function each<T>(
|
|
20
|
+
list: T[],
|
|
21
|
+
callback: (arg: T, index: number) => void
|
|
22
|
+
): void {
|
|
23
|
+
invariant(isFunction(callback), 'each callback must be a function');
|
|
24
|
+
|
|
25
|
+
Isolate.create(IsolateTypes.EACH, () => {
|
|
26
|
+
list.forEach((arg, index) => {
|
|
27
|
+
callback(arg, index);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IsolateTypes } from 'IsolateTypes';
|
|
2
|
+
import { SuiteContext } from 'SuiteContext';
|
|
3
|
+
import { Isolate } from 'isolate';
|
|
4
|
+
|
|
5
|
+
export function group(groupName: string, callback: () => void): Isolate {
|
|
6
|
+
return Isolate.create(IsolateTypes.GROUP, () => {
|
|
7
|
+
SuiteContext.run({ groupName }, callback);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CB } from 'vest-utils';
|
|
2
|
+
import { optionalFunctionValue } from 'vest-utils';
|
|
3
|
+
|
|
4
|
+
import { IsolateTypes } from 'IsolateTypes';
|
|
5
|
+
import { SuiteContext, useOmitted } from 'SuiteContext';
|
|
6
|
+
import { SuiteResult, TFieldName } from 'SuiteResultTypes';
|
|
7
|
+
import { Isolate } from 'isolate';
|
|
8
|
+
import { createSuiteResult } from 'suiteResult';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Conditionally omits tests from the suite.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
*
|
|
15
|
+
* omitWhen(res => res.hasErrors('username'), () => {
|
|
16
|
+
* test('username', 'User already taken', async () => await doesUserExist(username)
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export function omitWhen<F extends TFieldName>(
|
|
20
|
+
conditional: boolean | ((draft: SuiteResult<F>) => boolean),
|
|
21
|
+
callback: CB
|
|
22
|
+
): void {
|
|
23
|
+
Isolate.create(IsolateTypes.OMIT_WHEN, () => {
|
|
24
|
+
SuiteContext.run(
|
|
25
|
+
{
|
|
26
|
+
omitted:
|
|
27
|
+
withinActiveOmitWhen() ||
|
|
28
|
+
optionalFunctionValue(
|
|
29
|
+
conditional,
|
|
30
|
+
optionalFunctionValue(createSuiteResult)
|
|
31
|
+
),
|
|
32
|
+
},
|
|
33
|
+
callback
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Checks that we're currently in an active omitWhen block
|
|
39
|
+
export function withinActiveOmitWhen(): boolean {
|
|
40
|
+
return useOmitted();
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CB, optionalFunctionValue } from 'vest-utils';
|
|
2
|
+
|
|
3
|
+
import { IsolateTypes } from 'IsolateTypes';
|
|
4
|
+
import { SuiteContext, useSkipped } from 'SuiteContext';
|
|
5
|
+
import { SuiteResult, TFieldName } from 'SuiteResultTypes';
|
|
6
|
+
import { Isolate } from 'isolate';
|
|
7
|
+
import { createSuiteResult } from 'suiteResult';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Conditionally skips running tests within the callback.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
*
|
|
14
|
+
* skipWhen(res => res.hasErrors('username'), () => {
|
|
15
|
+
* test('username', 'User already taken', async () => await doesUserExist(username)
|
|
16
|
+
* });
|
|
17
|
+
*/
|
|
18
|
+
export function skipWhen<F extends TFieldName>(
|
|
19
|
+
condition: boolean | ((draft: SuiteResult<F>) => boolean),
|
|
20
|
+
callback: CB
|
|
21
|
+
): void {
|
|
22
|
+
Isolate.create(IsolateTypes.SKIP_WHEN, () => {
|
|
23
|
+
SuiteContext.run(
|
|
24
|
+
{
|
|
25
|
+
skipped:
|
|
26
|
+
// Checking for nested conditional. If we're in a nested skipWhen,
|
|
27
|
+
// we should skip the test if the parent conditional is true.
|
|
28
|
+
isExcludedIndividually() ||
|
|
29
|
+
// Otherwise, we should skip the test if the conditional is true.
|
|
30
|
+
optionalFunctionValue(
|
|
31
|
+
condition,
|
|
32
|
+
optionalFunctionValue(createSuiteResult)
|
|
33
|
+
),
|
|
34
|
+
},
|
|
35
|
+
callback
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isExcludedIndividually(): boolean {
|
|
41
|
+
return useSkipped();
|
|
42
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Test createSuite module Initial run Should be able to get the suite from the result of createSuite 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"errorCount": 0,
|
|
6
|
+
"getErrors": [Function],
|
|
7
|
+
"getErrorsByGroup": [Function],
|
|
8
|
+
"getWarnings": [Function],
|
|
9
|
+
"getWarningsByGroup": [Function],
|
|
10
|
+
"groups": {},
|
|
11
|
+
"hasErrors": [Function],
|
|
12
|
+
"hasErrorsByGroup": [Function],
|
|
13
|
+
"hasWarnings": [Function],
|
|
14
|
+
"hasWarningsByGroup": [Function],
|
|
15
|
+
"isValid": [Function],
|
|
16
|
+
"isValidByGroup": [Function],
|
|
17
|
+
"suiteName": undefined,
|
|
18
|
+
"testCount": 0,
|
|
19
|
+
"tests": {},
|
|
20
|
+
"valid": false,
|
|
21
|
+
"warnCount": 0,
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`Test createSuite module Initial run Should initialize with an empty result object 1`] = `
|
|
26
|
+
{
|
|
27
|
+
"errorCount": 0,
|
|
28
|
+
"getErrors": [Function],
|
|
29
|
+
"getErrorsByGroup": [Function],
|
|
30
|
+
"getWarnings": [Function],
|
|
31
|
+
"getWarningsByGroup": [Function],
|
|
32
|
+
"groups": {},
|
|
33
|
+
"hasErrors": [Function],
|
|
34
|
+
"hasErrorsByGroup": [Function],
|
|
35
|
+
"hasWarnings": [Function],
|
|
36
|
+
"hasWarningsByGroup": [Function],
|
|
37
|
+
"isValid": [Function],
|
|
38
|
+
"isValidByGroup": [Function],
|
|
39
|
+
"suiteName": undefined,
|
|
40
|
+
"testCount": 0,
|
|
41
|
+
"tests": {},
|
|
42
|
+
"valid": false,
|
|
43
|
+
"warnCount": 0,
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
exports[`Test createSuite module Test suite Arguments allows omitting suite name 1`] = `
|
|
48
|
+
{
|
|
49
|
+
"errorCount": 0,
|
|
50
|
+
"getErrors": [Function],
|
|
51
|
+
"getErrorsByGroup": [Function],
|
|
52
|
+
"getWarnings": [Function],
|
|
53
|
+
"getWarningsByGroup": [Function],
|
|
54
|
+
"groups": {},
|
|
55
|
+
"hasErrors": [Function],
|
|
56
|
+
"hasErrorsByGroup": [Function],
|
|
57
|
+
"hasWarnings": [Function],
|
|
58
|
+
"hasWarningsByGroup": [Function],
|
|
59
|
+
"isValid": [Function],
|
|
60
|
+
"isValidByGroup": [Function],
|
|
61
|
+
"suiteName": undefined,
|
|
62
|
+
"testCount": 0,
|
|
63
|
+
"tests": {},
|
|
64
|
+
"valid": false,
|
|
65
|
+
"warnCount": 0,
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { noop } from 'lodash';
|
|
3
|
+
|
|
4
|
+
import { dummyTest } from '../../../testUtils/testDummy';
|
|
5
|
+
import { TestPromise } from '../../../testUtils/testPromise';
|
|
6
|
+
|
|
7
|
+
import { create } from 'vest';
|
|
8
|
+
|
|
9
|
+
describe('Test createSuite module', () => {
|
|
10
|
+
describe('Test suite Arguments', () => {
|
|
11
|
+
it('allows omitting suite name', () => {
|
|
12
|
+
expect(typeof create(jest.fn())).toBe('function');
|
|
13
|
+
expect(typeof create(jest.fn()).get).toBe('function');
|
|
14
|
+
expect(typeof create(jest.fn()).reset).toBe('function');
|
|
15
|
+
expect(typeof create(jest.fn()).remove).toBe('function');
|
|
16
|
+
expect(create(jest.fn()).get()).toMatchSnapshot();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it.each([faker.random.word(), null, undefined, 0, 1, true, false, NaN, ''])(
|
|
20
|
+
'Throws an error when `tests` callback is not a function',
|
|
21
|
+
value => {
|
|
22
|
+
// @ts-expect-error - testing invalid input
|
|
23
|
+
expect(() => create(value)).toThrow(
|
|
24
|
+
'vest.create: Expected callback to be a function.'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
describe('When suite name is provided', () => {
|
|
30
|
+
it('Should add suite name to suite result', () => {
|
|
31
|
+
const res = create('form_name', () => {})();
|
|
32
|
+
|
|
33
|
+
expect(res.suiteName).toBe('form_name');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('Return value', () => {
|
|
39
|
+
it('should be a function', () => {
|
|
40
|
+
expect(typeof create(noop)).toBe('function');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('When returned function is invoked', () => {
|
|
45
|
+
it('Calls `tests` argument', () =>
|
|
46
|
+
TestPromise(done => {
|
|
47
|
+
const validate = create(() => {
|
|
48
|
+
done();
|
|
49
|
+
});
|
|
50
|
+
validate();
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
it('Passes all arguments over to tests callback', () => {
|
|
54
|
+
const testsCallback = jest.fn();
|
|
55
|
+
const params = [
|
|
56
|
+
1,
|
|
57
|
+
2,
|
|
58
|
+
3,
|
|
59
|
+
{ [faker.random.word()]: [1, 2, 3] },
|
|
60
|
+
false,
|
|
61
|
+
[faker.random.word()],
|
|
62
|
+
];
|
|
63
|
+
const validate = create(testsCallback);
|
|
64
|
+
validate(...params);
|
|
65
|
+
expect(testsCallback).toHaveBeenCalledWith(...params);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('Initial run', () => {
|
|
70
|
+
const testsCb = jest.fn();
|
|
71
|
+
const genValidate = () => create(testsCb);
|
|
72
|
+
|
|
73
|
+
it('Should initialize with an empty result object', () => {
|
|
74
|
+
const validate = genValidate();
|
|
75
|
+
expect(Object.keys(validate.get().tests)).toHaveLength(0);
|
|
76
|
+
expect(Object.keys(validate.get().groups)).toHaveLength(0);
|
|
77
|
+
|
|
78
|
+
expect(validate.get().errorCount).toBe(0);
|
|
79
|
+
expect(validate.get().warnCount).toBe(0);
|
|
80
|
+
expect(validate.get().testCount).toBe(0);
|
|
81
|
+
|
|
82
|
+
expect(validate.get()).toMatchSnapshot();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('Should be able to get the suite from the result of createSuite', () => {
|
|
86
|
+
const testsCb = jest.fn();
|
|
87
|
+
expect(create(testsCb).get()).toMatchSnapshot();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('Should be able to reset the suite from the result of createSuite', () => {
|
|
91
|
+
const testSuite = create(() => {
|
|
92
|
+
dummyTest.failing('f1', 'm1');
|
|
93
|
+
});
|
|
94
|
+
testSuite();
|
|
95
|
+
expect(testSuite.get().hasErrors()).toBe(true);
|
|
96
|
+
expect(testSuite.get().testCount).toBe(1);
|
|
97
|
+
testSuite.reset();
|
|
98
|
+
expect(testSuite.get().hasErrors()).toBe(false);
|
|
99
|
+
expect(testSuite.get().testCount).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('Should return without calling tests callback', () => {
|
|
103
|
+
const validate = create(testsCb);
|
|
104
|
+
expect(testsCb).not.toHaveBeenCalled();
|
|
105
|
+
validate();
|
|
106
|
+
expect(testsCb).toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import wait from 'wait';
|
|
2
|
+
|
|
3
|
+
import { dummyTest } from '../../../testUtils/testDummy';
|
|
4
|
+
|
|
5
|
+
import * as vest from 'vest';
|
|
6
|
+
|
|
7
|
+
describe('suite.remove', () => {
|
|
8
|
+
it('Should remove field from validation result', async () => {
|
|
9
|
+
const suite = vest.create(() => {
|
|
10
|
+
dummyTest.failing('field1');
|
|
11
|
+
dummyTest.failing('field1');
|
|
12
|
+
dummyTest.failingAsync('field1', { time: 100 });
|
|
13
|
+
dummyTest.failing('field2');
|
|
14
|
+
dummyTest.passing('field2');
|
|
15
|
+
dummyTest.passing('field1');
|
|
16
|
+
});
|
|
17
|
+
suite();
|
|
18
|
+
expect(suite.get().testCount).toBe(6);
|
|
19
|
+
expect(suite.get().tests.field1.testCount).toBe(4);
|
|
20
|
+
expect(suite.get().tests.field2.testCount).toBe(2);
|
|
21
|
+
suite.remove('field1');
|
|
22
|
+
expect(suite.get().testCount).toBe(2);
|
|
23
|
+
expect(suite.get().tests.field1).toBeUndefined();
|
|
24
|
+
await wait(150);
|
|
25
|
+
expect(suite.get().testCount).toBe(2);
|
|
26
|
+
expect(suite.get().tests.field1).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('Should clear the cache when removing a field', () => {
|
|
30
|
+
const suite = vest.create(() => {
|
|
31
|
+
dummyTest.failing('field1');
|
|
32
|
+
dummyTest.failing('field2');
|
|
33
|
+
});
|
|
34
|
+
suite();
|
|
35
|
+
const res = suite.get();
|
|
36
|
+
suite.remove('field2');
|
|
37
|
+
expect(suite.get()).not.toBe(res);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('Should return silently when removing a field that does not exist', () => {
|
|
41
|
+
const suite = vest.create(() => {
|
|
42
|
+
dummyTest.failing('field1');
|
|
43
|
+
dummyTest.passing('field2');
|
|
44
|
+
});
|
|
45
|
+
suite();
|
|
46
|
+
const res = suite.get();
|
|
47
|
+
suite.remove('field3');
|
|
48
|
+
expect(suite.get()).isDeepCopyOf(res);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { TTestSuite } from 'testUtils/TVestMock';
|
|
2
|
+
import { create, test } from 'vest';
|
|
3
|
+
|
|
4
|
+
describe('suite.resetField', () => {
|
|
5
|
+
let suite: TTestSuite;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
suite = create(() => {
|
|
9
|
+
test('field1', 'f1 error', () => false);
|
|
10
|
+
test('field2', 'f2 error', () => false);
|
|
11
|
+
});
|
|
12
|
+
suite();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('Should reset the validity state of a field', () => {
|
|
16
|
+
expect(suite.get().hasErrors('field1')).toBe(true);
|
|
17
|
+
expect(suite.get().hasErrors('field2')).toBe(true);
|
|
18
|
+
expect(suite.get().getErrors('field1')).toEqual(['f1 error']);
|
|
19
|
+
expect(suite.get().getErrors('field2')).toEqual(['f2 error']);
|
|
20
|
+
suite.resetField('field1');
|
|
21
|
+
expect(suite.get().hasErrors('field1')).toBe(false);
|
|
22
|
+
expect(suite.get().hasErrors('field2')).toBe(true);
|
|
23
|
+
expect(suite.get().getErrors('field1')).toEqual([]);
|
|
24
|
+
expect(suite.get().getErrors('field2')).toEqual(['f2 error']);
|
|
25
|
+
suite.resetField('field2');
|
|
26
|
+
expect(suite.get().hasErrors('field1')).toBe(false);
|
|
27
|
+
expect(suite.get().hasErrors('field2')).toBe(false);
|
|
28
|
+
expect(suite.get().getErrors('field1')).toEqual([]);
|
|
29
|
+
expect(suite.get().getErrors('field2')).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('Should refresh the suite result', () => {
|
|
33
|
+
const res = suite.get();
|
|
34
|
+
expect(res).toBe(suite.get());
|
|
35
|
+
suite.resetField('field1');
|
|
36
|
+
expect(res).not.toBe(suite.get());
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('Should allow the field to keep updating (no final status)', () => {
|
|
40
|
+
suite.resetField('field1');
|
|
41
|
+
expect(suite.get().hasErrors('field1')).toBe(false);
|
|
42
|
+
expect(suite.get().hasErrors('field2')).toBe(true);
|
|
43
|
+
suite();
|
|
44
|
+
expect(suite.get().hasErrors('field1')).toBe(true);
|
|
45
|
+
expect(suite.get().hasErrors('field2')).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('sanity', () => {
|
|
49
|
+
expect(suite.get().tests).toMatchInlineSnapshot(`
|
|
50
|
+
{
|
|
51
|
+
"field1": {
|
|
52
|
+
"errorCount": 1,
|
|
53
|
+
"errors": [
|
|
54
|
+
"f1 error",
|
|
55
|
+
],
|
|
56
|
+
"testCount": 1,
|
|
57
|
+
"valid": false,
|
|
58
|
+
"warnCount": 0,
|
|
59
|
+
"warnings": [],
|
|
60
|
+
},
|
|
61
|
+
"field2": {
|
|
62
|
+
"errorCount": 1,
|
|
63
|
+
"errors": [
|
|
64
|
+
"f2 error",
|
|
65
|
+
],
|
|
66
|
+
"testCount": 1,
|
|
67
|
+
"valid": false,
|
|
68
|
+
"warnCount": 0,
|
|
69
|
+
"warnings": [],
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
`);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { assign, CB, invariant, isFunction } from 'vest-utils';
|
|
2
|
+
|
|
3
|
+
import { IsolateTypes } from 'IsolateTypes';
|
|
4
|
+
import {
|
|
5
|
+
createVestState,
|
|
6
|
+
persist,
|
|
7
|
+
PersistedContext,
|
|
8
|
+
prepareEmitter,
|
|
9
|
+
useEmit,
|
|
10
|
+
} from 'PersistedContext';
|
|
11
|
+
import { SuiteContext } from 'SuiteContext';
|
|
12
|
+
import { SuiteResult, SuiteRunResult, TFieldName } from 'SuiteResultTypes';
|
|
13
|
+
import { Events } from 'VestBus';
|
|
14
|
+
import { Isolate } from 'isolate';
|
|
15
|
+
import { createSuiteResult } from 'suiteResult';
|
|
16
|
+
import { suiteRunResult } from 'suiteRunResult';
|
|
17
|
+
|
|
18
|
+
function createSuite<T extends CB, F extends TFieldName>(
|
|
19
|
+
suiteName: SuiteName,
|
|
20
|
+
suiteCallback: T
|
|
21
|
+
): Suite<T, F>;
|
|
22
|
+
function createSuite<T extends CB, F extends TFieldName>(
|
|
23
|
+
suiteCallback: T
|
|
24
|
+
): Suite<T, F>;
|
|
25
|
+
function createSuite<T extends CB, F extends TFieldName>(
|
|
26
|
+
...args: [suiteName: SuiteName, suiteCallback: T] | [suiteCallback: T]
|
|
27
|
+
): Suite<T, F> {
|
|
28
|
+
const [suiteCallback, suiteName] = args.reverse() as [T, SuiteName];
|
|
29
|
+
|
|
30
|
+
validateSuiteCallback(suiteCallback);
|
|
31
|
+
|
|
32
|
+
// Create a stateRef for the suite
|
|
33
|
+
// It holds the suite's persisted values that may remain between runs.
|
|
34
|
+
const stateRef = createVestState({ suiteName });
|
|
35
|
+
|
|
36
|
+
function suite(...args: Parameters<T>): SuiteRunResult<F> {
|
|
37
|
+
return SuiteContext.run({}, () => {
|
|
38
|
+
const emit = useEmit();
|
|
39
|
+
|
|
40
|
+
emit(Events.SUITE_RUN_STARTED);
|
|
41
|
+
|
|
42
|
+
return Isolate.create(IsolateTypes.SUITE, runSuiteCallback(...args));
|
|
43
|
+
}).output;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Assign methods to the suite
|
|
47
|
+
// We do this within the PersistedContext so that the suite methods
|
|
48
|
+
// will be bound to the suite's stateRef and be able to access it.
|
|
49
|
+
return PersistedContext.run(stateRef, () => {
|
|
50
|
+
return assign(
|
|
51
|
+
// We're also binding the suite to the stateRef, so that the suite
|
|
52
|
+
// can access the stateRef when it's called.
|
|
53
|
+
PersistedContext.bind(stateRef, suite),
|
|
54
|
+
{
|
|
55
|
+
get: persist(createSuiteResult),
|
|
56
|
+
remove: prepareEmitter<string>(Events.REMOVE_FIELD),
|
|
57
|
+
reset: prepareEmitter(Events.RESET_SUITE),
|
|
58
|
+
resetField: prepareEmitter<string>(Events.RESET_FIELD),
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function runSuiteCallback(...args: Parameters<T>): () => SuiteRunResult<F> {
|
|
64
|
+
return () => {
|
|
65
|
+
suiteCallback(...args);
|
|
66
|
+
return suiteRunResult();
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function validateSuiteCallback<T extends CB>(
|
|
72
|
+
suiteCallback: T
|
|
73
|
+
): asserts suiteCallback is T {
|
|
74
|
+
invariant(
|
|
75
|
+
isFunction(suiteCallback),
|
|
76
|
+
'vest.create: Expected callback to be a function.'
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type SuiteName = string | undefined;
|
|
81
|
+
|
|
82
|
+
export type Suite<T extends CB, F extends TFieldName> = ((
|
|
83
|
+
...args: Parameters<T>
|
|
84
|
+
) => SuiteRunResult<F>) &
|
|
85
|
+
SuiteMethods<F>;
|
|
86
|
+
|
|
87
|
+
type SuiteMethods<F extends TFieldName> = {
|
|
88
|
+
get: () => SuiteResult<F>;
|
|
89
|
+
reset: () => void;
|
|
90
|
+
remove: (fieldName: F) => void;
|
|
91
|
+
resetField: (fieldName: F) => void;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export { createSuite };
|