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

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!



Solution 1:[1]

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',
      },
    ],
  ],
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vasyl Nahuliak