react-native-testing-library with typescript does not work

2.9k views Asked by At

I've tried for days many ways to set up @testing-library/react-native with typescript following a sort of guides but still not able to render a simple component.

Roughly, my stack is react native with typescript and jest with ts-jest and react-native-testing-library. I'm following these guidelines among others:

This is the error I'm getting for the simple test component below:

ReferenceError: React is not defined

Component:

import React from 'react'
import { View, Text } from 'react-native'

const SomeComponent = () => {
  return (
    <View>
      <Text>Hello</Text>
    </View>
  )
}

export default SomeComponent

Test:

import { render } from '@testing-library/react-native'
import SomeComponent from './SomeComponent'

describe('<SomeComponent>', () => {
  it('should render some component', () => {
    const { getByText } = render(<SomeComponent />)
    expect(getByText(/hello/i)).toBeDefined()
  })
})

Follow a bunch of configurations for reference:

Dependencies:

{
  "name": "connect",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "react-native start",
    "debug": "open 'rndebugger://set-debugger-loc?host=localhost&port=8081' && react-native start",
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "pod": "npx pod-install",
    "test": "jest",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
  },
  "dependencies": {
    "@airbrake/browser": "^2.1.7",
    "@react-navigation/bottom-tabs": "^6.2.0",
    "@react-navigation/native": "^6.0.8",
    "@react-navigation/native-stack": "^6.5.1",
    "@reduxjs/toolkit": "^1.8.0",
    "@rneui/base": "^4.0.0-rc.1",
    "@rneui/themed": "^4.0.0-rc.1",
    "@types/react": "^17",
    "@types/react-native-dotenv": "^0.2.0",
    "@types/react-redux": "^7.1.23",
    "axios": "^0.26.1",
    "formik": "^2.2.9",
    "http-status": "^1.5.0",
    "moment": "^2.29.2",
    "react": "17.0.2",
    "react-native": "0.67.4",
    "react-native-blob-util": "^0.13.8",
    "react-native-dotenv": "^3.3.1",
    "react-native-dropdownalert": "^4.5.1",
    "react-native-error-boundary": "^1.1.12",
    "react-native-loading-spinner-overlay": "^2.0.0",
    "react-native-safe-area-context": "^4.2.2",
    "react-native-screens": "^3.13.1",
    "react-native-splash-screen": "^3.3.0",
    "react-native-vector-icons": "^9.1.0",
    "react-redux": "^7.2.6",
    "redux-persist": "^6.0.0",
    "redux-persist-filesystem-storage": "^4.0.0",
    "use-debounce": "^7.0.1",
    "yup": "^0.32.11"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/preset-env": "^7.16.11",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^3.0.1",
    "@testing-library/jest-native": "^4.0.4",
    "@testing-library/react-native": "^9.1.0",
    "@types/jest": "^27.4.1",
    "@types/react-native": "^0.66.15",
    "@types/react-native-loading-spinner-overlay": "^0.5.3",
    "@types/react-test-renderer": "^17.0.1",
    "babel-jest": "^27.5.1",
    "eslint": "7.32.0",
    "jest": "^27.5.1",
    "metro-react-native-babel-preset": "^0.70.1",
    "react-addons-test-utils": "^15.6.2",
    "react-native-typescript-transformer": "^1.2.13",
    "react-test-renderer": "18.0.0",
    "ts-jest": "^27.1.4",
    "typescript": "^4.4.4"
  },
  "resolutions": {
    "@types/react": "^17"
  }
}

jest.config.js

const { defaults: tsjPreset } = require('ts-jest/presets')

module.exports = {
  ...tsjPreset,
  preset: 'react-native',
  transform: {
    ...tsjPreset.transform,
    '\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
  },
  globals: {
    'ts-jest': {
      babelConfig: true,
    },
  },
  transformIgnorePatterns: [
    '/node_modules/(?!(@rneui|@react-native|react-native|react-native-size-matters|react-native-ratings|redux-persist-filesystem-storage|react-native-blob-util)/)',
  ],
  setupFiles: ['./jest.setup.js'],
  cacheDirectory: '.jest/cache',
}

babel.config.js

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'module:react-native-dotenv',
      {
        moduleName: 'react-native-dotenv',
      },
    ],
  ],
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "lib": ["es2017"],                        /* Specify library files to be included in the compilation. */
    "allowJs": true,                          /* Allow javascript files to be compiled. */
    "jsx": "react-native",                    /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "noEmit": true,                           /* Do not emit outputs. */
    "isolatedModules": true,                  /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
    "strict": true,                           /* Enable all strict type-checking options. */
    "moduleResolution": "node",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "allowSyntheticDefaultImports": true,     /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "skipLibCheck": false,                    /* Skip type checking of declaration files. */
    "resolveJsonModule": true                 /* Allows importing modules with a ‘.json’ extension, which is a common practice in node projects. */
  },
  "exclude": [
    "node_modules", "babel.config.js", "metro.config.js", "jest.config.js"
  ]
}

tsconfig.spec.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "jsx": "react"
  }
}

rn-cli.config.js

module.exports = {
  getTransformModulePath() {
    return require.resolve('react-native-typescript-transformer')
  },
  getSourceExts() {
    return ['ts', 'tsx']
  },
}

There is a similar open question about this setup here Setup for React Native/TypeScript/Testing Library/Jest not working

Thanks!

2

There are 2 answers

2
Vasyl Nahuliak On

You need run npm install @babel/plugin-transform-react-jsx --save-dev into terminal and add plugin into babel.config.js

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'module:react-native-dotenv',
      {
        moduleName: 'react-native-dotenv',
      },
    ],
    // add new plugin
    [
      '@babel/plugin-transform-react-jsx',
      {
        runtime: 'automatic',
      },
    ],
  ],
}
0
Maciej Jastrzebski On

You can use the official RNTL example that showcases a proper RNTL which also includes TypeScript.

Config issues like yours are hard to resolve as some small hard to notice issues might easily break the setup, so it's usually easiest to start with working setup.