Skip to content

Commit a77d51f

Browse files
authored
test(unstable): add async-validation mutators tests (#303)
1 parent 4213005 commit a77d51f

File tree

5 files changed

+323
-8
lines changed

5 files changed

+323
-8
lines changed

src/lib/unstable/__tests__/helpers.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type {Tools} from 'final-form';
2+
13
import {JsonSchemaType, SchemaRendererMode} from '../core/constants';
24
import type {
35
IndependentView,
@@ -194,6 +196,9 @@ export function createMockSchema<T extends JsonSchema>(
194196
} as T;
195197
}
196198

199+
export const mockTools = {} as Tools<{}, {}>;
200+
export const mockServiceFieldName = 'mockServiceFieldName';
201+
197202
describe('helpers', () => {
198203
test('just empty test', () => {
199204
expect(true).toBe(true);

src/lib/unstable/core/SchemaRendererServiceField/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,13 @@ const processAjvValidateErrors = <Schema extends JsonSchema>({
278278

279279
w.promise.then((result) => {
280280
setValidationCache({
281-
name: serviceFieldName,
282281
cache: {
283282
[w.instancePath]: {
284283
...w.params,
285284
result,
286285
},
287286
},
287+
serviceFieldName,
288288
});
289289
});
290290
},
@@ -397,7 +397,7 @@ export const getValidate = <Schema extends JsonSchema>({
397397
});
398398

399399
if (Object.keys(waiters).length) {
400-
setValidationWaiters({name: serviceFieldName, waiters});
400+
setValidationWaiters({serviceFieldName, waiters});
401401
}
402402

403403
const result = processErrorItems({
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
import type {InternalFormState, MutableState} from 'final-form';
2+
3+
import {mockServiceFieldName, mockTools} from '../../../../__tests__/helpers.test';
4+
import {JsonSchemaType} from '../../../constants';
5+
import {setValidationCache, setValidationWaiters} from '../async-validation';
6+
import type {ValidationCache, ValidationWaiter} from '../types';
7+
8+
const createMockWaiterAndCache = (prefix = '') => {
9+
const fieldName = `fieldName${prefix}`;
10+
const waiter: ValidationWaiter = {
11+
schema: {type: JsonSchemaType.String},
12+
validator: jest.fn(),
13+
value: `value${prefix}`,
14+
};
15+
const cache: ValidationCache = {...waiter, result: `result${prefix}`};
16+
17+
return {cache, fieldName, waiter};
18+
};
19+
20+
const createMockMutableState = (fields: Record<string, any> = {}): MutableState<{}, {}> => {
21+
const mockFormState = {} as InternalFormState;
22+
23+
return {
24+
fields,
25+
formState: mockFormState,
26+
fieldSubscribers: {},
27+
};
28+
};
29+
30+
describe('async-validation', () => {
31+
describe('setValidationWaiters', () => {
32+
it('should not modify state if service field does not exist', () => {
33+
const {fieldName, waiter} = createMockWaiterAndCache();
34+
const mutableState = createMockMutableState();
35+
36+
setValidationWaiters(
37+
[{serviceFieldName: mockServiceFieldName, waiters: {[fieldName]: waiter}}],
38+
mutableState,
39+
mockTools,
40+
);
41+
42+
expect(mutableState.fields).toEqual({});
43+
});
44+
45+
it('should not modify state if waiters are not provided', () => {
46+
const mutableState = createMockMutableState({
47+
[mockServiceFieldName]: {data: {}},
48+
});
49+
50+
setValidationWaiters(
51+
[{serviceFieldName: mockServiceFieldName, waiters: undefined as any}],
52+
mutableState,
53+
mockTools,
54+
);
55+
56+
expect(mutableState.fields[mockServiceFieldName].data).toEqual({});
57+
});
58+
59+
it('should add waiter to the validation state', () => {
60+
const {fieldName, waiter} = createMockWaiterAndCache();
61+
const mutableState = createMockMutableState({
62+
[mockServiceFieldName]: {data: {}},
63+
[fieldName]: {},
64+
});
65+
66+
setValidationWaiters(
67+
[{serviceFieldName: mockServiceFieldName, waiters: {[fieldName]: waiter}}],
68+
mutableState,
69+
mockTools,
70+
);
71+
72+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({
73+
[fieldName]: waiter,
74+
});
75+
expect(mutableState.fields[fieldName].validating).toBe(true);
76+
});
77+
78+
it('should add waiters to the validation state', () => {
79+
const waiterAndCacheKit = createMockWaiterAndCache();
80+
const waiterAndCacheKit2 = createMockWaiterAndCache('2');
81+
82+
const mutableState = createMockMutableState({
83+
[mockServiceFieldName]: {data: {}},
84+
[waiterAndCacheKit.fieldName]: {validating: false},
85+
[waiterAndCacheKit2.fieldName]: {validating: false},
86+
});
87+
88+
setValidationWaiters(
89+
[
90+
{
91+
serviceFieldName: mockServiceFieldName,
92+
waiters: {
93+
[waiterAndCacheKit.fieldName]: waiterAndCacheKit.waiter,
94+
[waiterAndCacheKit2.fieldName]: waiterAndCacheKit2.waiter,
95+
},
96+
},
97+
],
98+
mutableState,
99+
mockTools,
100+
);
101+
102+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({
103+
[waiterAndCacheKit.fieldName]: waiterAndCacheKit.waiter,
104+
[waiterAndCacheKit2.fieldName]: waiterAndCacheKit2.waiter,
105+
});
106+
expect(mutableState.fields[waiterAndCacheKit.fieldName].validating).toBe(true);
107+
expect(mutableState.fields[waiterAndCacheKit2.fieldName].validating).toBe(true);
108+
});
109+
110+
it('should merge waiters with existing waiters', () => {
111+
const waiterAndCacheKit = createMockWaiterAndCache();
112+
const existingWaiterAndCacheKit = createMockWaiterAndCache('existing');
113+
const mutableState = createMockMutableState({
114+
[mockServiceFieldName]: {
115+
data: {
116+
waiters: {
117+
[existingWaiterAndCacheKit.fieldName]: existingWaiterAndCacheKit.waiter,
118+
},
119+
},
120+
},
121+
[waiterAndCacheKit.fieldName]: {},
122+
});
123+
124+
setValidationWaiters(
125+
[
126+
{
127+
serviceFieldName: mockServiceFieldName,
128+
waiters: {[waiterAndCacheKit.fieldName]: waiterAndCacheKit.waiter},
129+
},
130+
],
131+
mutableState,
132+
mockTools,
133+
);
134+
135+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({
136+
[existingWaiterAndCacheKit.fieldName]: existingWaiterAndCacheKit.waiter,
137+
[waiterAndCacheKit.fieldName]: waiterAndCacheKit.waiter,
138+
});
139+
expect(mutableState.fields[waiterAndCacheKit.fieldName].validating).toBe(true);
140+
});
141+
});
142+
143+
describe('setValidationCache', () => {
144+
it('should not modify state if field does not exist', () => {
145+
const {cache, fieldName} = createMockWaiterAndCache();
146+
const mutableState = createMockMutableState();
147+
148+
setValidationCache(
149+
[{serviceFieldName: mockServiceFieldName, cache: {[fieldName]: cache}}],
150+
mutableState,
151+
mockTools,
152+
);
153+
154+
expect(mutableState.fields).toEqual({});
155+
});
156+
157+
it('should not modify state if cache is not provided', () => {
158+
const mutableState = createMockMutableState({
159+
[mockServiceFieldName]: {data: {}},
160+
});
161+
162+
setValidationCache(
163+
[{serviceFieldName: mockServiceFieldName, cache: undefined as any}],
164+
mutableState,
165+
mockTools,
166+
);
167+
168+
expect(mutableState.fields[mockServiceFieldName].data).toEqual({});
169+
});
170+
171+
it('should add cache to the validation state', () => {
172+
const {cache, fieldName} = createMockWaiterAndCache();
173+
const mutableState = createMockMutableState({
174+
[mockServiceFieldName]: {data: {}},
175+
[fieldName]: {},
176+
});
177+
178+
setValidationCache(
179+
[{serviceFieldName: mockServiceFieldName, cache: {[fieldName]: cache}}],
180+
mutableState,
181+
mockTools,
182+
);
183+
184+
expect(mutableState.fields[mockServiceFieldName].data.cache).toEqual({
185+
[fieldName]: [cache],
186+
});
187+
});
188+
189+
it('should append to existing cache', () => {
190+
const fieldName = 'fieldName';
191+
const existingWaiterAndCacheKit = createMockWaiterAndCache('existing');
192+
const waiterAndCacheKit = createMockWaiterAndCache();
193+
const mutableState = createMockMutableState({
194+
[mockServiceFieldName]: {
195+
data: {
196+
cache: {
197+
[fieldName]: [existingWaiterAndCacheKit.cache],
198+
},
199+
},
200+
},
201+
[fieldName]: {},
202+
});
203+
204+
setValidationCache(
205+
[
206+
{
207+
serviceFieldName: mockServiceFieldName,
208+
cache: {[fieldName]: waiterAndCacheKit.cache},
209+
},
210+
],
211+
mutableState,
212+
mockTools,
213+
);
214+
215+
expect(mutableState.fields[mockServiceFieldName].data.cache).toEqual({
216+
[fieldName]: [existingWaiterAndCacheKit.cache, waiterAndCacheKit.cache],
217+
});
218+
});
219+
220+
it('should clear waiter and set validating to false when waiter matches cache', () => {
221+
const fieldName = 'fieldName';
222+
const {cache, waiter} = createMockWaiterAndCache();
223+
const mutableState = createMockMutableState({
224+
[mockServiceFieldName]: {data: {waiters: {[fieldName]: waiter}}},
225+
[fieldName]: {validating: true},
226+
});
227+
228+
setValidationCache(
229+
[{serviceFieldName: mockServiceFieldName, cache: {[fieldName]: cache}}],
230+
mutableState,
231+
mockTools,
232+
);
233+
234+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({});
235+
expect(mutableState.fields[fieldName].validating).toBe(false);
236+
});
237+
238+
it('should not clear waiter when waiter does not match cache', () => {
239+
const fieldName = 'fieldName';
240+
const {waiter} = createMockWaiterAndCache('1');
241+
const {cache} = createMockWaiterAndCache('2');
242+
243+
const mutableState = createMockMutableState({
244+
[mockServiceFieldName]: {data: {waiters: {[fieldName]: waiter}}},
245+
[fieldName]: {validating: true},
246+
});
247+
248+
setValidationCache(
249+
[{serviceFieldName: mockServiceFieldName, cache: {[fieldName]: cache}}],
250+
mutableState,
251+
mockTools,
252+
);
253+
254+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({
255+
[fieldName]: waiter,
256+
});
257+
expect(mutableState.fields[fieldName].validating).toBe(true);
258+
});
259+
260+
it('should handle multiple cache entries', () => {
261+
const fieldName = 'fieldName';
262+
const waiterAndCacheKit = createMockWaiterAndCache(fieldName);
263+
264+
const fieldName2 = 'fieldName2';
265+
const waiterAndCacheKit2 = createMockWaiterAndCache(fieldName2);
266+
267+
const mutableState = createMockMutableState({
268+
[mockServiceFieldName]: {
269+
data: {
270+
waiters: {
271+
[fieldName]: waiterAndCacheKit.waiter,
272+
[fieldName2]: waiterAndCacheKit2.waiter,
273+
},
274+
},
275+
},
276+
[fieldName]: {validating: true},
277+
[fieldName2]: {validating: true},
278+
});
279+
280+
setValidationCache(
281+
[
282+
{
283+
serviceFieldName: mockServiceFieldName,
284+
cache: {
285+
[fieldName]: waiterAndCacheKit.cache,
286+
[fieldName2]: waiterAndCacheKit2.cache,
287+
},
288+
},
289+
],
290+
mutableState,
291+
mockTools,
292+
);
293+
294+
expect(mutableState.fields[mockServiceFieldName].data.waiters).toEqual({});
295+
expect(mutableState.fields[fieldName].validating).toBe(false);
296+
expect(mutableState.fields[fieldName2].validating).toBe(false);
297+
expect(mutableState.fields[mockServiceFieldName].data.cache).toEqual({
298+
[fieldName]: [waiterAndCacheKit.cache],
299+
[fieldName2]: [waiterAndCacheKit2.cache],
300+
});
301+
});
302+
});
303+
});

src/lib/unstable/core/mutators/async-validation/async-validation.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import type {
88
} from './types';
99

1010
export const setValidationWaiters: SetValidationWaitersFunction = (
11-
[{name, waiters}],
11+
[{serviceFieldName, waiters}],
1212
mutableState,
1313
) => {
14-
const validationState = mutableState.fields[name]?.data as ValidationState | undefined;
14+
const validationState = mutableState.fields[serviceFieldName]?.data as
15+
| ValidationState
16+
| undefined;
1517

1618
if (validationState && waiters) {
1719
Object.keys(waiters).forEach((waiterName) => {
@@ -29,8 +31,13 @@ export const setValidationWaiters: SetValidationWaitersFunction = (
2931
}
3032
};
3133

32-
export const setValidationCache: SetValidationCacheFunction = ([{cache, name}], mutableState) => {
33-
const validationState = mutableState.fields[name]?.data as ValidationState | undefined;
34+
export const setValidationCache: SetValidationCacheFunction = (
35+
[{cache, serviceFieldName}],
36+
mutableState,
37+
) => {
38+
const validationState = mutableState.fields[serviceFieldName]?.data as
39+
| ValidationState
40+
| undefined;
3441

3542
if (validationState && cache) {
3643
Object.keys(cache).forEach((cacheName) => {

src/lib/unstable/core/mutators/async-validation/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface ValidationState {
2222
}
2323

2424
export interface SetValidationWaitersParams {
25-
name: string;
25+
serviceFieldName: string;
2626
waiters: {
2727
[key: string]: ValidationWaiter;
2828
};
@@ -43,7 +43,7 @@ export interface SetValidationCacheParams {
4343
cache: {
4444
[key: string]: ValidationCache;
4545
};
46-
name: string;
46+
serviceFieldName: string;
4747
}
4848

4949
export type SetValidationCacheFunction<

0 commit comments

Comments
 (0)