Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔥 Testing with jest fails with 'Native module RNFBAppModule not found. Re-check module install, linking, configuration, build and install steps.' #8189

Open
1 of 10 tasks
itsramiel opened this issue Dec 12, 2024 · 7 comments
Labels

Comments

@itsramiel
Copy link

Issue

Testing a react native app with an import from firebase such as import messaging from '@react-native-firebase/messaging'; causes jest to fail:

 FAIL  __tests__/App.test.tsx
  ● Test suite failed to run

    Native module RNFBAppModule not found. Re-check module install, linking, configuration, build and install steps.

    > 1 | import messaging from '@react-native-firebase/messaging';
        | ^
      2 | messaging;
      3 |
      4 | function App() {

      at new RNFBNativeEventEmitter (node_modules/@react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:25:13)
      at Object.<anonymous> (node_modules/@react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:106:16)
      at Object.require (node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js:20:1)
      at Object.require (node_modules/@react-native-firebase/app/lib/FirebaseApp.js:18:1)
      at Object.require (node_modules/@react-native-firebase/app/lib/internal/index.js:18:1)
      at Object.require (node_modules/@react-native-firebase/messaging/lib/index.js:28:1)
      at Object.require (App.tsx:1:1)
      at Object.require (__tests__/App.test.tsx:7:1)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.152 s
Ran all test suites.

Project Files

Javascript

Click To Expand

package.json:

{
  "name": "Firebase",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "@react-native-firebase/app": "^21.6.1",
    "@react-native-firebase/messaging": "^21.6.1",
    "react": "18.3.1",
    "react-native": "0.76.5"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/runtime": "^7.25.0",
    "@react-native-community/cli": "15.0.1",
    "@react-native-community/cli-platform-android": "15.0.1",
    "@react-native-community/cli-platform-ios": "15.0.1",
    "@react-native/babel-preset": "0.76.5",
    "@react-native/eslint-config": "0.76.5",
    "@react-native/metro-config": "0.76.5",
    "@react-native/typescript-config": "0.76.5",
    "@types/react": "^18.2.6",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.6.3",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-test-renderer": "18.3.1",
    "typescript": "5.0.4"
  },
  "engines": {
    "node": ">=18"
  },
  "packageManager": "[email protected]"
}

firebase.json for react-native-firebase v6:

Irrelevant here. Doesnt affect testing environment

# N/A

iOS

Click To Expand

ios/Podfile:

Irrelevant

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

Irrelevant

// N/A


Android

Click To Expand

Have you converted to AndroidX?

Irrelevant

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// N/A

android/app/build.gradle:

// N/A

android/settings.gradle:

// N/A

MainApplication.java:

// N/A

AndroidManifest.xml:

<!-- N/A -->


Environment

Click To Expand

react-native info output:

info Fetching system and libraries information...
System:
  OS: macOS 15.1
  CPU: (14) arm64 Apple M3 Max
  Memory: 1.75 GB / 36.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 20.11.1
    path: /private/var/folders/p1/47x14k7x3hs1y75l4l8qd9980000gn/T/xfs-2ded1f97/node
  Yarn:
    version: 3.6.4
    path: /private/var/folders/p1/47x14k7x3hs1y75l4l8qd9980000gn/T/xfs-2ded1f97/yarn
  npm:
    version: 10.2.4
    path: ~/.nvm/versions/node/v20.11.1/bin/npm
  Watchman:
    version: 2024.10.28.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.14.3
    path: /Users/itsramiel/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.1
      - iOS 18.1
      - macOS 15.1
      - tvOS 18.1
      - visionOS 2.1
      - watchOS 11.1
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.1 AI-241.18034.62.2412.12266719
  Xcode:
    version: 16.1/16B40
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 3.0.0
    path: /Users/itsramiel/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.76.5
    wanted: 0.76.5
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: Not found
  newArchEnabled: false
  • Platform that you're experiencing the issue on: None(testing env, jest)
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • e.g. 5.4.3
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID
  • Are you using TypeScript?
    • Y/N & VERSION


Info I find relevant:

So basically you can reproduce with:

import messaging from '@react-native-firebase/messaging';
messaging;

function App() {
  return null;
}

export default App;

