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.
Files changed (182) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +2 -57
  3. package/dist/cjs/classnames.development.js +18 -16
  4. package/dist/cjs/classnames.production.js +1 -1
  5. package/dist/cjs/enforce/compose.development.js +5 -54
  6. package/dist/cjs/enforce/compose.production.js +1 -1
  7. package/dist/cjs/enforce/compounds.development.js +20 -83
  8. package/dist/cjs/enforce/compounds.production.js +1 -1
  9. package/dist/cjs/enforce/schema.development.js +19 -82
  10. package/dist/cjs/enforce/schema.production.js +1 -1
  11. package/dist/cjs/parser.development.js +12 -9
  12. package/dist/cjs/parser.production.js +1 -1
  13. package/dist/cjs/promisify.development.js +4 -8
  14. package/dist/cjs/promisify.production.js +1 -1
  15. package/dist/cjs/vest.development.js +1287 -1153
  16. package/dist/cjs/vest.production.js +1 -1
  17. package/dist/es/classnames.development.js +20 -18
  18. package/dist/es/classnames.production.js +1 -1
  19. package/dist/es/enforce/compose.development.js +1 -58
  20. package/dist/es/enforce/compose.production.js +1 -1
  21. package/dist/es/enforce/compounds.development.js +2 -90
  22. package/dist/es/enforce/compounds.production.js +1 -1
  23. package/dist/es/enforce/schema.development.js +2 -88
  24. package/dist/es/enforce/schema.production.js +1 -1
  25. package/dist/es/parser.development.js +12 -9
  26. package/dist/es/parser.production.js +1 -1
  27. package/dist/es/promisify.development.js +5 -9
  28. package/dist/es/promisify.production.js +1 -1
  29. package/dist/es/vest.development.js +1286 -1148
  30. package/dist/es/vest.production.js +1 -1
  31. package/dist/umd/classnames.development.js +21 -19
  32. package/dist/umd/classnames.production.js +1 -1
  33. package/dist/umd/enforce/compose.development.js +9 -57
  34. package/dist/umd/enforce/compose.production.js +1 -1
  35. package/dist/umd/enforce/compounds.development.js +32 -94
  36. package/dist/umd/enforce/compounds.production.js +1 -1
  37. package/dist/umd/enforce/schema.development.js +32 -94
  38. package/dist/umd/enforce/schema.production.js +1 -1
  39. package/dist/umd/parser.development.js +16 -13
  40. package/dist/umd/parser.production.js +1 -1
  41. package/dist/umd/promisify.development.js +7 -11
  42. package/dist/umd/promisify.production.js +1 -1
  43. package/dist/umd/vest.development.js +1289 -1155
  44. package/dist/umd/vest.production.js +1 -1
  45. package/package.json +12 -16
  46. package/src/__tests__/__snapshots__/integration.async-tests.test.ts.snap +71 -0
  47. package/src/__tests__/__snapshots__/integration.base.test.ts.snap +71 -0
  48. package/src/__tests__/__snapshots__/integration.stateful-async.test.ts.snap +243 -0
  49. package/src/__tests__/__snapshots__/integration.stateful-tests.test.ts.snap +376 -0
  50. package/src/__tests__/integration.async-tests.test.ts +90 -0
  51. package/src/__tests__/integration.base.test.ts +45 -0
  52. package/src/__tests__/integration.exclusive.test.ts +88 -0
  53. package/src/__tests__/integration.stateful-async.test.ts +137 -0
  54. package/src/__tests__/integration.stateful-tests.test.ts +155 -0
  55. package/src/__tests__/isolate.test.ts +288 -0
  56. package/src/__tests__/state_refill.test.ts +41 -0
  57. package/src/core/SuiteWalker/SuiteWalker.ts +64 -0
  58. package/src/core/SuiteWalker/__tests__/hasRemainingTests.test.ts +130 -0
  59. package/src/core/VestBus/VestBus.ts +78 -0
  60. package/src/core/context/PersistedContext.ts +243 -0
  61. package/src/core/context/SuiteContext.ts +74 -0
  62. package/src/core/isolate/IsolateTest/IsolateTest.ts +213 -0
  63. package/src/core/isolate/IsolateTest/IsolateTestReconciler.ts +156 -0
  64. package/src/core/isolate/IsolateTest/IsolateTestStateMachine.ts +69 -0
  65. package/src/core/isolate/IsolateTest/SimpleStateMachine.ts +43 -0
  66. package/src/core/isolate/IsolateTest/TestWalker.ts +77 -0
  67. package/src/core/isolate/IsolateTypes.ts +10 -0
  68. package/src/core/isolate/isIsolate.ts +6 -0
  69. package/src/core/isolate/isolate.ts +110 -0
  70. package/src/core/isolate/reconciler/Reconciler/Reconciler.ts +123 -0
  71. package/src/core/isolate/reconciler/cancelOverriddenPendingTest.ts +15 -0
  72. package/src/core/isolate/reconciler/isSameProfileTest.ts +12 -0
  73. package/src/core/isolate/walker.ts +127 -0
  74. package/src/core/test/TestTypes.ts +3 -0
  75. package/src/core/test/__tests__/IsolateTest.test.ts +152 -0
  76. package/src/core/test/__tests__/__snapshots__/IsolateTest.test.ts.snap +39 -0
  77. package/src/core/test/__tests__/__snapshots__/memo.test.ts.snap +101 -0
  78. package/src/core/test/__tests__/__snapshots__/test.test.ts.snap +231 -0
  79. package/src/core/test/__tests__/key.test.ts +195 -0
  80. package/src/core/test/__tests__/memo.test.ts +218 -0
  81. package/src/core/test/__tests__/merging_of_previous_test_runs.test.ts +341 -0
  82. package/src/core/test/__tests__/runAsyncTest.test.ts +175 -0
  83. package/src/core/test/__tests__/test.test.ts +226 -0
  84. package/src/core/test/helpers/__tests__/nonMatchingSeverityProfile.test.ts +52 -0
  85. package/src/core/test/helpers/asVestTest.ts +9 -0
  86. package/src/core/test/helpers/matchingFieldName.ts +16 -0
  87. package/src/core/test/helpers/matchingGroupName.ts +12 -0
  88. package/src/core/test/helpers/nonMatchingSeverityProfile.ts +14 -0
  89. package/src/core/test/helpers/shouldUseErrorMessage.ts +9 -0
  90. package/src/core/test/test.memo.ts +81 -0
  91. package/src/core/test/test.ts +64 -0
  92. package/src/core/test/testLevelFlowControl/runTest.ts +86 -0
  93. package/src/core/test/testLevelFlowControl/verifyTestRun.ts +32 -0
  94. package/src/core/test/testObjectIsolate.ts +11 -0
  95. package/src/errors/ErrorStrings.ts +4 -0
  96. package/src/exports/__tests__/classnames.test.ts +92 -0
  97. package/src/exports/__tests__/parser.test.ts +441 -0
  98. package/src/exports/__tests__/promisify.test.ts +77 -0
  99. package/src/exports/classnames.ts +35 -0
  100. package/src/exports/enforce@compose.ts +1 -0
  101. package/src/exports/enforce@compounds.ts +1 -0
  102. package/src/exports/enforce@schema.ts +1 -0
  103. package/src/exports/parser.ts +63 -0
  104. package/src/exports/promisify.ts +18 -0
  105. package/src/hooks/__tests__/__snapshots__/include.test.ts.snap +794 -0
  106. package/src/hooks/__tests__/eager.test.ts +130 -0
  107. package/src/hooks/__tests__/exclusive.test.ts +578 -0
  108. package/src/hooks/__tests__/include.test.ts +431 -0
  109. package/src/hooks/__tests__/optional.test.ts +83 -0
  110. package/src/hooks/__tests__/warn.test.ts +42 -0
  111. package/src/hooks/exclusive.ts +179 -0
  112. package/src/hooks/include.ts +54 -0
  113. package/src/hooks/mode.ts +47 -0
  114. package/src/hooks/optional/OptionalTypes.ts +31 -0
  115. package/src/hooks/optional/optional.ts +69 -0
  116. package/src/hooks/warn.ts +19 -0
  117. package/src/isolates/__tests__/__snapshots__/each.test.ts.snap +3 -0
  118. package/src/isolates/__tests__/__snapshots__/group.test.ts.snap +114 -0
  119. package/src/isolates/__tests__/__snapshots__/omitWhen.test.ts.snap +443 -0
  120. package/src/isolates/__tests__/__snapshots__/skipWhen.test.ts.snap +99 -0
  121. package/src/isolates/__tests__/each.test.ts +35 -0
  122. package/src/isolates/__tests__/group.test.ts +362 -0
  123. package/src/isolates/__tests__/omitWhen.test.ts +246 -0
  124. package/src/isolates/__tests__/skipWhen.test.ts +163 -0
  125. package/src/isolates/each.ts +30 -0
  126. package/src/isolates/group.ts +9 -0
  127. package/src/isolates/omitWhen.ts +41 -0
  128. package/src/isolates/skipWhen.ts +42 -0
  129. package/src/suite/__tests__/__snapshots__/create.test.ts.snap +67 -0
  130. package/src/suite/__tests__/create.test.ts +109 -0
  131. package/src/suite/__tests__/remove.test.ts +50 -0
  132. package/src/suite/__tests__/resetField.test.ts +74 -0
  133. package/src/suite/createSuite.ts +94 -0
  134. package/src/suite/runCallbacks.ts +28 -0
  135. package/src/suiteResult/Severity.ts +15 -0
  136. package/src/suiteResult/SuiteResultTypes.ts +42 -0
  137. package/src/suiteResult/__tests__/done.test.ts +334 -0
  138. package/src/suiteResult/__tests__/produce.test.ts +163 -0
  139. package/src/suiteResult/done/deferDoneCallback.ts +28 -0
  140. package/src/suiteResult/done/shouldSkipDoneRegistration.ts +20 -0
  141. package/src/suiteResult/selectors/__tests__/__snapshots__/collectFailureMessages.test.ts.snap +89 -0
  142. package/src/suiteResult/selectors/__tests__/collectFailureMessages.test.ts +124 -0
  143. package/src/suiteResult/selectors/__tests__/getFailures.test.ts +158 -0
  144. package/src/suiteResult/selectors/__tests__/getFailuresByGroup.test.ts +199 -0
  145. package/src/suiteResult/selectors/__tests__/hasFailures.test.ts +141 -0
  146. package/src/suiteResult/selectors/__tests__/hasFailuresByGroup.test.ts +185 -0
  147. package/src/suiteResult/selectors/__tests__/hasFailuresByTestObject.test.ts +88 -0
  148. package/src/suiteResult/selectors/__tests__/isValid.test.ts +359 -0
  149. package/src/suiteResult/selectors/__tests__/isValidByGroup.test.ts +480 -0
  150. package/src/suiteResult/selectors/collectFailures.ts +43 -0
  151. package/src/suiteResult/selectors/hasFailuresByTestObjects.ts +62 -0
  152. package/src/suiteResult/selectors/produceSuiteSummary.ts +135 -0
  153. package/src/suiteResult/selectors/shouldAddValidProperty.ts +148 -0
  154. package/src/suiteResult/selectors/suiteSelectors.ts +199 -0
  155. package/src/suiteResult/suiteResult.ts +15 -0
  156. package/src/suiteResult/suiteRunResult.ts +43 -0
  157. package/src/vest.ts +36 -0
  158. package/testUtils/TVestMock.ts +5 -0
  159. package/testUtils/__tests__/partition.test.ts +4 -4
  160. package/testUtils/mockThrowError.ts +4 -2
  161. package/testUtils/suiteDummy.ts +2 -1
  162. package/testUtils/testDummy.ts +12 -10
  163. package/testUtils/testPromise.ts +3 -0
  164. package/tsconfig.json +84 -2
  165. package/types/classnames.d.ts +39 -4
  166. package/types/classnames.d.ts.map +1 -0
  167. package/types/enforce/compose.d.ts +2 -126
  168. package/types/enforce/compose.d.ts.map +1 -0
  169. package/types/enforce/compounds.d.ts +2 -136
  170. package/types/enforce/compounds.d.ts.map +1 -0
  171. package/types/enforce/schema.d.ts +2 -144
  172. package/types/enforce/schema.d.ts.map +1 -0
  173. package/types/parser.d.ts +45 -10
  174. package/types/parser.d.ts.map +1 -0
  175. package/types/promisify.d.ts +36 -34
  176. package/types/promisify.d.ts.map +1 -0
  177. package/types/vest.d.ts +169 -224
  178. package/types/vest.d.ts.map +1 -0
  179. package/CHANGELOG.md +0 -87
  180. package/testUtils/expandStateRef.ts +0 -8
  181. package/testUtils/runCreateRef.ts +0 -10
  182. 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 };