How to call or mock useForm on jest react native?
Asked Answered
W

3

5

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()
  })
})

here is the error pic
enter image description here

my question is similar to this

Wattage answered 6/4, 2022 at 4:51 Comment(0)
C
7

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

Centennial answered 8/3, 2023 at 2:27 Comment(0)
W
6

Finally I fixed this problem with this code

jest.mock('react-hook-form', () => ({
  ...jest.requireActual('react-hook-form'),
  Controller: () => <></>,
  useForm: () => ({
    control: () => ({}),
    handleSubmit: () => jest.fn(),
  }),
}))
Wattage answered 8/4, 2022 at 4:16 Comment(1)
can you share you share the entire test code for this?Anatomist
T
0

Found a good answer that doesn't require rewriting the code to make the test work: https://mcmap.net/q/1923030/-typeerror-with-vitest-cannot-read-properties-of-null-reading-39-useref-39

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

Thrawn answered 11/9 at 14:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.