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,137 @@
1
+ import wait from 'wait';
2
+
3
+ import { dummyTest } from '../../testUtils/testDummy';
4
+ import { TestPromise } from '../../testUtils/testPromise';
5
+
6
+ import * as vest from 'vest';
7
+
8
+ type SuiteParams = { skip?: string; skipGroup?: string };
9
+
10
+ const suite = () =>
11
+ vest.create(({ skip, skipGroup }: SuiteParams = {}) => {
12
+ vest.skip(skip);
13
+ vest.skip.group(skipGroup);
14
+
15
+ vest.group('group', () => {
16
+ dummyTest.failingAsync('field_1', { message: 'field_1_group_message' });
17
+ dummyTest.failingAsync('field_4', { message: 'field_4_group_message' });
18
+ });
19
+
20
+ dummyTest.failing('field_1', 'field_message_1');
21
+
22
+ dummyTest.failingAsync('field_2', {
23
+ time: 50,
24
+ message: 'rejection_message_1',
25
+ });
26
+
27
+ dummyTest.passing('field_2', 'field_message_2');
28
+
29
+ dummyTest.passingAsync('field_3', { message: 'field_message_3' });
30
+ dummyTest.failingAsync('field_3', { message: 'field_message_3' });
31
+ });
32
+
33
+ let validate: vest.Suite<({ skip, skipGroup }: SuiteParams) => void, string>;
34
+ let callback_1 = jest.fn(),
35
+ callback_2 = jest.fn(),
36
+ callback_3 = jest.fn(),
37
+ callback_4 = jest.fn(),
38
+ control = jest.fn();
39
+
40
+ describe('Stateful async tests', () => {
41
+ beforeEach(() => {
42
+ callback_1 = jest.fn();
43
+ callback_2 = jest.fn();
44
+ callback_3 = jest.fn();
45
+ callback_4 = jest.fn();
46
+ control = jest.fn();
47
+ validate = suite();
48
+ });
49
+
50
+ it('Should only run callbacks for last suite run', () =>
51
+ TestPromise(done => {
52
+ validate({}).done(callback_1).done('field_3', callback_2);
53
+ expect(callback_1).not.toHaveBeenCalled();
54
+ expect(callback_2).not.toHaveBeenCalled();
55
+ validate({}).done(callback_3).done('field_3', callback_4);
56
+ expect(callback_3).not.toHaveBeenCalled();
57
+ expect(callback_4).not.toHaveBeenCalled();
58
+ setTimeout(() => {
59
+ expect(callback_1).not.toHaveBeenCalled();
60
+ expect(callback_2).not.toHaveBeenCalled();
61
+ expect(callback_3).not.toHaveBeenCalled();
62
+ expect(callback_4).toHaveBeenCalled();
63
+ control();
64
+ });
65
+ setTimeout(() => {
66
+ expect(callback_1).not.toHaveBeenCalled();
67
+ expect(callback_2).not.toHaveBeenCalled();
68
+ expect(callback_3).toHaveBeenCalledTimes(1);
69
+ expect(control).toHaveBeenCalled();
70
+ done();
71
+ }, 50);
72
+ }));
73
+
74
+ it('Merges skipped validations from previous suite', () =>
75
+ TestPromise(done => {
76
+ const res = validate({ skipGroup: 'group', skip: 'field_3' });
77
+ expect(res.testCount).toBe(3);
78
+ expect(res.errorCount).toBe(1);
79
+ expect(res.warnCount).toBe(0);
80
+ expect(res.hasErrors('field_1')).toBe(true);
81
+ expect(res.tests.field_1.errorCount).toBe(1);
82
+ expect(res.hasErrors('field_2')).toBe(false);
83
+ expect(res.hasErrors('field_3')).toBe(false);
84
+ expect(res.hasErrors('field_4')).toBe(false);
85
+ expect(res).toMatchSnapshot();
86
+ setTimeout(() => {
87
+ const res = validate.get();
88
+
89
+ expect(res.testCount).toBe(3);
90
+ expect(res.errorCount).toBe(2);
91
+ expect(res.warnCount).toBe(0);
92
+ expect(res.tests.field_1.errorCount).toBe(1);
93
+ expect(res.hasErrors('field_2')).toBe(true);
94
+ expect(res.hasErrors('field_3')).toBe(false);
95
+ expect(res.hasErrors('field_4')).toBe(false);
96
+ expect(res).toMatchSnapshot();
97
+
98
+ validate({ skip: 'field_2' }).done(res => {
99
+ expect(res.testCount).toBe(7);
100
+ expect(res.errorCount).toBe(5);
101
+ expect(res.warnCount).toBe(0);
102
+ expect(res.tests.field_1.errorCount).toBe(2);
103
+ expect(res.hasErrors('field_2')).toBe(true);
104
+ expect(res.hasErrors('field_3')).toBe(true);
105
+ expect(res.hasErrors('field_4')).toBe(true);
106
+ expect(res).toMatchSnapshot();
107
+ done();
108
+ });
109
+ }, 50);
110
+ }));
111
+
112
+ it('Should discard of re-tested async tests', async () => {
113
+ const tests: Array<vest.IsolateTest> = [];
114
+ const control = jest.fn();
115
+ const suite = vest.create(() => {
116
+ tests.push(
117
+ vest.test('field_1', tests.length.toString(), async () => {
118
+ await wait(100);
119
+ throw new Error();
120
+ })
121
+ );
122
+ });
123
+ suite().done(() => {
124
+ control(0);
125
+ });
126
+ await wait(5);
127
+ suite().done(() => {
128
+ control(1);
129
+ });
130
+ await wait(100);
131
+ expect(control).toHaveBeenCalledTimes(1);
132
+ expect(control).toHaveBeenCalledWith(1);
133
+
134
+ expect(tests[0].isCanceled()).toBe(true);
135
+ expect(tests[1].isFailing()).toBe(true);
136
+ });
137
+ });
@@ -0,0 +1,155 @@
1
+ import { enforce } from 'n4s';
2
+
3
+ import * as vest from 'vest';
4
+
5
+ describe('Stateful behavior', () => {
6
+ let result;
7
+ const validate = genSuite();
8
+
9
+ test('Should merge skipped fields with previous values', () => {
10
+ result = validate({ only: 'field_1' });
11
+ expect(result.tests.field_1.errorCount).toBe(1);
12
+ expect(result.errorCount).toBe(1);
13
+ expect(Object.keys(result.tests)).toHaveLength(5); // including 4 skipped tests
14
+ expect(result.tests).toHaveProperty('field_1');
15
+ expect(result).toMatchSnapshot();
16
+
17
+ result = validate({ only: 'field_5' });
18
+ expect(result.errorCount).toBe(3);
19
+ expect(result.tests.field_1.errorCount).toBe(1);
20
+ expect(result.tests.field_5.errorCount).toBe(2);
21
+ expect(Object.keys(result.tests)).toHaveLength(5); // including 4 skipped tests
22
+ expect(result.tests).toHaveProperty('field_1');
23
+ expect(result.tests).toHaveProperty('field_5');
24
+ expect(result).toMatchSnapshot();
25
+
26
+ result = validate();
27
+ expect(result.errorCount).toBe(4);
28
+ expect(result.tests.field_1.errorCount).toBe(1);
29
+ expect(result.tests.field_2.errorCount).toBe(1);
30
+ expect(result.tests.field_4.warnCount).toBe(1);
31
+ expect(result.tests.field_5.errorCount).toBe(2);
32
+ expect(Object.keys(result.tests)).toHaveLength(5);
33
+ expect(result).toMatchSnapshot();
34
+ });
35
+ });
36
+
37
+ describe('more complex', () => {
38
+ const data: Record<string, string> = {};
39
+
40
+ it('Should run correctly', () => {
41
+ expect(suite.get().hasErrors()).toBe(false);
42
+ expect(suite.get()).toMatchSnapshot();
43
+
44
+ data.username = 'user_1';
45
+ suite(data, 'username');
46
+
47
+ expect(suite.get().hasErrors()).toBe(false);
48
+ expect(suite.get()).toMatchSnapshot();
49
+
50
+ suite(data, 'password');
51
+ expect(suite.get().hasErrors()).toBe(true);
52
+ expect(suite.get().tests.password).toMatchInlineSnapshot(`
53
+ {
54
+ "errorCount": 1,
55
+ "errors": [
56
+ "password is required",
57
+ ],
58
+ "testCount": 1,
59
+ "valid": false,
60
+ "warnCount": 0,
61
+ "warnings": [],
62
+ }
63
+ `);
64
+ expect(suite.get()).toMatchSnapshot();
65
+
66
+ suite(data, 'confirm');
67
+ expect(suite.get().tests.confirm).toMatchInlineSnapshot(`
68
+ {
69
+ "errorCount": 0,
70
+ "errors": [],
71
+ "testCount": 0,
72
+ "valid": false,
73
+ "warnCount": 0,
74
+ "warnings": [],
75
+ }
76
+ `);
77
+ expect(suite.get()).toMatchSnapshot();
78
+ expect(suite.get().hasErrors('password')).toBe(true);
79
+ expect(suite.get().hasErrors('confirm')).toBe(false);
80
+
81
+ data.password = '123456';
82
+ suite(data, 'password');
83
+ expect(suite.get().tests.confirm).toMatchInlineSnapshot(`
84
+ {
85
+ "errorCount": 0,
86
+ "errors": [],
87
+ "testCount": 0,
88
+ "valid": false,
89
+ "warnCount": 0,
90
+ "warnings": [],
91
+ }
92
+ `);
93
+ data.confirm = '123456';
94
+ suite(data, 'confirm');
95
+ expect(suite.get().hasErrors('password')).toBe(false);
96
+ expect(suite.get().hasErrors('confirm')).toBe(false);
97
+ expect(suite.get().tests.confirm).toMatchInlineSnapshot(`
98
+ {
99
+ "errorCount": 0,
100
+ "errors": [],
101
+ "testCount": 1,
102
+ "valid": true,
103
+ "warnCount": 0,
104
+ "warnings": [],
105
+ }
106
+ `);
107
+ });
108
+
109
+ const suite = vest.create(
110
+ (data: Record<string, unknown> = {}, only: string) => {
111
+ vest.only(only);
112
+
113
+ vest.test('username', 'username is required', () => {
114
+ enforce(data.username).isNotEmpty();
115
+ });
116
+
117
+ vest.test('username', 'username must be at least 3 characters', () => {
118
+ enforce(data.username).longerThanOrEquals(3);
119
+ });
120
+
121
+ vest.test('password', 'password is required', () => {
122
+ enforce(data.password).isNotEmpty();
123
+ });
124
+
125
+ vest.skipWhen(
126
+ draft => draft.hasErrors('password'),
127
+ () => {
128
+ vest.test('confirm', 'passwords do not match', () => {
129
+ enforce(data.confirm).equals(data.password);
130
+ });
131
+ }
132
+ );
133
+ }
134
+ );
135
+ });
136
+
137
+ function genSuite() {
138
+ return vest.create(({ only }: { only?: string | string[] } = {}) => {
139
+ vest.only(only);
140
+ vest.test('field_1', 'field_statement_1', () => false);
141
+ vest.test('field_2', 'field_statement_2', () => {
142
+ enforce(2).equals(3);
143
+ });
144
+ vest.test('field_3', 'field_statement_3', jest.fn());
145
+ vest.test('field_4', 'field_statement_4', () => {
146
+ vest.warn();
147
+ throw new Error();
148
+ });
149
+ vest.test('field_4', 'field_statement_4', () => {
150
+ vest.warn();
151
+ });
152
+ vest.test('field_5', 'field_statement_5', () => false);
153
+ vest.test('field_5', 'field_statement_6', () => false);
154
+ });
155
+ }
@@ -0,0 +1,288 @@
1
+ import { CB } from 'vest-utils';
2
+ import { TDeferThrow } from 'vest-utils/src/deferThrow';
3
+
4
+ import { TVestMock } from '../../testUtils/TVestMock';
5
+ import mockThrowError from '../../testUtils/mockThrowError';
6
+ import { TDummyTest } from '../../testUtils/testDummy';
7
+
8
+ import { IsolateTypes } from 'IsolateTypes';
9
+
10
+ describe('isolate', () => {
11
+ let vest: TVestMock;
12
+ let firstRun = true;
13
+ // eslint-disable-next-line no-unused-expressions
14
+ require('IsolateTest').IsolateTest;
15
+ let Isolate = require('isolate').Isolate;
16
+ let dummyTest: TDummyTest;
17
+ let deferThrow: TDeferThrow;
18
+
19
+ beforeEach(() => {
20
+ firstRun = true;
21
+ const mock = mockThrowError();
22
+ deferThrow = mock.deferThrow;
23
+ // eslint-disable-next-line no-unused-expressions
24
+ require('IsolateTest').IsolateTest;
25
+ Isolate = require('isolate').Isolate;
26
+ vest = mock.vest;
27
+ dummyTest = require('../../testUtils/testDummy').dummyTest;
28
+ });
29
+
30
+ afterEach(() => {
31
+ jest.resetModules();
32
+ jest.resetAllMocks();
33
+ });
34
+
35
+ describe('Base behavior', () => {
36
+ it("Should throw an error if the callback isn't a function", () => {
37
+ expect(() => Isolate.create({}, 'not a function')).toThrow();
38
+ });
39
+
40
+ it('Should retain test results between runs', () => {
41
+ const f1 = jest.fn(() => false);
42
+ const f2 = jest.fn(() => false);
43
+ const suite = genSuite(() => {
44
+ vest.skipWhen(!firstRun, () => {
45
+ Isolate.create({ type: IsolateTypes.DEFAULT }, () => {
46
+ vest.test('f1', f1);
47
+ vest.test('f2', f2);
48
+ });
49
+ });
50
+ });
51
+
52
+ suite();
53
+ expect(suite.get().hasErrors('f1')).toBe(true);
54
+ expect(suite.get().hasErrors('f2')).toBe(true);
55
+ expect(f1).toHaveBeenCalledTimes(1);
56
+ expect(f2).toHaveBeenCalledTimes(1);
57
+ suite();
58
+ expect(suite.get().hasErrors('f1')).toBe(true);
59
+ expect(suite.get().hasErrors('f2')).toBe(true);
60
+ expect(f1).toHaveBeenCalledTimes(1);
61
+ expect(f2).toHaveBeenCalledTimes(1);
62
+ });
63
+ });
64
+
65
+ describe('When order changes within the isolate', () => {
66
+ it('Should contain test order changes within the isolate', () => {
67
+ const suite = genSuite(() => {
68
+ dummyTest.failing('f1');
69
+
70
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
71
+ dummyTest.failing('f2');
72
+ if (!firstRun) {
73
+ dummyTest.failing('f3');
74
+ dummyTest.failing('f4');
75
+ }
76
+ });
77
+
78
+ vest.skipWhen(!firstRun, () => {
79
+ dummyTest.failing('f5');
80
+ });
81
+ });
82
+
83
+ suite();
84
+ expect(suite.get().hasErrors('f1')).toBe(true);
85
+ expect(suite.get().hasErrors('f2')).toBe(true);
86
+ expect(suite.get().hasErrors('f3')).toBe(false);
87
+ expect(suite.get().hasErrors('f4')).toBe(false);
88
+ expect(suite.get().hasErrors('f5')).toBe(true);
89
+ expect(suite.get().tests.f1).toBeDefined();
90
+ expect(suite.get().tests.f2).toBeDefined();
91
+ expect(suite.get().tests.f3).toBeUndefined();
92
+ expect(suite.get().tests.f4).toBeUndefined();
93
+ expect(suite.get().tests.f5).toBeDefined();
94
+
95
+ suite();
96
+ expect(suite.get().hasErrors('f1')).toBe(true);
97
+ expect(suite.get().hasErrors('f2')).toBe(true);
98
+ expect(suite.get().hasErrors('f3')).toBe(true);
99
+ expect(suite.get().hasErrors('f4')).toBe(true);
100
+
101
+ // without "isolate" this assertion would fail
102
+ // because the test would have been overwritten
103
+ expect(suite.get().hasErrors('f5')).toBe(true);
104
+
105
+ expect(suite.get().tests.f1).toBeDefined();
106
+ expect(suite.get().tests.f2).toBeDefined();
107
+ expect(suite.get().tests.f3).toBeDefined();
108
+ expect(suite.get().tests.f4).toBeDefined();
109
+ expect(suite.get().tests.f5).toBeDefined();
110
+ });
111
+
112
+ it('Should only retain the state of the unmoved state before the order index', () => {
113
+ const suite = genSuite(() => {
114
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
115
+ vest.skipWhen(!firstRun, () => {
116
+ dummyTest.failing('f1');
117
+ });
118
+ if (!firstRun) {
119
+ dummyTest.failing('f2');
120
+ }
121
+ vest.skipWhen(!firstRun, () => {
122
+ dummyTest.failing('f3');
123
+ });
124
+ });
125
+
126
+ suite();
127
+ expect(suite.get().hasErrors('f1')).toBe(true);
128
+ expect(suite.get().hasErrors('f2')).toBe(false);
129
+ expect(suite.get().hasErrors('f3')).toBe(true);
130
+ expect(suite.get().tests.f1).toBeDefined();
131
+ expect(suite.get().tests.f2).toBeUndefined();
132
+ expect(suite.get().tests.f3).toBeDefined();
133
+
134
+ suite();
135
+ expect(suite.get().hasErrors('f1')).toBe(true);
136
+ expect(suite.get().hasErrors('f2')).toBe(true);
137
+ expect(suite.get().hasErrors('f3')).toBe(false);
138
+ expect(suite.get().tests.f1).toBeDefined();
139
+ expect(suite.get().tests.f2).toBeDefined();
140
+ expect(suite.get().tests.f3).toBeDefined();
141
+ });
142
+ });
143
+ });
144
+
145
+ describe('When test order changes before the isolate opens', () => {
146
+ it('Should clean up follow up tests. Reregister', () => {
147
+ const suite = genSuite(() => {
148
+ dummyTest.failing('f1');
149
+ if (!firstRun) {
150
+ dummyTest.failing('f6');
151
+ }
152
+
153
+ // this way we can tell if the state is kept or discarded.
154
+ // if the state is kept, they should be invalid. Otherwise
155
+ // they should be untested.
156
+ vest.skipWhen(!firstRun, () => {
157
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
158
+ dummyTest.failing('f2');
159
+ dummyTest.failing('f3');
160
+ dummyTest.failing('f4');
161
+ });
162
+
163
+ dummyTest.failing('f5');
164
+ });
165
+ });
166
+
167
+ suite();
168
+ expect(suite.get().hasErrors('f1')).toBe(true);
169
+ expect(suite.get().hasErrors('f2')).toBe(true);
170
+ expect(suite.get().hasErrors('f3')).toBe(true);
171
+ expect(suite.get().hasErrors('f4')).toBe(true);
172
+ expect(suite.get().hasErrors('f5')).toBe(true);
173
+ expect(suite.get().hasErrors('f6')).toBe(false);
174
+ expect(suite.get().tests.f1).toBeDefined();
175
+ expect(suite.get().tests.f2).toBeDefined();
176
+ expect(suite.get().tests.f3).toBeDefined();
177
+ expect(suite.get().tests.f4).toBeDefined();
178
+ expect(suite.get().tests.f5).toBeDefined();
179
+ expect(suite.get().tests.f6).toBeUndefined();
180
+
181
+ suite();
182
+ expect(suite.get().hasErrors('f1')).toBe(true);
183
+ expect(suite.get().hasErrors('f2')).toBe(false);
184
+ expect(suite.get().hasErrors('f3')).toBe(false);
185
+ expect(suite.get().hasErrors('f4')).toBe(false);
186
+ expect(suite.get().hasErrors('f5')).toBe(false);
187
+ expect(suite.get().hasErrors('f6')).toBe(true);
188
+ expect(suite.get().tests.f1).toBeDefined();
189
+ expect(suite.get().tests.f2).toBeDefined();
190
+ expect(suite.get().tests.f3).toBeDefined();
191
+ expect(suite.get().tests.f4).toBeDefined();
192
+ expect(suite.get().tests.f5).toBeDefined();
193
+ expect(suite.get().tests.f6).toBeDefined();
194
+ });
195
+ });
196
+
197
+ describe('When an incorrect isolate is encountered', () => {
198
+ it('Should replace isolate completely', () => {
199
+ const suite = genSuite(() => {
200
+ if (firstRun) {
201
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
202
+ dummyTest.failing('f1');
203
+ });
204
+ } else {
205
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
206
+ dummyTest.failing('f2');
207
+ });
208
+ }
209
+ });
210
+
211
+ suite();
212
+ expect(suite.get().hasErrors('f1')).toBe(true);
213
+ expect(suite.get().hasErrors('f2')).toBe(false);
214
+ expect(suite.get().tests.f1).toBeDefined();
215
+ expect(suite.get().tests.f2).toBeUndefined();
216
+ suite();
217
+ expect(suite.get().hasErrors('f1')).toBe(false);
218
+ expect(suite.get().hasErrors('f2')).toBe(true);
219
+ expect(suite.get().tests.f1).toBeUndefined();
220
+ expect(suite.get().tests.f2).toBeDefined();
221
+ });
222
+ });
223
+
224
+ describe('When an isolate is present when a test was expected', () => {
225
+ it('Should erase test history, and re-register', () => {
226
+ const suite = genSuite(() => {
227
+ if (firstRun) {
228
+ dummyTest.failing('f1');
229
+ } else {
230
+ Isolate.create({ type: IsolateTypes.EACH }, () => {
231
+ dummyTest.failing('f2');
232
+ });
233
+ }
234
+ });
235
+
236
+ suite();
237
+ expect(suite.get().hasErrors('f1')).toBe(true);
238
+ expect(suite.get().hasErrors('f2')).toBe(false);
239
+ expect(suite.get().tests.f1).toBeDefined();
240
+ expect(suite.get().tests.f2).toBeUndefined();
241
+ suite();
242
+ expect(suite.get().hasErrors('f1')).toBe(false);
243
+ expect(suite.get().hasErrors('f2')).toBe(true);
244
+ expect(suite.get().tests.f1).toBeUndefined();
245
+ expect(suite.get().tests.f2).toBeDefined();
246
+ });
247
+
248
+ describe('Errors', () => {
249
+ it('should throw a deferred error when the tests are out of order', () => {
250
+ const suite = genSuite(() => {
251
+ Isolate.create({ type: IsolateTypes.GROUP }, () => {
252
+ dummyTest.failing(firstRun ? 'f1' : 'f2');
253
+ });
254
+ });
255
+
256
+ suite();
257
+ expect(deferThrow).toHaveBeenCalledTimes(0);
258
+ suite();
259
+ expect(deferThrow).toHaveBeenCalledTimes(1);
260
+ expect(deferThrow).toHaveBeenCalledWith(
261
+ expect.stringContaining(
262
+ 'Vest Critical Error: Tests called in different order than previous run'
263
+ )
264
+ );
265
+ });
266
+
267
+ it('Should allow unordered tests within an each isolate', () => {
268
+ const suite = genSuite(() => {
269
+ Isolate.create(IsolateTypes.EACH, () => {
270
+ dummyTest.failing(firstRun ? 'f1' : 'f2');
271
+ });
272
+ });
273
+
274
+ suite();
275
+ expect(deferThrow).toHaveBeenCalledTimes(0);
276
+ suite();
277
+ expect(deferThrow).toHaveBeenCalledTimes(0);
278
+ });
279
+ });
280
+ });
281
+
282
+ function genSuite(cb: CB) {
283
+ return vest.create(() => {
284
+ cb();
285
+ firstRun = false;
286
+ });
287
+ }
288
+ });
@@ -0,0 +1,41 @@
1
+ import * as vest from 'vest';
2
+
3
+ describe('state refill', () => {
4
+ it('Should refill test state according to the execution order', () => {
5
+ const suiteStates: vest.SuiteResult<string>[][] = [];
6
+ const suite = vest.create(() => {
7
+ const currentRun = [suite.get()];
8
+ expect(suite.get().hasErrors('field1')).toBe(false);
9
+ vest.test('field1', () => false);
10
+ expect(suite.get().tests.field1.errorCount).toBe(1);
11
+ currentRun.push(suite.get());
12
+ vest.test('field1', () => false);
13
+ expect(suite.get().tests.field1.errorCount).toBe(2);
14
+ currentRun.push(suite.get());
15
+ expect(suite.get().hasErrors('field2')).toBe(false);
16
+ vest.test('field2', () => false);
17
+ currentRun.push(suite.get());
18
+ vest.test('field2', () => true);
19
+ expect(suite.get().tests.field2.errorCount).toBe(1);
20
+ currentRun.push(suite.get());
21
+ expect(suite.get().hasErrors('field3')).toBe(false);
22
+ vest.test('field3', () => undefined);
23
+ expect(suite.get().hasErrors('field3')).toBe(false);
24
+ expect(suite.get().tests.field3.errorCount).toBe(0);
25
+ currentRun.push(suite.get());
26
+ expect(suite.get().hasWarnings('field4')).toBe(false);
27
+ vest.test('field4', () => {
28
+ vest.warn();
29
+ return false;
30
+ });
31
+ expect(suite.get().hasWarnings('field4')).toBe(true);
32
+ currentRun.push(suite.get());
33
+ suiteStates.push(currentRun);
34
+ });
35
+
36
+ expect(suite()).isDeepCopyOf(suite());
37
+ suiteStates[0].forEach((suiteState, i) => {
38
+ expect(suiteState).isDeepCopyOf(suiteStates[1][i]);
39
+ });
40
+ });
41
+ });
@@ -0,0 +1,64 @@
1
+ import * as walker from 'walker';
2
+
3
+ import { useAvailableSuiteRoot } from 'PersistedContext';
4
+ import type { Isolate } from 'isolate';
5
+
6
+ export class SuiteWalker {
7
+ static walk(
8
+ callback: (isolate: Isolate, breakout: () => void) => void,
9
+ visitOnly?: walker.VisitOnlyPredicate
10
+ ): void {
11
+ const root = useAvailableSuiteRoot();
12
+
13
+ if (!root) return;
14
+
15
+ walker.walk(root, callback, visitOnly);
16
+ }
17
+
18
+ static some(
19
+ predicate: (node: Isolate) => boolean,
20
+ visitOnly?: walker.VisitOnlyPredicate
21
+ ): boolean {
22
+ const root = useAvailableSuiteRoot();
23
+
24
+ if (!root) return false;
25
+ return walker.some(root, predicate, visitOnly);
26
+ }
27
+
28
+ static has(match: walker.VisitOnlyPredicate): boolean {
29
+ const root = useAvailableSuiteRoot();
30
+
31
+ if (!root) return false;
32
+ return walker.has(root, match);
33
+ }
34
+
35
+ static find(
36
+ predicate: (node: Isolate) => boolean,
37
+ visitOnly?: walker.VisitOnlyPredicate
38
+ ): Isolate | null {
39
+ const root = useAvailableSuiteRoot();
40
+
41
+ if (!root) return null;
42
+ return walker.find(root, predicate, visitOnly);
43
+ }
44
+
45
+ static every(
46
+ predicate: (node: Isolate) => boolean,
47
+ visitOnly?: walker.VisitOnlyPredicate
48
+ ): boolean {
49
+ const root = useAvailableSuiteRoot();
50
+
51
+ if (!root) return false;
52
+ return walker.every(root, predicate, visitOnly);
53
+ }
54
+
55
+ static pluck(
56
+ predicate: (node: Isolate) => boolean,
57
+ visitOnly?: walker.VisitOnlyPredicate
58
+ ): void {
59
+ const root = useAvailableSuiteRoot();
60
+
61
+ if (!root) return;
62
+ return walker.pluck(root, predicate, visitOnly);
63
+ }
64
+ }