reactjsreact-nativejestjsbabel-jest

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components)... with correct import/export


Error

I'm trying to render a component in jest and getting the following

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check the render method of SplashScreen.

Code

src/screens/Splash/Splash.tsx

import React from 'react'
import { View, Image } from 'react-native'
import { styleSplash } from './styles'

const SplashScreen = props => {
  const {} = props

  return (
    <View style={styleSplash.main}>
      <Image style={styleSplash.logo} source={require('../../img/logo.png')} />
    </View>
  )
}
export default SplashScreen

__tests__/Splash-test.tsx

import React from 'react';
import 'react-native';
import SplashScreen from '../src/screens/Splash/Splash';
import { render, waitFor } from '@testing-library/react-native';

it('renders correctly', async () => {
  const tree = render(<SplashScreen />)
  await waitFor(() => {
    expect(tree).toMatchSnapshot();
  });
});

Issue

I understand the difference between named and default exports, but as you can see, my code looks correct(?) so I've been super confused. If my path or import was incorrect, VS Code will also just throw me an error so that would be obvious. Am I just going insane or is there something wrong with the packages I'm using?

The versions (not really sure what would be relevant here):

"react": "18.2.0",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react": "^14.0.0",
"@testing-library/react-native": "11.5.1",
"@tsconfig/react-native": "^2.0.2",
"babel-jest": "^29.7.0",
"eslint": "^8.19.0",
"jest": "^29.7.0",
"jest-expo": "^49.0.0",
"metro-react-native-babel-preset": "0.73.9",
"react-dom": "^18.2.0",
"react-test-renderer": "18.2.0",

Things I've tried

When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

which I couldn't fix. Seemed like using the testing-library was the more modern way to go, so I opted for that.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

    There seems to be an issue with your configuration that prevents React Native Testing Library from working correctly.
    Please check if you are using compatible versions of React Native and React Native Testing Library.

Instead, so I tried downgrading it to 11.5.1, which gave me the original error.

"transform": {
    "^.+\\.tsx?$": "babel-jest"
  }

to my jest config. No change in error message.


Solution

  • TL;DR: The component was indeed empty

    Details

    As you can see in my component, it used components from react-native including View and Image. However, I had no jest mocks setup for these components, so the page was not being rendered.

    Fix

    I added

    jest.mock('react-native', () => {
        return {
            View: () => {
                return <>test</>;
            },
            Image: () => {
                return <>test</>;
            }
        }
    });
    

    to my jest-setup file. And my Splash-test.tsx.snap file now shows

    exports[`renders correctly 1`] = `"test"`;
    

    which makes sense since all that gets rendered now is View. Which is just <>test</>.