callstack / react-native-testing-library

🦉 Simple and complete React Native testing utilities that encourage good testing practices.
https://callstack.github.io/react-native-testing-library/
MIT License
3.04k stars 268 forks source link

Typescript and React Navigation app won't render (TypeError: Cannot read properties of undefined (reading 'current')) #1061

Closed Danondso closed 2 years ago

Danondso commented 2 years ago

Ask your Question

I have the following test where I'm trying to render my login screen.

// __tests__/App.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react-native';
import AppNavigator from '../src/screens';

jest.mock('../node_modules/react-native-spotify-remote', () => ({
  authorize: jest.fn(),
}));

it('Login Screen renders', async () => {
  render(<AppNavigator />);

  const loginText = await screen.findByText('a smol bean app');
  const loginButton = await screen.findAllByText(/Login/);

  expect(loginText).toBeTruthy();
  expect(loginButton.length).toBe(1);
});

// AppNavigator component /screens/index.ts
import React, { useMemo, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Provider as PaperProvider } from 'react-native-paper';
import { RootStackParamList } from '../types';
import DetailsScreen from './Details/Details';
import { DETAILS, LOGIN } from './constants/Screens';
import LoginScreen from './Login';

import {
  initialState,
  SpotifyAuthContext,
  SpotifyAuthentication,
} from '../context';

const Stack = createNativeStackNavigator<RootStackParamList>();

function ScreenIndex() {
  const [spotifyAuth, setSpotifyAuth] =
    useState<SpotifyAuthentication>(initialState);

  const authState = useMemo<SpotifyAuthContext>(
    () => [spotifyAuth, setSpotifyAuth],
    [spotifyAuth, setSpotifyAuth],
  );
  return (
    <SpotifyAuthContext.Provider value={authState}>
      <PaperProvider>
        <NavigationContainer>
          <Stack.Navigator initialRouteName={LOGIN}>
            <Stack.Screen
              options={{
                headerShown: false,
              }}
              name={LOGIN}
              component={LoginScreen}
            />
            <Stack.Screen name={DETAILS} component={DetailsScreen} />
          </Stack.Navigator>
        </NavigationContainer>
      </PaperProvider>
    </SpotifyAuthContext.Provider>
  );
}

export default ScreenIndex;

But every time I run the tests I end up getting this error. image

I've tried it with a super basic component as well (A View and Text component) and I still get the same error. I've read around here that there's something up when using TS and imports, does this seem like it's related? Thanks!

Danondso commented 2 years ago

Here's my package.json as well.

{
  "name": "bedfellow",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint .",
    "tsc": "tsc",
    "prepare": "husky install"
  },
  "dependencies": {
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/native-stack": "^6.2.5",
    "@types/react-native-dotenv": "^0.2.0",
    "axios": "0.24.0",
    "lottie-ios": "3.2.3",
    "react": "18.0.0",
    "react-native": "0.69.3",
    "react-native-dotenv": "^3.3.1",
    "react-native-lottie-splash-screen": "^1.0.1",
    "react-native-paper": "^4.12.4",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.10.1",
    "react-native-spotify-remote": "^0.3.10"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^3.0.1",
    "@testing-library/jest-native": "^4.0.11",
    "@testing-library/react-native": "^11.0.0",
    "@types/jest": "^27.4.0",
    "@types/react": "^17.0.38",
    "@types/react-native": "^0.66.10",
    "babel-jest": "^26.6.3",
    "eslint": "^7.32.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-plugin-import": "^2.25.3",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-react": "^7.28.0",
    "eslint-plugin-react-hooks": "^4.3.0",
    "husky": "^8.0.1",
    "jest": "^28.1.3",
    "metro-react-native-babel-preset": "^0.66.2",
    "prettier": "^2.7.1",
    "react-test-renderer": "17.0.2",
    "typescript": "^4.5.4"
  }
}
SpaghettiC0des commented 2 years ago

