import * as React from 'react'; import { FunctionComponent, ReactElement, useEffect } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { useFormContext, useWatch } from 'react-hook-form'; import { CoreAdminContext } from '../core'; import { testDataProvider } from '../dataProvider'; import { Form } from './Form'; import { useInput, InputProps } from './useInput'; import { required } from './validate'; const Input: FunctionComponent< { children: (props: ReturnType) => ReactElement; } & InputProps > = ({ children, ...props }) => { const inputProps = useInput(props); return children(inputProps); }; describe('useInput', () => { it('returns the props needed for an input', () => { let inputProps; render(
{props => { inputProps = props; return
; }} ); expect(inputProps.id).toEqual('title'); expect(inputProps.isRequired).toEqual(true); expect(inputProps.field).toBeDefined(); expect(inputProps.field.name).toEqual('title'); expect(inputProps.field.value).toEqual('A title'); expect(inputProps.fieldState).toBeDefined(); }); it('allows to override the input id', () => { let inputProps; render(
{props => { inputProps = props; return
; }} ); expect(inputProps.id).toEqual('my-title'); expect(inputProps.field).toBeDefined(); expect(inputProps.field.name).toEqual('title'); expect(inputProps.fieldState).toBeDefined(); }); it('allows to extend the input event handlers', () => { const handleBlur = jest.fn(); const handleChange = jest.fn(); render(
{({ id, field }) => { return ( ); }}
); const input = screen.getByLabelText('Title'); fireEvent.change(input, { target: { value: 'A title' }, }); expect(handleChange).toHaveBeenCalled(); fireEvent.blur(input); expect(handleBlur).toHaveBeenCalled(); }); describe('defaultValue', () => { it('applies the defaultValue when input does not have a value', () => { const onSubmit = jest.fn(); render(
{({ id, field }) => { return ( ); }}
); expect(screen.queryByDisplayValue('foo')).not.toBeNull(); }); it('does not apply the defaultValue when input has a value of 0', () => { render(
{({ id, field }) => { return ( ); }}
); expect(screen.queryByDisplayValue('99')).toBeNull(); }); const BooleanInput = ({ source, defaultValue, }: { source: string; defaultValue?: boolean; }) => ( {() => } ); const BooleanInputValue = ({ source }) => { const values = useFormContext().getValues(); return ( <> {typeof values[source] === 'undefined' ? 'undefined' : values[source] ? 'true' : 'false'} ); }; it('does not change the value if the field is of type checkbox and has no value', () => { render(
); expect(screen.queryByText('undefined')).not.toBeNull(); }); it('applies the defaultValue true when the field is of type checkbox and has no value', () => { render(
); expect(screen.queryByText('true')).not.toBeNull(); }); it('applies the defaultValue false when the field is of type checkbox and has no value', () => { render(
); expect(screen.queryByText('false')).not.toBeNull(); }); it('does not apply the defaultValue true when the field is of type checkbox and has a value', () => { render(
); expect(screen.queryByText('false')).not.toBeNull(); }); it('does not apply the defaultValue false when the field is of type checkbox and has a value', () => { render(
); expect(screen.queryByText('true')).not.toBeNull(); }); }); describe('format', () => { it('should format null values to an empty string to avoid console warnings about controlled/uncontrolled components', () => { let inputProps; render(
{props => { inputProps = props; return
; }} ); expect(inputProps.field.value).toEqual(''); }); it('should format undefined values to an empty string to avoid console warnings about controlled/uncontrolled components', () => { let inputProps; render(
{props => { inputProps = props; return
; }} ); expect(inputProps.field.value).toEqual(''); }); it('should format null default values to an empty string to avoid console warnings about controlled/uncontrolled components', () => { let inputProps; render(
{props => { inputProps = props; return
; }} ); expect(inputProps.field.value).toEqual(''); }); test('should apply the provided format function before passing the value to the real input', () => { render(
`${value} formatted`} source="test" children={({ id, field }) => { return ; }} defaultValue="test" />
); expect(screen.getByDisplayValue('test formatted')).not.toBeNull(); }); }); describe('parse', () => { test('should apply the provided parse function before applying the value from the real input', () => { render(
(value + 1).toString()} source="test" children={({ id, field }) => { useEffect(() => { field.onChange(999); }, [field]); return ; }} />
); expect(screen.getByDisplayValue('1000')).not.toBeNull(); }); test('should parse empty strings to null by default', async () => { const onSubmit = jest.fn(); render(
{ useEffect(() => { field.onChange(''); }, [field]); const value = useWatch({ name: 'test' }); return ( <>
'test' value in form:  {JSON.stringify(value)} ( {typeof value})
); }} />
); await screen.findByText('null (object)'); }); }); });