Skip to content

Commit

Permalink
[@mantine/form] Add all uncontrolled form tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rtivital committed Apr 6, 2024
1 parent 878720b commit f2b68d8
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 50 deletions.
36 changes: 25 additions & 11 deletions packages/@mantine/form/src/tests/reset.test.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/reset', () => {
function tests(mode: FormMode) {
it('resets errors and values with reset handler', () => {
const hook = renderHook(() =>
useForm({ initialErrors: { a: 1, b: 2 }, initialValues: { c: 3, d: 4 } })
useForm({ mode, initialErrors: { a: 1, b: 2 }, initialValues: { c: 3, d: 4 } })
);
expect(hook.result.current.errors).toStrictEqual({ a: 1, b: 2 });
expect(hook.result.current.values).toStrictEqual({ c: 3, d: 4 });
expect(hook.result.current.getValues()).toStrictEqual({ c: 3, d: 4 });

act(() => hook.result.current.setValues({ c: 5, d: 6 }));
act(() => hook.result.current.setErrors({ a: 7, b: 8 }));
expect(hook.result.current.values).toStrictEqual({ c: 5, d: 6 });
expect(hook.result.current.getValues()).toStrictEqual({ c: 5, d: 6 });
expect(hook.result.current.errors).toStrictEqual({ a: 7, b: 8 });

act(() => hook.result.current.reset());
expect(hook.result.current.errors).toStrictEqual({});
expect(hook.result.current.values).toStrictEqual({ c: 3, d: 4 });
expect(hook.result.current.getValues()).toStrictEqual({ c: 3, d: 4 });
});

it('resets touched and dirty state', () => {
const hook = renderHook(() =>
useForm({ initialValues: { a: 1 }, initialDirty: { a: true }, initialTouched: { a: true } })
useForm({
mode,
initialValues: { a: 1 },
initialDirty: { a: true },
initialTouched: { a: true },
})
);

expect(hook.result.current.isDirty()).toBe(true);
Expand All @@ -34,26 +40,34 @@ describe('@mantine/form/reset', () => {

it('resets values without keeping added values', () => {
const hook = renderHook(() =>
useForm<{ a: number; b?: number; c?: number }>({ initialValues: { a: 1, b: 2 } })
useForm<{ a: number; b?: number; c?: number }>({ mode, initialValues: { a: 1, b: 2 } })
);

act(() => hook.result.current.setFieldValue('c', 3));
expect(hook.result.current.isDirty()).toBe(true);
expect(hook.result.current.values).toStrictEqual({ a: 1, b: 2, c: 3 });
expect(hook.result.current.getValues()).toStrictEqual({ a: 1, b: 2, c: 3 });

act(() => hook.result.current.reset());
expect(hook.result.current.isDirty()).toBe(false);
expect(hook.result.current.values).toStrictEqual({ a: 1, b: 2 });
expect(hook.result.current.getValues()).toStrictEqual({ a: 1, b: 2 });
});

it('resets values correctly after updating initial values', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1, b: 2 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: 1, b: 2 } }));
const newInitialState = { a: 3, b: 4 };

act(() => hook.result.current.setValues({ a: 100, b: 200 }));
act(() => hook.result.current.setInitialValues(newInitialState));
act(() => hook.result.current.reset());

expect(hook.result.current.values).toStrictEqual(newInitialState);
expect(hook.result.current.getValues()).toStrictEqual(newInitialState);
});
}

describe('@mantine/form/reset-controlled', () => {
tests('controlled');
});

describe('@mantine/form/reset-uncontrolled', () => {
tests('uncontrolled');
});
15 changes: 12 additions & 3 deletions packages/@mantine/form/src/tests/resetDirty.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/resetDirty', () => {
function tests(mode: FormMode) {
it('memoizes values that were used in resetDirty', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1, b: 2 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: 1, b: 2 } }));
expect(hook.result.current.isDirty()).toBe(false);

