Skip to content

Commit

Permalink
Fix useConverterField tests (#293)
Browse files Browse the repository at this point in the history
* Refactoring

* Fixed tests warnings
  • Loading branch information
AlexShukel authored Aug 27, 2023
1 parent 524f4d2 commit 0676ac5
Showing 1 changed file with 94 additions and 119 deletions.
213 changes: 94 additions & 119 deletions packages/x/tests/useConverterField.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { ReactiveFormProvider, useForm } from '@reactive-forms/core';
import { act, renderHook } from '@testing-library/react';
import { act, renderHook, waitFor } from '@testing-library/react';

import { ConversionError, useConverterField } from '../src/useConverterField';

Expand Down Expand Up @@ -52,115 +52,83 @@ const renderUseConverterField = (config: Config = {}) => {
},
);

return {
formBag,
converterFieldBag,
};
return [converterFieldBag, formBag] as const;
};

describe('Converter field', () => {
it('Should update field with valid value', async () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField();
const [{ result: converterFieldBag }] = renderUseConverterField();
const { onTextChange } = converterFieldBag.current;

expect(converterFieldBag.current.value).toBe(0);
expect(converterFieldBag.current.text).toBe('0');

await act(async () => {
await onTextChange('1');
await act(() => {
onTextChange('1');
});

expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});

it('Should set an error if conversion fails', async () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField();
const { onTextChange } = converterFieldBag.current;

await act(async () => {
await onTextChange('a');
await waitFor(() => {
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});

expect(converterFieldBag.current.meta.error?.$error).toBe('hello');
expect(converterFieldBag.current.value).toBe(0);
expect(converterFieldBag.current.text).toBe('a');
});

it('Should clear conversion error', async () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField();

it('Should set an error if conversion fails', async () => {
const [{ result: converterFieldBag }] = renderUseConverterField();
const { onTextChange } = converterFieldBag.current;

await act(async () => {
await onTextChange('a');
await act(() => {
onTextChange('a');
});

expect(converterFieldBag.current.meta.error?.$error).toBe('hello');

await act(async () => {
await onTextChange('1');
await waitFor(() => {
expect(converterFieldBag.current.meta.error?.$error).toBe('hello');
expect(converterFieldBag.current.value).toBe(0);
expect(converterFieldBag.current.text).toBe('a');
});

expect(converterFieldBag.current.meta.error?.$error).toBeUndefined();
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});

it('Should update text when form value changes (field is not focused)', async () => {
const {
converterFieldBag: { result: converterFieldBag },
formBag: { result: formBag },
} = renderUseConverterField();
it('Should update text when form value changes', async () => {
const [{ result: converterFieldBag }, { result: formBag }] = renderUseConverterField();

const { paths } = formBag.current;

await act(async () => {
await formBag.current.setFieldValue(paths.test, 1);
await act(() => {
formBag.current.setFieldValue(paths.test, 1);
});

expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
await waitFor(() => {
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});
});

it('Should not update text when field is focused and set old value when field is blurred', async () => {
const {
converterFieldBag: { result: converterFieldBag },
formBag: { result: formBag },
} = renderUseConverterField();
it('Should clear conversion error', async () => {
const [{ result: converterFieldBag }] = renderUseConverterField();

const { onFocus, onBlur } = converterFieldBag.current;
const { setFieldValue, paths } = formBag.current;
const { onTextChange } = converterFieldBag.current;

await act(async () => {
await onFocus();
await act(() => {
onTextChange('a');
});

await act(async () => {
await setFieldValue(paths.test, 1);
await waitFor(() => {
expect(converterFieldBag.current.meta.error?.$error).toBe('hello');
});

expect(converterFieldBag.current.text).toBe('0');
expect(converterFieldBag.current.value).toBe(1);

await act(async () => {
await onBlur();
await act(() => {
onTextChange('1');
});

expect(converterFieldBag.current.text).toBe('0');
expect(converterFieldBag.current.value).toBe(0);
await waitFor(() => {
expect(converterFieldBag.current.meta.error?.$error).toBeUndefined();
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});
});

it('Should rethrow an error in case it is not ConversionError', () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField({
const [{ result: converterFieldBag }] = renderUseConverterField({
parse: () => {
throw new Error('custom');
},
Expand All @@ -172,106 +140,113 @@ describe('Converter field', () => {
});

it('Should not update text if there are some conversion errors', async () => {
const {
converterFieldBag: { result: converterFieldBag },
formBag: { result: formBag },
} = renderUseConverterField();
const [{ result: converterFieldBag }, { result: formBag }] = renderUseConverterField();
const { onTextChange } = converterFieldBag.current;
const { setFieldValue, paths } = formBag.current;

await act(async () => {
await onTextChange('a');
await act(() => {
onTextChange('a');
setFieldValue(paths.test, 1);
});

await act(async () => {
await setFieldValue(paths.test, 1);
await waitFor(() => {
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('a');
});

expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('a');
});

it('Should return error from validator', async () => {
const {
converterFieldBag: { result: converterFieldBag },
formBag: { result: formBag },
} = renderUseConverterField();
const [{ result: converterFieldBag }, { result: formBag }] = renderUseConverterField();

const { onTextChange } = converterFieldBag.current;
const { validateForm, values } = formBag.current;

await act(async () => {
await onTextChange('a');
await act(() => {
onTextChange('a');
});

const errors = await validateForm(values.getValues());

expect(errors.test?.$error).toBe('hello');
});

it('Should ignore new value when field is focused and set old value when field is blurred', async () => {
const [{ result: converterFieldBag }, { result: formBag }] = renderUseConverterField();

const { onFocus, onBlur } = converterFieldBag.current;
const { setFieldValue, paths } = formBag.current;

await act(() => {
onFocus();
setFieldValue(paths.test, 1);
});

await waitFor(() => {
expect(converterFieldBag.current.text).toBe('0');
expect(converterFieldBag.current.value).toBe(1);
});

await act(() => {
onBlur();
});

await waitFor(() => {
expect(converterFieldBag.current.text).toBe('0');
expect(converterFieldBag.current.value).toBe(0);
});
});

it('Should set field touched=true on blur', async () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField();
const [{ result: converterFieldBag }] = renderUseConverterField();

const { onBlur } = converterFieldBag.current;

await act(async () => {
await onBlur();
await act(() => {
onBlur();
});

expect(converterFieldBag.current.meta.touched?.$touched).toBe(true);
await waitFor(() => {
expect(converterFieldBag.current.meta.touched?.$touched).toBe(true);
});
});

it('Should set value both in form state and local text state when focused if using `setValue` callback from hook bag', async () => {
const {
converterFieldBag: { result: converterFieldBag },
} = renderUseConverterField();
it('Should set value both in form state and local text state', async () => {
const [{ result: converterFieldBag }] = renderUseConverterField();

const {
control: { setValue },
onFocus,
} = converterFieldBag.current;

await act(async () => {
await onFocus();
await act(() => {
onFocus();
setValue(1);
});

await act(async () => {
await setValue(1);
await waitFor(() => {
expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});

expect(converterFieldBag.current.value).toBe(1);
expect(converterFieldBag.current.text).toBe('1');
});

it('Should reformat value when format function changes', () => {
const { converterFieldBag } = renderUseConverterField();
const [converterFieldBag] = renderUseConverterField();

const format = jest.fn(() => 'test');

expect(converterFieldBag.result.current.text).toBe('0');

act(() => {
converterFieldBag.rerender({ format, parse: defaultParse });
});
converterFieldBag.rerender({ format, parse: defaultParse });

expect(format).toBeCalled();
expect(converterFieldBag.result.current.text).toBe('test');
});

it('Should parse text again when parse function changes', () => {
const { converterFieldBag } = renderUseConverterField();
it('Should parse text again when parse function changes', async () => {
const [converterFieldBag] = renderUseConverterField();

const parse = jest.fn(() => 1);

expect(converterFieldBag.result.current.value).toBe(0);

act(() => {
await act(() => {
converterFieldBag.rerender({ format: defaultFormat, parse });
});

expect(parse).toBeCalled();
expect(converterFieldBag.result.current.value).toBe(1);
});
});

0 comments on commit 0676ac5

Please sign in to comment.