The error is this:

    Native module RNFBAppModule not found. Re-check module install, linking, configuration, build and install steps.

    > 1 | import messaging from '@react-native-firebase/messaging';
        | ^
      2 | messaging;
      3 |
      4 | function App() {

      at new RNFBNativeEventEmitter (node_modules/@react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:25:13)
      at Object.<anonymous> (node_modules/@react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:106:16)
      at Object.require (node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js:20:1)
      at Object.require (node_modules/@react-native-firebase/app/lib/FirebaseApp.js:18:1)
      at Object.require (node_modules/@react-native-firebase/app/lib/internal/index.js:18:1)
      at Object.require (node_modules/@react-native-firebase/messaging/lib/index.js:28:1)
      at Object.require (App.tsx:1:1)
      at Object.require (__tests__/App.test.tsx:7:1)

The problem is that this import:
at Object.require (node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js:20:1)

is resolving to app/lib/internal/nativeModule.ios.js since apparently ios is the default platform in react native preset for jest.

Now this file imports from: app/lib/internal/nativeModuleAndroidIos.js

which tries to get the module from NativeModules which obv will return undefined in a jest env:

const nativeModule = NativeModules[moduleName];

which leads to the throwing of the error:

const RNFBAppModule = getReactNativeModule('RNFBAppModule');
if (!RNFBAppModule) {
throw new Error(
'Native module RNFBAppModule not found. Re-check module install, linking, configuration, build and install steps.',
);
}

@mikehardy
Copy link
Collaborator

Using jest to test modules that requires native modules will require mocking and setup of course, this is a typical jest use case you have and a typical jest need for that use case

A follow-on in this instance should be: well, how do they do it then? That is, how do we do our testing in our repo so it works for us?

https://github.com/invertase/react-native-firebase/blob/main/jest.config.js

which has

setupFiles: ['./jest.setup.ts'],

Which points to

https://github.com/invertase/react-native-firebase/blob/main/jest.setup.ts

I'd do what we do in that file - or! if there is a better way - please suggest anything better for that file as we use jest too and we welcome PRs.

Should work?

@itsramiel
Copy link
Author

What I would love to have is a mock file I could import and then mock the libary with that mock. This is a common thing that other libraries do, examples:

import mockRNCNetInfo from '@react-native-community/netinfo/jest/netinfo-mock.js';
jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo);
import mockRNLocalize from 'react-native-localize/mock/index.js';
jest.mock('react-native-localize', () => mockRNLocalize);
jest.mock('@react-native-async-storage/async-storage', () =>
  require('@react-native-async-storage/async-storage/jest/async-storage-mock')
);

If the library would provide such a mock that can be used internally plus for library users, then that would be perfect.

Note: The failing of jest is new. This didnt use to happen in 18.7.1 but did happen when upgrading to 21.6.1. Same was experiences by others, but their solution was to downgrade which is obv not the correct solution.

@mikehardy
Copy link
Collaborator

It would be great if we shipped a mock yes. I also maintain netinfo ( 👋 ), so I'm familiar with this.

So how did it go when you used that mock file in your jest setup?

There is only so much time in a day - if you opened a PR that added that mock to the list of files in package.json so it was shipped with @react-native-firebase/app that would be great, after you've confirmed it worked for you

@itsramiel
Copy link
Author

Yes, copy pasting jest.setup.js into my projects jest.setup.js does fix the tests, but the file is mocking react-native not the library. Shouldnt we expose a mock of the library instead? Or how is this setup file meant to be used? I am not sure if exposing a setup file that mocks react native is the best here

@mikehardy
Copy link
Collaborator

It mocks react-native yes, because we do module loading. It mocks the minimum to make that "work" (read as: not fail) in a jest environment, then for the rest of react-native, the mock is the actual implementation of react-native

What could possibly go wrong ;-)

You tested it and it worked for you, that's great news. No reason we couldn't ship it and people could use it if they like

@itsramiel
Copy link
Author

What could possibly go wrong ;-)

I am not familiar with jest but my initial thought was that if we mock rn, then does that override other mocks of rn that a user may already have. I am not very familiar with jest. maybe you already know, or I have to test

@mikehardy
Copy link
Collaborator

You'd have to test that, however if jest is already mocking things then I would assume (dangerous!) that when our jest says "import" for react-native we'll get the mocked one.

it may be then that our mocks will collide with other specific mocks, but ours is mocking the minimum we need - not sure what we can do about that.

Then the rest of the react native module from import is spread into our mock so it should still apply

I'm not sure a different way to do it though, we have a multi-module system and need to reach into react-native and inspect / load etc our native modules. In a jest context that has to be mocked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants