Reputation: 458
I have a resuable component, called DatePicker like this
export interface IPDatePicker extends IProps {
control: any
label: string
placeholder: string
value?: string
errorText?: string
isRequired?: boolean
name: string
defaultValue?: any
onChangeText: (value: string) => void
minimumDate?: any
maximumDate?: any
timeOnly?: boolean
hideLabel?: boolean
labelMaxLine?: number
// setDateValue: any
}
const DatePicker: React.FC<IPDatePicker> = props => {
const todaysDate = new Date()
const [date, setDate] = useState<Date>(todaysDate)
const [isDatePickerOpen, setIsDatePickerOpen] = useState(false)
return (
<Controller
name={props?.name}
defaultValue={props?.defaultValue}
control={props?.control}
render={({field: {onChange, value}}: any) => {.....}
/>
The point is, the component needs 'control' as mandatory parameters.
The 'control' is from the parent page/component using useForm
const ParentPage = () => {
const {
control,
formState: {errors, isValid, isDirty},
} = useForm({
resolver,
mode: 'onChange',
defaultValues: {
date: '',
},
})
}
return (
...
<DatePicker
control={control} <-here
name='date'
...
/>
)
I tried to create a test file but I cant figure it out how to call useForm on jest. It always show Invalid hook call. Hooks can only be called inside of the body of a function component
import React from 'react'
import {render, fireEvent} from '@testing-library/react-native'
import {IProps} from '@app/presentations/types'
import {DatePicker} from '@app/presentations/_shared-components'
import {useForm} from 'react-hook-form'
interface IPDatePicker extends IProps {
control: any
label: string
placeholder: string
value?: string
errorText?: string
isRequired?: boolean
name: string
defaultValue?: any
onChangeText: (value: string) => void
}
function renderComponent(props: IPDatePicker) {
const component = render(<DatePicker {...props} />)
return {
component,
...component,
}
}
describe('DatePicker component', () => {
it('Should render correctly', () => {
const {control} = useForm({
mode: 'onChange',
defaultValues: {
date: '',
},
})
const component = renderComponent({
control: control,
label: 'Date picker',
placeholder: 'Placeholder',
onChangeText: v => {},
name: 'date',
})
expect(component).toMatchSnapshot()
})
})
my question is similar to this
Upvotes: 5
Views: 17135
Reputation: 1022
Found a good answer that doesn't require rewriting the code to make the test work: https://stackoverflow.com/a/76780938/6113915
Instead of mocking, call useForm
in the test. This will lead to the following error: TypeError: Cannot read properties of null (reading 'useRef')
. In order to call hooks in React testing library one must wrap them in renderHook.
Example of test:
const { result } = renderHook(() => useForm())
const methods = result.current;
render(
<FormProvider {...methods}>
<TextField label="testInput" />
</FormProvider>
);
expect(screen.getByRole('textbox')).toBeInTheDocument()
Now the TextField have access to a control
from useForm
Upvotes: 0
Reputation: 2288
The way that I manage to test something similar with the useForm
without mocking it was to create a component that includes the one that I wanted to test.
Example: Let's imagine that you want to test that DatePicker
component. So in order to use the control function from useForm I'll do:
// spec/javascript/DatePicker.spec.tsx file
import '@testing-library/jest-dom/extend-expect';
import { render } from '@testing-library/react';
import React from 'react';
const DatePickerWithForm = () => {
const { control } = useForm();
return <DatePicker control={control} ...some_other_attributes_here... />;
}
describe('DatePicker', () => {
it('shows something', () => {
const { getByText } = render(<DatePickerWithForm />);
expect(getByText('Something')).toBeInTheDocument();
});
});
After doing that no more hook errors were thrown in the console
Upvotes: 7
Reputation: 458
Finally I fixed this problem with this code
jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
Controller: () => <></>,
useForm: () => ({
control: () => ({}),
handleSubmit: () => jest.fn(),
}),
}))
Upvotes: 6