vest-utils 1.5.0 → 2.0.1

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 (157) hide show
  1. package/README.md +7 -2
  2. package/dist/chunk-CLMFDpHK.mjs +18 -0
  3. package/dist/exports/minifyObject.cjs +114 -0
  4. package/dist/exports/minifyObject.cjs.map +1 -0
  5. package/dist/exports/minifyObject.mjs +113 -0
  6. package/dist/exports/minifyObject.mjs.map +1 -0
  7. package/dist/exports/standardSchemaSpec.cjs +0 -0
  8. package/dist/exports/standardSchemaSpec.mjs +1 -0
  9. package/dist/isEmpty-BBxAFjjm.mjs +103 -0
  10. package/dist/isEmpty-BBxAFjjm.mjs.map +1 -0
  11. package/dist/isEmpty-BuEa-96Q.cjs +235 -0
  12. package/dist/isEmpty-BuEa-96Q.cjs.map +1 -0
  13. package/dist/vest-utils.cjs +510 -0
  14. package/dist/vest-utils.cjs.map +1 -0
  15. package/dist/vest-utils.mjs +421 -0
  16. package/dist/vest-utils.mjs.map +1 -0
  17. package/minifyObject/package.json +12 -8
  18. package/package.json +43 -58
  19. package/src/Brand.ts +9 -0
  20. package/src/IO.ts +2 -0
  21. package/src/Predicates.ts +13 -0
  22. package/src/Result.ts +121 -0
  23. package/src/SimpleStateMachine.ts +157 -0
  24. package/src/StringObject.ts +6 -0
  25. package/src/__tests__/Architecture.test.ts +69 -0
  26. package/src/__tests__/Predicates.test.ts +118 -0
  27. package/src/__tests__/Result.test.ts +284 -0
  28. package/src/__tests__/SimpleStateMachine.test.ts +425 -0
  29. package/src/__tests__/StringObject.test.ts +18 -0
  30. package/src/__tests__/asArray.test.ts +14 -0
  31. package/src/__tests__/bindNot.test.ts +39 -0
  32. package/src/__tests__/bus.test.ts +135 -0
  33. package/src/__tests__/cache.test.ts +139 -0
  34. package/src/__tests__/callEach.test.ts +20 -0
  35. package/src/__tests__/defaultTo.test.ts +52 -0
  36. package/src/__tests__/deferThrow.test.ts +26 -0
  37. package/src/__tests__/either.test.ts +17 -0
  38. package/src/__tests__/freezeAssign.test.ts +24 -0
  39. package/src/__tests__/greaterThan.test.ts +68 -0
  40. package/src/__tests__/invariant.test.ts +47 -0
  41. package/src/__tests__/isArray.test.ts +16 -0
  42. package/src/__tests__/isBoolean.test.ts +16 -0
  43. package/src/__tests__/isEmpty.test.ts +55 -0
  44. package/src/__tests__/isEmptySet.test.ts +22 -0
  45. package/src/__tests__/isNull.test.ts +26 -0
  46. package/src/__tests__/isNumeric.test.ts +27 -0
  47. package/src/__tests__/isPositive.test.ts +38 -0
  48. package/src/__tests__/isPromise.test.ts +17 -0
  49. package/src/__tests__/isString.test.ts +13 -0
  50. package/src/__tests__/isUndefined.test.ts +27 -0
  51. package/src/__tests__/isUnsafeKey.test.ts +22 -0
  52. package/src/__tests__/lengthEquals.test.ts +58 -0
  53. package/src/__tests__/longerThan.test.ts +58 -0
  54. package/src/__tests__/mapFirst.test.ts +31 -0
  55. package/src/__tests__/nonnullish.test.ts +25 -0
  56. package/src/__tests__/noop.test.ts +12 -0
  57. package/src/__tests__/numberEquals.test.ts +67 -0
  58. package/src/__tests__/optionalFunctionValue.test.ts +29 -0
  59. package/src/__tests__/seq.test.ts +29 -0
  60. package/src/__tests__/text.test.ts +41 -0
  61. package/src/__tests__/tinyState.test.ts +68 -0
  62. package/src/__tests__/toNumber.test.ts +39 -0
  63. package/src/__tests__/vest-utils.test.ts +13 -0
  64. package/src/__tests__/withCatch.test.ts +17 -0
  65. package/src/__tests__/withResolvers.test.ts +45 -0
  66. package/src/asArray.ts +3 -0
  67. package/src/assign.ts +1 -0
  68. package/src/bindNot.ts +3 -0
  69. package/src/bus.ts +52 -0
  70. package/src/cache.ts +68 -0
  71. package/src/callEach.ts +5 -0
  72. package/src/defaultTo.ts +9 -0
  73. package/src/deferThrow.ts +7 -0
  74. package/src/dynamicValue.ts +9 -0
  75. package/src/either.ts +3 -0
  76. package/src/exports/__tests__/minifyObject.security.test.ts +65 -0
  77. package/src/exports/__tests__/minifyObject.test.ts +281 -0
  78. package/src/exports/minifyObject.ts +198 -0
  79. package/src/exports/standardSchemaSpec.ts +70 -0
  80. package/src/freezeAssign.ts +5 -0
  81. package/src/globals.d.ts +3 -0
  82. package/src/greaterThan.ts +8 -0
  83. package/src/hasOwnProperty.ts +9 -0
  84. package/src/invariant.ts +19 -0
  85. package/src/isArrayValue.ts +11 -0
  86. package/src/isBooleanValue.ts +3 -0
  87. package/src/isEmpty.ts +18 -0
  88. package/src/isEmptySet.ts +15 -0
  89. package/src/isFunction.ts +5 -0
  90. package/src/isNull.ts +7 -0
  91. package/src/isNullish.ts +10 -0
  92. package/src/isNumeric.ts +11 -0
  93. package/src/isPositive.ts +5 -0
  94. package/src/isPromise.ts +5 -0
  95. package/src/isStringValue.ts +3 -0
  96. package/src/isUndefined.ts +7 -0
  97. package/src/isUnsafeKey.ts +3 -0
  98. package/src/lengthEquals.ts +11 -0
  99. package/src/longerThan.ts +8 -0
  100. package/src/mapFirst.ts +25 -0
  101. package/src/nonnullish.ts +9 -0
  102. package/src/noop.ts +1 -0
  103. package/src/numberEquals.ts +11 -0
  104. package/src/seq.ts +16 -0
  105. package/src/text.ts +20 -0
  106. package/src/tinyState.ts +28 -0
  107. package/src/toNumber.ts +11 -0
  108. package/src/utilityTypes.ts +25 -0
  109. package/src/valueIsObject.ts +5 -0
  110. package/src/vest-utils.ts +73 -0
  111. package/src/withCatch.ts +11 -0
  112. package/src/withResolvers.ts +33 -0
  113. package/standardSchemaSpec/package.json +14 -0
  114. package/types/{minifyObject.d.ts → exports/minifyObject.d.cts} +4 -2
  115. package/types/exports/minifyObject.d.cts.map +1 -0
  116. package/types/exports/minifyObject.d.mts +7 -0
  117. package/types/exports/minifyObject.d.mts.map +1 -0
  118. package/types/exports/standardSchemaSpec.d.cts +59 -0
  119. package/types/exports/standardSchemaSpec.d.cts.map +1 -0
  120. package/types/exports/standardSchemaSpec.d.mts +59 -0
  121. package/types/exports/standardSchemaSpec.d.mts.map +1 -0
  122. package/types/vest-utils.d.cts +296 -0
  123. package/types/vest-utils.d.cts.map +1 -0
  124. package/types/vest-utils.d.mts +295 -0
  125. package/types/vest-utils.d.mts.map +1 -0
  126. package/types/vest-utils.d.ts +245 -143
  127. package/vitest.config.ts +9 -45
  128. package/dist/cjs/minifyObject.development.js +0 -217
  129. package/dist/cjs/minifyObject.development.js.map +0 -1
  130. package/dist/cjs/minifyObject.js +0 -6
  131. package/dist/cjs/minifyObject.production.js +0 -2
  132. package/dist/cjs/minifyObject.production.js.map +0 -1
  133. package/dist/cjs/package.json +0 -1
  134. package/dist/cjs/vest-utils.development.js +0 -378
  135. package/dist/cjs/vest-utils.development.js.map +0 -1
  136. package/dist/cjs/vest-utils.js +0 -6
  137. package/dist/cjs/vest-utils.production.js +0 -2
  138. package/dist/cjs/vest-utils.production.js.map +0 -1
  139. package/dist/es/minifyObject.development.js +0 -214
  140. package/dist/es/minifyObject.development.js.map +0 -1
  141. package/dist/es/minifyObject.production.js +0 -2
  142. package/dist/es/minifyObject.production.js.map +0 -1
  143. package/dist/es/package.json +0 -1
  144. package/dist/es/vest-utils.development.js +0 -330
  145. package/dist/es/vest-utils.development.js.map +0 -1
  146. package/dist/es/vest-utils.production.js +0 -2
  147. package/dist/es/vest-utils.production.js.map +0 -1
  148. package/dist/umd/minifyObject.development.js +0 -223
  149. package/dist/umd/minifyObject.development.js.map +0 -1
  150. package/dist/umd/minifyObject.production.js +0 -2
  151. package/dist/umd/minifyObject.production.js.map +0 -1
  152. package/dist/umd/vest-utils.development.js +0 -384
  153. package/dist/umd/vest-utils.development.js.map +0 -1
  154. package/dist/umd/vest-utils.production.js +0 -2
  155. package/dist/umd/vest-utils.production.js.map +0 -1
  156. package/types/minifyObject.d.ts.map +0 -1
  157. package/types/vest-utils.d.ts.map +0 -1