act(() => hook.result.current.setFieldValue('a', 3));
Expand All @@ -21,7 +22,7 @@ describe('@mantine/form/resetDirty', () => {

it('correctly handles partial values', () => {
const hook = renderHook(() =>
useForm<{ a: number; b?: number }>({ initialValues: { a: 1, b: 2 } })
useForm<{ a: number; b?: number }>({ mode, initialValues: { a: 1, b: 2 } })
);

expect(hook.result.current.isDirty()).toBe(false);
Expand All @@ -33,4 +34,12 @@ describe('@mantine/form/resetDirty', () => {

expect(hook.result.current.isDirty()).toBe(false);
});
}

describe('@mantine/form/resetDirty-controlled', () => {
tests('controlled');
});

describe('@mantine/form/resetDirty-uncontrolled', () => {
tests('uncontrolled');
});
13 changes: 11 additions & 2 deletions packages/@mantine/form/src/tests/setErrors.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/setErrors', () => {
function tests(mode: FormMode) {
it('filters out errors with undefined and null with setErrors handler', () => {
const hook = renderHook(() => useForm());
const hook = renderHook(() => useForm({ mode }));
act(() => hook.result.current.setErrors({ a: 1, b: undefined, c: null, d: 2 }));
expect(hook.result.current.errors).toStrictEqual({ a: 1, d: 2 });
});
}

describe('@mantine/form/setErrors-controlled', () => {
tests('controlled');
});

describe('@mantine/form/setErrors-uncontrolled', () => {
tests('uncontrolled');
});
43 changes: 28 additions & 15 deletions packages/@mantine/form/src/tests/setFieldValue.test.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,66 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/setFieldValue', () => {
function tests(mode: FormMode) {
it('sets given value with root path', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1, b: 2 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: 1, b: 2 } }));

act(() => hook.result.current.setFieldValue('a', 10));
expect(hook.result.current.values).toStrictEqual({ a: 10, b: 2 });
expect(hook.result.current.getValues()).toStrictEqual({ a: 10, b: 2 });

act(() => hook.result.current.setFieldValue('b', 20));
expect(hook.result.current.values).toStrictEqual({ a: 10, b: 20 });
expect(hook.result.current.getValues()).toStrictEqual({ a: 10, b: 20 });
});

it('sets given value at composite path', () => {
const hook = renderHook(() => useForm({ initialValues: { a: { d: 2, b: { c: 1 } } } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: { d: 2, b: { c: 1 } } } }));

act(() => hook.result.current.setFieldValue('a.b.c', 10));
expect(hook.result.current.values).toStrictEqual({ a: { d: 2, b: { c: 10 } } });
expect(hook.result.current.getValues()).toStrictEqual({ a: { d: 2, b: { c: 10 } } });

act(() => hook.result.current.setFieldValue('a.d', 20));
expect(hook.result.current.values).toStrictEqual({ a: { d: 20, b: { c: 10 } } });
expect(hook.result.current.getValues()).toStrictEqual({ a: { d: 20, b: { c: 10 } } });
});

it('sets given value at array path', () => {
const hook = renderHook(() => useForm({ initialValues: { a: [{ b: 1 }, { b: 2 }] } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: [{ b: 1 }, { b: 2 }] } }));

act(() => hook.result.current.setFieldValue('a.1.b', 20));
expect(hook.result.current.values).toStrictEqual({ a: [{ b: 1 }, { b: 20 }] });
expect(hook.result.current.getValues()).toStrictEqual({ a: [{ b: 1 }, { b: 20 }] });

act(() => hook.result.current.setFieldValue('a.0.b', 10));
expect(hook.result.current.values).toStrictEqual({ a: [{ b: 10 }, { b: 20 }] });
expect(hook.result.current.getValues()).toStrictEqual({ a: [{ b: 10 }, { b: 20 }] });
});