I have the same issue, I just recently upgraded a boilerplate to expo 46. You can check the issue here, https://github.com/karlmarxlopez/expo-ts-and-jest.

SpaghettiC0des commented 2 years ago

Actually, react-navigation does not cause the issue.

A simple test like this will also result in the same error. See my package.json here.

import 'react';
import {render} from '@testing-library/react-native';
import {Text} from 'react-native';

// import App from './App';

const App = () => <Text>Hello</Text>;

describe('<App/>', () => {
  it('should render without crashing', () => {
    const tree = render(<App />);
    expect(tree.toJSON()).not.toBeNull();
  });
});
Danondso commented 2 years ago

Okay good to know, I didn't think it was related as I put together a really simple functional component like your example and the same result happened.

I'm wondering if it's a version disparity in the library based on this issue. I know it's unrelated but I'm wondering if that's a clue at least.

EDIT: Well dang seems like the latest package.json has react 18 as a dependency. So that's probably an incorrect assumption.

Danondso commented 2 years ago

@karlmarxlopez Think I got it figured out, upgrade your devDependency of 'react-test-renderer' to match your version of react. I got it working on your repo, I guess the bump from 17 to 18 is causing the issue, shame it's manifesting so vaguely.

Danondso commented 2 years ago

Got this solved so closing out the issue.

mdjastrzebski commented 2 years ago

I've added the root cause/fix for this issue to our Troubleshooting guide: https://callstack.github.io/react-native-testing-library/docs/troubleshooting#matching-react-native-react--react-test-renderer-versions

najumasad commented 1 year ago

TypeError: Cannot read properties of undefined (reading 'debug') const {debug,getByTestId} = render() please help me to solve it @mdjastrzebski @Danondso @karlmarxlopez @pke @carlosdp I'm runing a simple test case in react native cli

const App = () => Hello; describe('', () => { test('should render without crashing', () => { const {toJSON,debug} = render() }); })

My package.json { "name": "abc", "version": "1.0.8", "private": true, "scripts": { "android": "react-native run-android --variant=playStoreDebug", "ios": "react-native run-ios", "build:ios": "react-native bundle --entry-file='index.js' --bundle-output='./ios/main.jsbundle' --dev=false --platform='ios'", "start": "react-native start", "test": "jest --config=./jest.config.js", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "pretty": "prettier --write 'src/*/.{tsx,ts,js}'", "generate-bundle": "react-native bundle --platform android --dev false --bundle-output android/app/src/main/assets/index.android.bundle --entry-file index.js" }, "dependencies": { "@babel/runtime": "^7.21.5", "@hmscore/react-native-hms-push": "^6.7.0-300", "@invertase/react-native-apple-authentication": "^2.2.2", "@react-native-community/checkbox": "^0.5.15", "@react-native-community/netinfo": "^9.3.10", "@react-native-firebase/analytics": "^17.5.0", "@react-native-firebase/app": "^17.5.0", "@react-native-firebase/auth": "^17.5.0", "@react-native-firebase/crashlytics": "^17.5.0", "@react-native-firebase/messaging": "^17.5.0", "@react-native-firebase/remote-config": "^17.5.0", "@react-native-google-signin/google-signin": "^9.1.0", "@react-native-masked-view/masked-view": "^0.2.9", "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/native": "^6.1.6", "@react-navigation/stack": "^6.3.16", "@reduxjs/toolkit": "^1.9.5", "axios": "^1.4.0", "force": "^0.0.3", "i18next": "^22.5.0", "lottie-ios": "3.4.0", "lottie-react-native": "^5.1.6", "metro-react-native-babel-preset": "^0.76.5", "promise": "^8.3.0", "react": "18.2.0", "react-native": "0.71.8", "react-native-appsflyer": "^6.10.3", "react-native-config": "^1.4.11", "react-native-device-info": "^10.3.0", "react-native-fast-image": "^8.6.3", "react-native-fbsdk-next": "^10.1.0", "react-native-freshchat-sdk": "^4.2.0", "react-native-gesture-handler": "^2.10.1", "react-native-get-random-values": "^1.8.0", "react-native-gradle-plugin": "^0.71.18", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-linear-gradient": "^2.6.2", "react-native-pager-view": "^6.2.0", "react-native-permissions": "^3.8.0", "react-native-portalize": "^1.0.7", "react-native-render-html": "^6.3.4", "react-native-restart": "0.0.27", "react-native-safe-area-context": "^4.5.3", "react-native-screens": "^3.20.0", "react-native-webengage": "^1.3.0", "react-native-webview": "^12.0.3", "react-navigation": "^4.4.4", "react-redux": "^8.0.5", "uuid": "^9.0.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@react-native-community/eslint-config": "^3.2.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-native": "^5.4.2", "@testing-library/react-native": "^12.1.2", "@types/jest": "^29.5.1", "@types/react-test-renderer": "^18", "@typescript-eslint/eslint-plugin": "^5.59.7", "@typescript-eslint/parser": "^5.59.7", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^29.5.0", "eslint": "^8.41.0", "@types/react": "~18.2.6", "jest": "^29.3.0", "jest-environment-node": "^29.5.0", "jest-expo": "^48.0.2", "jest-fetch-mock": "^3.0.3", "jest-native": "^3.0.0", "json-format": "^1.0.1", "prettier": "^2.8.8", "react-native-clean-project": "^4.0.1", "react-native-codegen": "0.71.5", "react-test-renderer": "18.2.0", "typescript": "^5.0.4" }, "jest": { "preset": "react-native", "moduleFileExtensions": [ "ts", "tsx", "js", "jsx", "json", "node" ], "detectOpenHandles": true } }