@@ -0,0 +1,284 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+
3
+ import { isFailure, isResult, isSuccess, makeResult, unwrap } from '../Result';
4
+
5
+ describe('Result', () => {
6
+ describe('makeResult', () => {
7
+ describe('Ok', () => {
8
+ it('should return a Success result', () => {
9
+ const result = makeResult.Ok(1);
10
+ expect(result.type).toBe('ok');
11
+ expect(result.value).toBe(1);
12
+ });
13
+
14
+ it('should have correct methods', () => {
15
+ const result = makeResult.Ok(1);
16
+ expect(typeof result.map).toBe('function');
17
+ expect(typeof result.chain).toBe('function');
18
+ expect(typeof result.mapError).toBe('function');
19
+ expect(typeof result.match).toBe('function');
20
+ });
21
+ });
22
+
23
+ describe('Err', () => {
24
+ it('should return a Failure result', () => {
25
+ const result = makeResult.Err('error');
26
+ expect(result.type).toBe('err');
27
+ expect(result.error).toBe('error');
28
+ });
29
+
30
+ it('should have correct methods', () => {
31
+ const result = makeResult.Err('error');
32
+ expect(typeof result.map).toBe('function');
33
+ expect(typeof result.chain).toBe('function');
34
+ expect(typeof result.mapError).toBe('function');
35
+ expect(typeof result.match).toBe('function');
36
+ });
37
+ });
38
+ });
39
+
40
+ describe('isResult', () => {
41
+ it('should return true for Success result', () => {
42
+ expect(isResult(makeResult.Ok(1))).toBe(true);
43
+ });
44
+
45
+ it('should return true for Failure result', () => {
46
+ expect(isResult(makeResult.Err('error'))).toBe(true);
47
+ });
48
+
49
+ it('should return false for non-result objects', () => {
50
+ expect(isResult({})).toBe(false);
51
+ expect(isResult(null)).toBe(false);
52
+ expect(isResult(undefined)).toBe(false);
53
+ expect(isResult(1)).toBe(false);
54
+ expect(isResult('string')).toBe(false);
55
+ expect(isResult({ type: 'ok' })).toBe(false); // Missing value
56
+ expect(isResult({ type: 'err' })).toBe(false); // Missing error
57
+ expect(isResult({ value: 1 })).toBe(false); // Missing type
58
+ });
59
+ });
60
+
61
+ describe('isSuccess', () => {
62
+ it('should return true for Success result', () => {
63
+ expect(isSuccess(makeResult.Ok(1))).toBe(true);
64
+ });
65
+
66
+ it('should return false for Failure result', () => {
67
+ expect(isSuccess(makeResult.Err('error'))).toBe(false);
68
+ });
69
+ });
70
+
71
+ describe('isFailure', () => {
72
+ it('should return true for Failure result', () => {
73
+ expect(isFailure(makeResult.Err('error'))).toBe(true);
74
+ });
75
+
76
+ it('should return false for Success result', () => {
77
+ expect(isFailure(makeResult.Ok(1))).toBe(false);
78
+ });
79
+ });
80
+
81
+ describe('unwrap', () => {
82
+ it('should return value if result is Success', () => {
83
+ const result = makeResult.Ok(100);
84
+ expect(unwrap(result)).toBe(100);
85
+ expect(result.unwrap()).toBe(100);
86
+ });
87
+
88
+ it('should throw error if result is Failure', () => {
89
+ const error = new Error('fail');
90
+ const result = makeResult.Err(error);
91
+ expect(() => unwrap(result)).toThrow(error);
92
+ expect(() => result.unwrap()).toThrow(error);
93
+ });
94
+
95
+ it('should throw Error object if failure contains non-Error', () => {
96
+ const result = makeResult.Err('string error');
97
+ expect(() => unwrap(result)).toThrow('string error');
98
+ expect(() => result.unwrap()).toThrow('string error');
99
+ try {
100
+ result.unwrap();
101
+ } catch (e) {
102
+ expect(e).toBeInstanceOf(Error);
103
+ expect((e as Error).message).toBe('string error');
104
+ }
105
+ });
106
+ });
107
+
108
+ describe('unwrapOr', () => {
109
+ it('should return value if result is Success', () => {
110
+ const result = makeResult.Ok(100);
111
+ expect(result.unwrapOr(200)).toBe(100);
112
+ });
113
+
114
+ it('should return default value if result is Failure', () => {
115
+ const result = makeResult.Err<number>('error');
116
+ expect(result.unwrapOr(200)).toBe(200);
117
+ });
118
+ });
119
+
120
+ describe('Success methods', () => {
121
+ describe('map', () => {
122
+ it('should transform the value', () => {
123
+ const result = makeResult.Ok(1).map(x => x + 1);
124
+ expect(unwrap(result)).toBe(2);
125
+ });
126
+ });
127
+
128
+ describe('chain', () => {
129
+ it('should chain with another Result', () => {
130
+ const result = makeResult.Ok(1).chain(x => makeResult.Ok(x + 1));
131
+ expect(unwrap(result)).toBe(2);
132
+ });
133
+
134
+ it('should chain with a Failure', () => {
135
+ const result = makeResult.Ok(1).chain(() => makeResult.Err('fail'));
136
+ expect(isFailure(result)).toBe(true);
137
+ expect((result as any).error).toBe('fail');
138
+ });
139
+ });
140
+
141
+ describe('mapError', () => {
142
+ it('should not transform the error (no-op for Success)', () => {
143
+ const result = makeResult.Ok(1).mapError(() => 'new error');
144
+ expect(unwrap(result)).toBe(1);
145
+ });
146
+ });
147
+
148
+ describe('match', () => {
149
+ it('should call ok handler', () => {
150
+ const result = makeResult.Ok(1);
151
+ const output = result.match({
152
+ ok: val => `ok: ${val}`,
153
+ err: err => `err: ${err}`,
154
+ });
155
+ expect(output).toBe('ok: 1');
156
+ });
157
+ });
158
+ });
159
+
160
+ describe('Failure methods', () => {
161
+ describe('map', () => {
162
+ it('should not transform the value (no-op for Failure)', () => {
163
+ const result = makeResult.Err('error').map((x: any) => x + 1);
164
+ expect(isFailure(result)).toBe(true);
165
+ expect((result as any).error).toBe('error');
166
+ });
167
+ });
168
+
169
+ describe('chain', () => {
170
+ it('should not call the function (no-op for Failure)', () => {
171
+ const fn = vi.fn();
172
+ const result = makeResult.Err('error').chain(fn);
173
+ expect(fn).not.toHaveBeenCalled();
174
+ expect(isFailure(result)).toBe(true);
175
+ });
176
+ });
177
+
178
+ describe('mapError', () => {
179
+ it('should transform the error', () => {
180
+ const result = makeResult.Err('error').mapError(e => e.toUpperCase());
181
+ expect(isFailure(result)).toBe(true);
182
+ expect((result as any).error).toBe('ERROR');
183
+ });
184
+ });
185
+
186
+ describe('match', () => {
187
+ it('should call err handler', () => {
188
+ const result = makeResult.Err('error');
189
+ const output = result.match({
190
+ ok: val => `ok: ${val}`,
191
+ err: err => `err: ${err}`,
192
+ });
193
+ expect(output).toBe('err: error');
194
+ });
195
+ });
196
+ });
197
+
198
+ describe('Edge Cases: Nullish values', () => {
199
+ it('should handle null as a valid Success value', () => {
200
+ const result = makeResult.Ok(null);
201
+ expect(isSuccess(result)).toBe(true);
202
+ expect(unwrap(result)).toBeNull();
203
+ });
204
+
205
+ it('should handle undefined as a valid Success value', () => {
206
+ const result = makeResult.Ok(undefined);
207
+ expect(isSuccess(result)).toBe(true);
208
+ expect(unwrap(result)).toBeUndefined();
209
+ });
210
+
211
+ it('should allow mapping over null values', () => {
212
+ const result = makeResult
213
+ .Ok(null)
214
+ .map(val => (val === null ? 'was null' : 'not null'));
215
+ expect(unwrap(result)).toBe('was null');
216
+ });
217
+ });
218
+
219
+ describe('Control Flow: Exceptions', () => {
220
+ it('should NOT catch errors thrown inside map (Sync/Pure behavior)', () => {
221
+ const result = makeResult.Ok(1);
222
+
223
+ // If your architecture intends to catch this, change .toThrow() to checking for Err
224
+ expect(() => {
225
+ result.map(() => {
226
+ throw new Error('Boom');
227
+ });
228
+ }).toThrow('Boom');
229
+ });
230
+
231
+ it('should NOT catch errors thrown inside chain', () => {
232
+ const result = makeResult.Ok(1);
233
+
234
+ expect(() => {
235
+ result.chain(() => {
236
+ throw new Error('Boom');
237
+ });
238
+ }).toThrow('Boom');
239
+ });
240
+ });
241
+
242
+ describe('isResult Edge Cases', () => {
243
+ it('should return false if type discriminator is invalid', () => {
244
+ // Has correct shape keys, but wrong 'type' value
245
+ const fakeResult = { type: 'banana', value: 1 };
246
+ expect(isResult(fakeResult)).toBe(false);
247
+ });
248
+
249
+ it('should return false for extra properties mimicking result', () => {
250
+ // Depends on how strict your guard is.
251
+ // Usually, duck typing accepts this, but good to know.
252
+ const complicatedObj = { type: 'ok', value: 1, extra: 'stuff' };
253
+ expect(isResult(complicatedObj)).toBe(true); // Should likely be true
254
+ });
255
+ });
256
+
257
+ describe('Integration: Pipelining', () => {
258
+ it('should handle a sequence of maps and chains', () => {
259
+ const result = makeResult
260
+ .Ok(10)
261
+ .map(x => x * 2) // 20
262
+ .chain(x => makeResult.Ok(x + 5)) // 25
263
+ .mapError(() => 'new error') // Ignored
264
+ .map(x => `Value: ${x}`); // "Value: 25"
265
+
266
+ expect(unwrap(result)).toBe('Value: 25');
267
+ });
268
+
269
+ it('should short-circuit the pipeline on first error', () => {
270
+ const fn = vi.fn();
271
+
272
+ const result = makeResult
273
+ .Ok(10)
274
+ .map(x => x * 2) // 20
275
+ .chain(() => makeResult.Err('First Failure')) // Breaks here
276
+ .map(fn) // Should skip
277
+ .chain(x => makeResult.Ok(x)); // Should skip
278
+
279
+ expect(fn).not.toHaveBeenCalled();
280
+ expect(isFailure(result)).toBe(true);
281
+ expect((result as any).error).toBe('First Failure');
282
+ });
283
+ });
284
+ });
@@ -0,0 +1,425 @@
1
+ import { describe, test, it, expect } from 'vitest';
2
+
3
+ import { unwrap, isFailure, isSuccess } from '../Result';
4
+ import { StateMachine } from '../SimpleStateMachine';
5
+
6
+ describe('SimpleStateMachine', () => {
7
+ test('sample', () => {
8
+ const machine = StateMachine({
9
+ initial: 'idle',
10
+ states: {
11
+ error: {},
12
+ idle: {
13
+ click: 'loading',
14
+ },
15
+ loading: {
16
+ success: 'success',
17
+ error: 'error',
18
+ },
19
+ success: {},
20
+ },
21
+ });
22
+
23
+ expect(machine.getState()).toBe('idle');
24
+
25
+ unwrap(machine.transition('click'));
26
+
27
+ expect(machine.getState()).toBe('loading');
28
+
29
+ unwrap(machine.transition('success'));
30
+
31
+ expect(machine.getState()).toBe('success');
32
+
33
+ expect(isFailure(machine.transition('click'))).toBe(true);
34
+
35
+ expect(machine.getState()).toBe('success');
36
+ });
37
+
38
+ test('sample with conditional', () => {
39
+ const machine = StateMachine({
40
+ initial: 'idle',
41
+ states: {
42
+ error: {},
43
+ idle: {
44
+ click: ['loading', () => false],
45
+ },
46
+ loading: {
47
+ success: 'success',
48
+ error: 'error',
49
+ },
50
+ success: {},
51
+ },
52
+ });
53
+
54
+ expect(machine.getState()).toBe('idle');
55
+
56
+ expect(isFailure(machine.transition('click'))).toBe(true);
57
+
58
+ expect(machine.getState()).toBe('idle');
59
+
60
+ expect(isFailure(machine.transition('success'))).toBe(true);
61
+
62
+ expect(machine.getState()).toBe('idle');
63
+
64
+ expect(isFailure(machine.transition('click'))).toBe(true);
65
+
66
+ expect(machine.getState()).toBe('idle');
67
+ });
68
+
69
+ describe('sample with conditional and payload', () => {
70
+ const machine = StateMachine({
71
+ initial: 'idle',
72
+ states: {
73
+ error: {},
74
+ idle: {
75
+ click: ['loading', (payload: number) => payload > 0],
76
+ },
77
+ loading: {
78
+ success: 'success',
79
+ error: 'error',
80
+ },
81
+ success: {},
82
+ },
83
+ });
84
+
85
+ test('should not transition if payload is falsy', () => {
86
+ expect(machine.getState()).toBe('idle');
87
+
88
+ expect(isFailure(machine.transition('click', 0))).toBe(true);
89
+
90
+ expect(machine.getState()).toBe('idle');
91
+ });
92
+
93
+ test('should transition if payload is truthy', () => {
94
+ expect(machine.getState()).toBe('idle');
95
+
96
+ unwrap(machine.transition('click', 1));
97
+
98
+ expect(machine.getState()).toBe('loading');
99
+ });
100
+ });
101
+
102
+ describe('invalid transitions', () => {
103
+ test('should not transition if action is invalid', () => {
104
+ const machine = StateMachine({
105
+ initial: 'idle',
106
+ states: {
107
+ error: {},
108
+ idle: {
109
+ click: 'loading',
110
+ },
111
+ loading: {
112
+ success: 'success',
113
+ error: 'error',
114
+ },
115
+ success: {},
116
+ },
117
+ });
118
+ expect(machine.getState()).toBe('idle');
119
+
120
+ unwrap(machine.transition('click'));
121
+
122
+ expect(machine.getState()).toBe('loading');
123
+
124
+ expect(isFailure(machine.transition('click'))).toBe(true);
125
+
126
+ expect(machine.getState()).toBe('loading');
127
+ });
128
+
129
+ test('should not transition if target state is invalid', () => {
130
+ const machine = StateMachine({
131
+ initial: 'idle',
132
+ states: {
133
+ error: {},
134
+ idle: {
135
+ click: 'loading',
136
+ },
137
+ loading: {
138
+ success: 'success',
139
+ error: 'error',
140
+ },
141
+ success: {},
142
+ },
143
+ });
144
+ expect(machine.getState()).toBe('idle');
145
+
146
+ unwrap(machine.transition('click'));
147
+
148
+ expect(machine.getState()).toBe('loading');
149
+
150
+ // @ts-expect-error - Testing invalid transition
151
+ expect(isFailure(machine.transition('finish'))).toBe(true);
152
+
153
+ expect(machine.getState()).toBe('loading');
154
+ });
155
+ });
156
+
157
+ describe('Catchall state', () => {
158
+ it('When a valid transition does not exist, should search in the search all state', () => {
159
+ const machine = StateMachine({
160
+ initial: 'idle',
161
+ states: {
162
+ '*': {
163
+ terminate: 'x_x',
164
+ },
165
+ error: {},
166
+ idle: {
167
+ click: 'loading',
168
+ },
169
+ loading: {
170
+ success: 'success',
171
+ error: 'error',
172
+ },
173
+ success: {},
174
+ },
175
+ });
176
+ expect(machine.getState()).toBe('idle');
177
+
178
+ unwrap(machine.transition('click'));
179
+
180
+ expect(machine.getState()).toBe('loading');
181
+
182
+ unwrap(machine.transition('terminate'));
183
+
184
+ expect(machine.getState()).toBe('x_x');
185
+ });
186
+ });
187
+
188
+ describe('transition output value', () => {
189
+ describe('when transition is valid', () => {
190
+ it('Should return Success', () => {
191
+ const machine = StateMachine({
192
+ initial: 'idle',
193
+ states: {
194
+ error: {},
195
+ idle: {
196
+ click: 'loading',
197
+ },
198
+ loading: {
199
+ success: 'success',
200
+ error: 'error',
201
+ },
202
+ success: {},
203
+ },
204
+ });
205
+ expect(machine.getState()).toBe('idle');
206
+
207
+ expect(isSuccess(machine.transition('click'))).toBe(true);
208
+ });
209
+ });
210
+
211
+ describe('When transitioning to the same state', () => {
212
+ it('Should return Success if transition is valid', () => {
213
+ const machine = StateMachine({
214
+ initial: 'idle',
215
+ states: {
216
+ idle: {
217
+ click: 'idle',
218
+ },
219
+ },
220
+ });
221
+ expect(machine.getState()).toBe('idle');
222
+
223
+ expect(isSuccess(machine.transition('click'))).toBe(true);
224
+ expect(machine.getState()).toBe('idle');
225
+ });
226
+ });
227
+
228
+ describe('When target state does not exist', () => {
229
+ it('Should return Failure', () => {
230
+ const machine = StateMachine({
231
+ initial: 'idle',
232
+ states: {
233
+ error: {},
234
+ idle: {
235
+ click: 'loading',
236
+ },
237
+ loading: {
238
+ success: 'success',
239
+ error: 'error',
240
+ },
241
+ success: {},
242
+ },
243
+ });
244
+ expect(machine.getState()).toBe('idle');
245
+
246
+ unwrap(machine.transition('click'));
247
+ // @ts-expect-error - Testing invalid transition
248
+ expect(isFailure(machine.transition('finish'))).toBe(true);
249
+ });
250
+ });
251
+
252
+ describe('When transition is invalid', () => {
253
+ it('Should return Failure', () => {
254
+ const machine = StateMachine({
255
+ initial: 'idle',
256
+ states: {
257
+ error: {},
258
+ idle: {
259
+ click: 'loading',
260
+ },
261
+ loading: {
262
+ success: 'success',
263
+ error: 'error',
264
+ },
265
+ success: {},
266
+ },
267
+ });
268
+ expect(machine.getState()).toBe('idle');
269
+
270
+ unwrap(machine.transition('click'));
271
+ expect(isFailure(machine.transition('click'))).toBe(true);
272
+ });
273
+ });
274
+
275
+ describe('When the transition is disallowed by a conditional', () => {
276
+ it('Should return Failure', () => {
277
+ const machine = StateMachine({
278
+ initial: 'idle',
279
+ states: {
280
+ error: {},
281
+ idle: {
282
+ click: ['loading', () => false],
283
+ },
284
+ loading: {
285
+ success: 'success',
286
+ error: 'error',
287
+ },
288
+ success: {},
289
+ },
290
+ });
291
+ expect(machine.getState()).toBe('idle');
292
+
293
+ expect(isFailure(machine.transition('click'))).toBe(true);
294
+ });
295
+ });
296
+ });
297
+
298
+ describe('staticTransition', () => {
299
+ describe('When the transition is valid', () => {
300
+ it('Should return the new state', () => {
301
+ const machine = StateMachine({
302
+ initial: 'idle',
303
+ states: {
304
+ error: {},
305
+ idle: {
306
+ click: 'loading',
307
+ },
308
+ loading: {
309
+ success: 'success',
310
+ error: 'error',
311
+ },
312
+ success: {},
313
+ },
314
+ });
315
+ expect(machine.getState()).toBe('idle');
316
+ expect(machine.staticTransition('idle', 'click')).toBe('loading');
317
+ });
318
+
319
+ it('Should not modify the state', () => {
320
+ const machine = StateMachine({
321
+ initial: 'idle',
322
+ states: {
323
+ error: {},
324
+ idle: {
325
+ click: 'loading',
326
+ },
327
+ loading: {
328
+ success: 'success',
329
+ error: 'error',
330
+ },
331
+ success: {},
332
+ },
333
+ });
334
+ expect(machine.getState()).toBe('idle');
335
+ machine.staticTransition('idle', 'click');
336
+ expect(machine.getState()).toBe('idle');
337
+ });
338
+ });
339
+
340
+ describe('When the transition is invalid', () => {
341
+ it('Should return the previous state', () => {
342
+ const machine = StateMachine({
343
+ initial: 'idle',
344
+ states: {
345
+ error: {},
346
+ idle: {
347
+ click: 'loading',
348
+ },
349
+ loading: {
350
+ success: 'success',
351
+ error: 'error',
352
+ },
353
+ success: {},
354
+ },
355
+ });
356
+ expect(machine.getState()).toBe('idle');
357
+ // @ts-expect-error - Testing invalid transition
358
+ expect(machine.staticTransition('idle', 'finish')).toBe('idle');
359
+ });
360
+ });
361
+
362
+ describe('When the transition is disallowed by a conditional', () => {
363
+ it('Should return the previous state', () => {
364
+ const machine = StateMachine({
365
+ initial: 'idle',
366
+ states: {
367
+ error: {},
368
+ idle: {
369
+ click: ['loading', () => false],
370
+ },
371
+ loading: {
372
+ success: 'success',
373
+ error: 'error',
374
+ },
375
+ success: {},
376
+ },
377
+ });
378
+ expect(machine.getState()).toBe('idle');
379
+ expect(machine.staticTransition('idle', 'click')).toBe('idle');
380
+ });
381
+ });
382
+
383
+ describe('When the transition is allowed by a conditional', () => {
384
+ it('Should return the new state', () => {
385
+ const machine = StateMachine({
386
+ initial: 'idle',
387
+ states: {
388
+ error: {},
389
+ idle: {
390
+ click: ['loading', () => true],
391
+ },
392
+ loading: {
393
+ success: 'success',
394
+ error: 'error',
395
+ },
396
+ success: {},
397
+ },
398
+ });
399
+ expect(machine.getState()).toBe('idle');
400
+ expect(machine.staticTransition('idle', 'click')).toBe('loading');
401
+ });
402
+ });
403
+ });
404
+
405
+ describe('iniitial', () => {
406
+ it('Should return the initial state', () => {
407
+ const machine = StateMachine({
408
+ initial: 'idle',
409
+ states: {
410
+ error: {},
411
+ idle: {
412
+ click: 'loading',
413
+ },
414
+ loading: {
415
+ success: 'success',
416
+ error: 'error',
417
+ },
418
+ success: {},
419
+ },
420
+ });
421
+ expect(machine.getState()).toBe('idle');
422
+ expect(machine.initial()).toBe('idle');
423
+ });
424
+ });
425
+ });