it('sets given value at mixed nested path', () => {
const hook = renderHook(() =>
useForm({ initialValues: { a: [{ b: { c: 1 } }, { b: { c: 2 } }] } })
useForm({ mode, initialValues: { a: [{ b: { c: 1 } }, { b: { c: 2 } }] } })
);

act(() => hook.result.current.setFieldValue('a.1.b.c', 20));
expect(hook.result.current.values).toStrictEqual({ a: [{ b: { c: 1 } }, { b: { c: 20 } }] });
expect(hook.result.current.getValues()).toStrictEqual({
a: [{ b: { c: 1 } }, { b: { c: 20 } }],
});

act(() => hook.result.current.setFieldValue('a.0.b.c', 10));
expect(hook.result.current.values).toStrictEqual({ a: [{ b: { c: 10 } }, { b: { c: 20 } }] });
expect(hook.result.current.getValues()).toStrictEqual({
a: [{ b: { c: 10 } }, { b: { c: 20 } }],
});
});

it('sets value at path based on previous value', () => {
const hook = renderHook(() => useForm({ initialValues: { a: { d: 2, b: { c: 1 } } } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: { d: 2, b: { c: 1 } } } }));

act(() => hook.result.current.setFieldValue('a.b.c', (prev) => prev + 1));
expect(hook.result.current.values).toStrictEqual({ a: { d: 2, b: { c: 2 } } });
expect(hook.result.current.getValues()).toStrictEqual({ a: { d: 2, b: { c: 2 } } });
});
}

describe('@mantine/form/setFieldValue-controlled', () => {
tests('controlled');
});

describe('@mantine/form/setFieldValue-uncontrolled', () => {
tests('uncontrolled');
});
18 changes: 14 additions & 4 deletions packages/@mantine/form/src/tests/setValues.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

interface Values {
a: number;
b: number;
}