khushal87 commented 4 months ago

I am on 18.2.0 and getting this while using TouchableOpacity. Any help would be appreciated. 😄

TypeError: cleanupRef.current is not a function

      63 |
      64 |     const onPlayPauseMock = jest.fn();
    > 65 |     render(
         |           ^
      66 |       getComponent({
      67 |         fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
      68 |         item: {

      at current (node_modules/react-native/Libraries/Utilities/useRefEffect.js:36:20)
      at ref (node_modules/react-native/Libraries/Utilities/useMergeRefs.js:35:13)
      at ref (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12784:20)
      at safelyDetachRef (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13909:11)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13902:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13917:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13902:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13809:11)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13917:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13902:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13902:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13939:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13939:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13780:5)
      at recursivelyTraverseDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13902:9)
      at commitDeletionEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13767:5)
      at commitDeletionEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13992:9)
      at recursivelyTraverseMutationEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14165:9)
      at commitMutationEffectsOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13978:3)
      at commitMutationEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16053:5)
      at commitRootImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15933:5)
      at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15454:3)
      at callback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2597:22)
      at callback (node_modules/react/cjs/react.development.js:2667:24)
      at Object.flushActQueue [as act] (node_modules/react/cjs/react.development.js:2521:11)
      at act (node_modules/@testing-library/react-native/src/render-act.ts:11:21)
      at renderInternal (node_modules/@testing-library/react-native/src/render.tsx:58:33)
      at renderInternal (node_modules/@testing-library/react-native/src/render.tsx:29:10)
      at _callee$ (src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx:65:11)
      at call (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
      at Generator.tryCatch (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
      at Generator._invoke [as next] (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7)
      at Object.<anonymous> (node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
        console.error
    The above error occurred in the <View> component:

        at Component (/Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/jest/mockComponent.js:30:18)
        at /Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/Libraries/Animated/createAnimatedComponent.js:36:57
        at TouchableOpacity (/Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/Libraries/Components/Touchable/TouchableOpacity.js:132:23)
        at TouchableOpacity
        at View
        at Component (/Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/jest/mockComponent.js:30:18)
        at item (/Users/khushalagarwal/Stream/stream-chat-react-native/package/src/components/Attachment/AudioAttachment.tsx:84:11)
        at AudioAttachment{messageInput{audioAttachment}}
        at children (/Users/khushalagarwal/Stream/stream-chat-react-native/package/src/contexts/themeContext/ThemeContext.tsx:48:11)

    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

      at logCapturedError (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8661:23)
      at logCapturedError (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8694:5)
      at call (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:4092:12)
      at callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:4113:9)
      at commitUpdateQueue (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13232:13)
      at commitLayoutEffectOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14330:9)
      at commitLayoutMountEffects_complete (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14316:7)
      at commitLayoutEffects_begin (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14301:3)
      at commitLayoutEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16062:5)
      at commitRootImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15933:5)
      at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15454:3)
      at callback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2597:22)
      at callback (node_modules/scheduler/cjs/scheduler.development.js:266:34)
      at workLoop (node_modules/scheduler/cjs/scheduler.development.js:239:14)
      at Immediate.scheduledHostCallback [as _onImmediate] (node_modules/scheduler/cjs/scheduler.development.js:533:21)

