I am trying to set up testing for my React app using Vitest, but I am experiencing an error which must be due to some missing dependency or error in my test suite. I'm unsure what exactly is the cause. When I try to run my tests I get the following error:
TypeError: Cannot read properties of null (reading 'useRef')
It says it's happening in my Login component, which contains a hook from react-hook-form
.
export default function Login() {
const { register, handleSubmit } = useForm();
^
When I remove this apparently problematic line it causes a similar problem elsewhere, where it says that an instance of useReducer
is null
.
This is what my setupTests.js looks like:
import { server } from './mocks/server';
import '@testing-library/jest-dom';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Here is my Vite config:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.js',
}
})
And here is my package.json:
{
"name": "my-project",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"knex": "knex",
"test": "vitest"
},
"dependencies": {
"bcrypt": "^5.0.1",
"cloudinary": "^1.30.0",
"connect-session-knex": "^3.0.0",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"express-session": "^1.17.3",
"knex": "^2.0.0",
"multer": "^1.4.5-lts.1",
"passport": "^0.5.3",
"passport-local": "^1.0.0",
"pg": "^8.7.3",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-hook-form": "^7.31.2",
"react-router-dom": "^6.3.0",
"sass": "^1.51.0",
"vitest": "^0.16.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.2.1",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@vitejs/plugin-react": "^1.3.0",
"jsdom": "^20.0.0",
"msw": "^0.42.3",
"vite": "^2.9.9"
}
}
All these hooks work perfectly fine outside of the tests, so I am not sure why they are undefined.
I tried installing @testing-library/react-hooks
in the hope that it might fix my problem but I was unable to do so as it doesn't appear to support React 18.
I'd really appreciate your support.
I had the exact same problem so I investigated a bit and I figured out a working solution.
@testing-library/react
> 13.1Use renderHook
method from @testing-library/react
package and wrap your hooks with it:
import React from 'react';
import { render, renderHook, screen } from '@testing-library/react';
import { describe, test } from 'vitest';
import { FormProvider, useForm } from 'react-hook-form';
describe('Input', () => {
test('should render an Input component', () => {
type FormValues = {
field: string;
};
const { result } = renderHook(
() => useForm<FormValues>({
defaultValues: {
field: '',
},
})
);
const methods = result.current;
const { register } = methods;
render(
<FormProvider {...methods}>
<form>
<input {...register('field')} data-testid="my-field" />
</form>
</FormProvider>
);
expect(screen.getByTestId('my-field').toHaveAttribute('name', 'field'));
});
});
First of all, the reason why the hooks are not working is because we are in a testing context so the functions we are using need to be mocked.
@testing-library
provides a solution to being able to use the hooks. Since @testing-library/react@^13.1
, the package @testing-library/react-hooks
is useless as you can read here: https://www.npmjs.com/package/@testing-library/react-hooks#user-content-a-note-about-react-18-support
Let's say that we have a test like this using React Hook Form and Vitest:
import React from 'react';
import { describe, test } from 'vitest';
import { FormProvider, useForm } from 'react-hook-form';
describe('Input', () => {
test('should render an Input component', () => {
type FormValues = {
field: string;
};
const methods = useForm<FormValues>({ defaultValues: { field: '' } });
const { register } = methods;
render(
<FormProvider {...methods}>
<form>
<input {...register('field')} data-testid="my-field" />
</form>
</FormProvider>
);
expect(screen.getByTestId('my-field').toHaveAttribute('name', 'field'));
});
});
This test will crash with the following error:
TypeError: Cannot read properties of null (reading 'useRef')
To make it work, add this import:
import { renderHook } from '@testing-library/react';
And replace the previous useForm
React Hook Form hook by:
const { result } = renderHook(
() => useForm<FormValues>({
defaultValues: {
field: ''
},
})
);
const methods = result.current;
And now the test is working well 🥳
@testing-library/react@^13.1
Run the following command to add @testing-library/react-hooks
to your project:
npm i --save-dev @testing-library/react-hooks
And import renderHook
from the package you just installed
import { renderHook } from '@testing-library/react-hooks`
The documentation can be found here: https://www.npmjs.com/package/@testing-library/react-hooks#table-of-contents
This went away for me when I added the react
plugin
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [react()],
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With