describe('@mantine/form/setValues', () => {
function tests(mode: FormMode) {
it('resets errors when setValues is called', () => {
const hook = renderHook(() => useForm<Values>({ initialErrors: { a: 1, b: 2 } }));
const hook = renderHook(() => useForm<Values>({ mode, initialErrors: { a: 1, b: 2 } }));
expect(hook.result.current.errors).toStrictEqual({ a: 1, b: 2 });
act(() => hook.result.current.setValues({ a: 1, b: 2 }));
expect(hook.result.current.errors).toStrictEqual({});
Expand All @@ -17,6 +18,7 @@ describe('@mantine/form/setValues', () => {
it('does not reset errors when setValues is called if clearInputErrorOnChange is false', () => {
const hook = renderHook(() =>
useForm<Values>({
mode,
initialErrors: { a: 1, b: 2 },
clearInputErrorOnChange: false,
})
Expand All @@ -28,8 +30,16 @@ describe('@mantine/form/setValues', () => {
});

it('allows setting values partial', () => {
const hook = renderHook(() => useForm<Values>({ initialValues: { a: 1, b: 2 } }));
const hook = renderHook(() => useForm<Values>({ mode, initialValues: { a: 1, b: 2 } }));
act(() => hook.result.current.setValues({ a: 3 }));
expect(hook.result.current.values).toStrictEqual({ a: 3, b: 2 });
expect(hook.result.current.getValues()).toStrictEqual({ a: 3, b: 2 });
});
}

describe('@mantine/form/setValues-controlled', () => {
tests('controlled');
});

describe('@mantine/form/setValues-uncontrolled', () => {
tests('uncontrolled');
});
21 changes: 15 additions & 6 deletions packages/@mantine/form/src/tests/touched.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/touched', () => {
function tests(mode: FormMode) {
it('accepts initial touched state', () => {
const hook = renderHook(() => useForm({ initialTouched: { a: true, b: false } }));
const hook = renderHook(() => useForm({ mode, initialTouched: { a: true, b: false } }));
expect(hook.result.current.isTouched('a')).toBe(true);
expect(hook.result.current.isTouched('b')).toBe(false);
expect(hook.result.current.isTouched()).toBe(true);
});

it('sets field as touched if value changes', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: 1 } }));
expect(hook.result.current.isTouched('a')).toBe(false);
expect(hook.result.current.isTouched()).toBe(false);

Expand All @@ -20,7 +21,7 @@ describe('@mantine/form/touched', () => {
});

it('allows to set touched state with setTouched handler', () => {
const hook = renderHook(() => useForm());
const hook = renderHook(() => useForm({ mode }));
expect(hook.result.current.isTouched()).toBe(false);
expect(hook.result.current.isTouched('a')).toBe(false);

Expand All @@ -30,20 +31,28 @@ describe('@mantine/form/touched', () => {
});

it('resets status with resetTouched handler', () => {
const hook = renderHook(() => useForm({ initialTouched: { a: true } }));
const hook = renderHook(() => useForm({ mode, initialTouched: { a: true } }));
expect(hook.result.current.isTouched()).toBe(true);

act(() => hook.result.current.resetTouched());
expect(hook.result.current.isTouched()).toBe(false);
});

it('sets field as touched with getInputProps onFocus', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: 1 } }));
expect(hook.result.current.isTouched()).toBe(false);
expect(hook.result.current.isTouched('a')).toBe(false);

act(() => hook.result.current.getInputProps('a').onFocus());
expect(hook.result.current.isTouched()).toBe(true);
expect(hook.result.current.isTouched('a')).toBe(true);
});
}

describe('@mantine/form/touched-controlled', () => {
tests('controlled');
});

describe('@mantine/form/touched-uncontrolled', () => {
tests('uncontrolled');
});
14 changes: 12 additions & 2 deletions packages/@mantine/form/src/tests/transformValues.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

const getFormEvent = () => ({ preventDefault: jest.fn() }) as any;

describe('@mantine/form/transformValues', () => {
function tests(mode: FormMode) {
it('does not transform values if transformValues function is not provided', () => {
const spy = jest.fn();
const event = getFormEvent();
const hook = renderHook(() => useForm({ initialValues: { a: '1', b: 1 } }));
const hook = renderHook(() => useForm({ mode, initialValues: { a: '1', b: 1 } }));
act(() => hook.result.current.onSubmit(spy)(event));
expect(spy).toHaveBeenCalledWith({ a: '1', b: 1 }, event);
});
Expand All @@ -17,11 +18,20 @@ describe('@mantine/form/transformValues', () => {
const event = getFormEvent();
const hook = renderHook(() =>
useForm({
mode,
initialValues: { a: '1', b: 1 },
transformValues: (values) => ({ a: Number(values.a), b: values.b.toString() }),
})
);
act(() => hook.result.current.onSubmit(spy)(event));
expect(spy).toHaveBeenCalledWith({ a: 1, b: '1' }, event);
});
}

describe('@mantine/form/transformValues-controlled', () => {
tests('controlled');
});

describe('@mantine/form/transformValues-uncontrolled', () => {
tests('uncontrolled');
});
13 changes: 12 additions & 1 deletion packages/@mantine/form/src/tests/validate-function.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { act, renderHook } from '@testing-library/react';
import { FormMode } from '../types';
import { useForm } from '../use-form';

describe('@mantine/form/validate with function rules', () => {
function tests(mode: FormMode) {
it('validates all fields with validate handler', () => {
const hook = renderHook(() =>
useForm({
mode,
initialValues: {
banana: '',
orange: '',
Expand Down Expand Up @@ -58,6 +60,7 @@ describe('@mantine/form/validate with function rules', () => {
it('validates single field with validateField handler', () => {
const hook = renderHook(() =>
useForm({
mode,
initialValues: {
banana: '',
orange: '',
Expand Down Expand Up @@ -85,4 +88,12 @@ describe('@mantine/form/validate with function rules', () => {

expect(hook.result.current.errors).toStrictEqual({});
});
}

describe('@mantine/form/validate with function rules controlled', () => {
tests('controlled');
});

describe('@mantine/form/validate with function rules uncontrolled', () => {
tests('uncontrolled');
});
Loading

0 comments on commit f2b68d8

Please sign in to comment.