ReferenceError: You are trying to access a property or method of the Jest environment after it has been torn down. From src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx.
mdjastrzebski commented 4 months ago

@khushal87 Your error: "ReferenceError: You are trying to access a property or method of the Jest environment after it has been torn down. From src/components/MessageInput/tests/AudioAttachmentUploadPreviewExpo.test.tsx." suggests that you did not wait for some async action to complete before the test has been tore done.

khushal87 commented 4 months ago

@mdjastrzebski this is same for Pressable as well


● AudioAttachmentExpo › handle play pause button when isPausedStatusAvailable unavailable and progress 1

TypeError: pressability.getEventHandlers is not a function

  72 |
  73 |     const onPlayPauseMock = jest.fn();
> 74 |     render(
     |           ^
  75 |       getComponent({
  76 |         fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
  77 |         item: {

at getEventHandlers (node_modules/react-native/Libraries/Pressability/usePressability.js:49:53) at Pressable (node_modules/react-native/Libraries/Components/Pressable/Pressable.js:336:40) at Component (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6351:18) at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9150:20) at updateForwardRef (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:11361:16) at beginWork$1 (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15811:12) at performUnitOfWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15745:5) at workLoopSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15717:7) at renderRootSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15422:20) at callback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2597:22) at callback (node_modules/react/cjs/react.development.js:2667:24) at Object.flushActQueue [as act] (node_modules/react/cjs/react.development.js:2521:11) at act (node_modules/@testing-library/react-native/src/render-act.ts:11:21) at renderInternal (node_modules/@testing-library/react-native/src/render.tsx:58:33) at renderInternal (node_modules/@testing-library/react-native/src/render.tsx:29:10) at _callee$ (src/components/MessageInput/tests/AudioAttachmentUploadPreviewExpo.test.tsx:74:11) at call (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16) at Generator.tryCatch (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17) at Generator._invoke [as next] (node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21) at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24) at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9) at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7) at Object. (node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12) console.error The above error occurred in the component:

    at accessible (/Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/Libraries/Components/Pressable/Pressable.js:206:5)
    at View
    at Component (/Users/khushalagarwal/Stream/stream-chat-react-native/package/node_modules/react-native/jest/mockComponent.js:30:18)
    at item (/Users/khushalagarwal/Stream/stream-chat-react-native/package/src/components/Attachment/AudioAttachment.tsx:84:11)
    at AudioAttachment{messageInput{audioAttachment}}
    at children (/Users/khushalagarwal/Stream/stream-chat-react-native/package/src/contexts/themeContext/ThemeContext.tsx:48:11)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

khushal87 commented 4 months ago

For me the functions that I am trying to test is not even running. The component simply fails in testing since it has Pressable or TouchableOpacity.