I have an expo react-native web component that renders fine on web but fails under test:
import React, { useState, useEffect } from "react";
import { View } from "react-native";
const timePickerWeb = (date: Date, setDate: React.Dispatch<React.SetStateAction<Date>>) => {
const getHours = (date.getHours() % 12 || 12).toString()
const [hours, setHours] = useState(getHours)
useEffect(() => {
let newdate = date
newdate.setHours(parseInt(hours))
setDate(newdate)
}, [hours])
return (
<View testID="webTimePicker" style={{justifyContent:"center", flexDirection:"row"}}>
<TimeSelector hours={hours} setHours={setHours} />
</View>
)
}
export default timePickerWeb;
test:
import { screen, render } form '@testing-library/react-native';
import timePickerWeb from './timePickerWeb'
it('renders the web picker', () => {
const mockSetEventDate = jest.fn();
const testDate = new Date(1680854389743);
const tree = render(timePickerWeb(testDate, mockSetEventDate)).toJSON();
expect(tree).toMatchSnapshot();
expect(screen.getByTestId('webTimePicker')).toBeTruthy();
});
this fails when it gets to the first useState call in timePickerWeb:
console.error
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
4 | const timePickerWeb = (date: Date, setDate: React.Dispatch<React.SetStateAction<Date>>) => {
5 | const getHours = (date.getHours() % 12 || 12).toString()
> 6 | const [hours, setHours] = useState(getHours)
| ^
7 |
8 | useEffect(() => {
9 | let newdate = date
TypeError: Cannot read properties of null (reading 'useState')
4 | const timePickerWeb = (date: Date, setDate: React.Dispatch<React.SetStateAction<Date>>) => {
5 | const getHours = (date.getHours() % 12 || 12).toString()
> 6 | const [hours, setHours] = useState(getHours)
| ^
7 |
8 | useEffect(() => {
9 | let newdate = date
This is only a problem when testing this component. Other components that have useState or useEffect in them pass their tests without issue. When I remove the useState and useEffect then it works. I don't think this is a hooks issue because if I add useContext or useNavigation (without useState or useEffect) then there is no issue.
I checked for multiple versions of react with npm ls react
and found that I did have 18.1.0 for everything expect react
as a dependency of react-test-renderer
as a dependency of jest-expo
. I fixed that by changing jest-expo
from 48 to 47 and adding peerDependencies
for react: 18.1
to my package.json file. There is no 18.2 in the npm ls react
or in package-lock
.