Running Test with Jest, Firebase & React-Native
Asked Answered
S

5

12

I am trying to successfully run the boiler place App-test.js test that comes with the react-native installation. I have seen this test work "out of the box" with other projects, however, mine fails due to our integration with Firebase SDK. The long-term goal is to build out a test suite that mocks the calls to our firebase SDK (want to explore the following solutions: https://medium.com/stories-from-upstatement/jest-mocks-roasting-on-an-open-firestore-36fa55b76953, How do you mock Firebase Firestore methods using Jest? ), but I am stuck at the opening gates.

Here was the initial error I was receiving when trying to run the following command:

npm test __tests__/App-test.js

Error:

import { getFirebaseRoot } from './internal/registry/namespace';
export default () => ({
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import React from 'react';
    > 2 | import firebase from '@react-native-firebase/app';
        | ^
      3 | import analytics from '@react-native-firebase/analytics';
      4 | import '@react-native-firebase/auth';
      5 | import '@react-native-firebase/database';

It appears that our App.js file is the culprit.

import React from 'react';
import firebase from '@react-native-firebase/app';
import analytics from '@react-native-firebase/analytics';
import '@react-native-firebase/auth';
import '@react-native-firebase/database';
import '@react-native-firebase/crashlytics';
import '@react-native-firebase/functions';
import '@react-native-firebase/storage';

import { Provider } from 'react-redux';
import store from './app/store';
import Navigator from './app/routes';
import { loginUser } from './app/domain/Common/auth/actions';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.props = props;
  }

  // gets the current screen from navigation state
  getActiveRouteName = (navigationState) => {
    let routeName = null;

    if (!navigationState) {
      return null;
    }
    const route = navigationState.routes[navigationState.index];
    // dive into nested navigators
    if (route.routes) {
      return getActiveRouteName(route);
    }

    routeName = route.routeName;

    // for venues, append specific venue name
    if (route.params && route.params.venueName) {
      routeName += ` - ${route.params.venueName}`;
    }

    return routeName;
  }

  render() {
    return (
      <Provider store={store}>
        <Navigator
          onNavigationStateChange={(prevState, currentState) => {
            // track user screen changes in  Analytics
            const currentScreen = this.getActiveRouteName(currentState);
            const prevScreen = this.getActiveRouteName(prevState);

            if (prevScreen !== currentScreen) {
              analytics().setCurrentScreen(currentScreen);
            }
          }} />
      </Provider>
    );
  }
}

After researching this issue, the most promising lead to resolve the problem appears to be the following, https://github.com/invertase/react-native-firebase/issues/3035.

But I am now stuck with a new error:

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

    /Users/kyjelly/micturnTwo/node_modules/react-native/Libraries/Utilities/warnOnce.js:15
    const warnedKeys: {[string]: boolean} = {};
          ^^^^^^^^^^

    SyntaxError: Missing initializer in const declaration

      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)
      at Object.<anonymous> (node_modules/react-native/Libraries/react-native/react-native-implementation.js:14:18)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        3.101s

Here is the jest portion of my pacakge.json

 "jest": {
    "preset": "react-native",
    "transformIgnorePatterns": [
      "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@react-native-firebase/app)"
    ]
  }

And here is my jest.config.js

module.exports = {
  verbose: true,
  moduleNameMapper: {
    '@react-native-firebase/crashlytics': '<rootDir>/__tests__/__mocks__/firebase/crashlytics.js',
  }
};

Can anyone point my in the right direction? As I understand it, Jest has issues compiling certain files that are not native Javascript. But every solution I try leads to another rabbit hole of configuration attempts.

Selfgratification answered 5/4, 2020 at 13:0 Comment(0)
M
8

I have a fix that have worked to me and it is not related to ignoring libraries but configuring the Jest to mock the functions that I'm going to use. I've followed this comment on the link you pasted.

Finally my code looks like:

export const setupModulesMock = (() => {
    jest.mock('@react-native-firebase/crashlytics', () => {
        return () => ({
            log: jest.fn(),
            recordError: jest.fn(),
            // Any function you want to use or mock
        });
    });
})();
Mortify answered 30/10, 2020 at 8:20 Comment(2)
Adding this to my jest.setup.js worked perfectly, thanks!Receptionist
this helps alot thanksMaible
L
2

Ideally, the package should provide the jest setup. However, since it's not available, you'd need to create the mock implementations for each module of the Firebase package.

I have placed two files - jest.config.js and jest.setup.js and the latter is referenced in the former as a value of setupFiles property of the config.

Apart from other mock implementations, for Firebase, these are my setup. You could modify them based on your use case.

const mockedFirebaseCrashlyticsLog = jest.fn()
const mockedFirebaseCrashlyticsRecordError = jest.fn()
jest.mock('@react-native-firebase/crashlytics', () => {
  return () => ({
    log: mockedFirebaseCrashlyticsLog,
    recordError: mockedFirebaseCrashlyticsRecordError
  })
})

const mockedFirebaseAuthSignInWithCustomToken = jest.fn()
jest.mock('@react-native-firebase/auth', () => () => {
  return {
    signInWithCustomToken: mockedFirebaseAuthSignInWithCustomToken
  }
})

const mockedFirestoreCollection = jest.fn()
jest.mock('@react-native-firebase/firestore', () => () => {
  return {
    collection: mockedFirestoreCollection
  }
})

const mockedFirebaseAnalyticsLogEvent = jest.fn()
const mockedFirebaseAnalyticsLogLogin = jest.fn()
const mockedFirebaseAnalyticsSetUserId = jest.fn()
jest.mock('@react-native-firebase/analytics', () => () => {
  return {
    logEvent: mockedFirebaseAnalyticsLogEvent,
    logLogin: mockedFirebaseAnalyticsLogLogin,
    setUserId: mockedFirebaseAnalyticsSetUserId
  }
})
Lickspittle answered 14/3, 2021 at 3:51 Comment(0)
I
0

I solved this by creating mock of @react-native-firebase/dynamic-links in this way

jest.mock('@react-native-firebase/dynamic-links', () => {
  return () => ({
    onLink: jest.fn(),
  });
});
Insatiate answered 27/1, 2022 at 5:43 Comment(0)
G
0

If you have a jest.setup.js file, or a ___mocks___ folder, you probably want to add this code to one of those:

jest.mock("@react-native-firebase/analytics", () => ({
  analytics: jest.fn(() => ({
    logEvent: jest.fn(),
    setUserProperties: jest.fn(),
    setUserId: jest.fn(),
    setCurrentScreen: jest.fn(),
  })),
}));
Goodwin answered 7/10, 2022 at 23:41 Comment(0)
V
0

In my case, I only installed:

  • "@react-native-firebase/app": "^20.3.0",
  • "@react-native-firebase/auth": "^20.0.0",
  • "@react-native-firebase/messaging": "^20.3.0",

So, my mock file is like the following:

// rn-firebase.js

import {jest} from '@jest/globals';

jest.mock('@react-native-firebase/app', () => {
  return () => ({
    delete: jest.fn(),
  });
});

jest.mock('@react-native-firebase/auth', () => {
  return () => ({
    onAuthStateChanged: jest.fn(),
  });
});

jest.mock('@react-native-firebase/messaging', () => {
  const module = () => ({
    getToken: jest.fn(() => '1234'),
  });

  module.AuthorizationStatus = {
    NOT_DETERMINED: -1,
    DENIED: 0,
    AUTHORIZED: 1,
    PROVISIONAL: 2,
  };

  return module;
});

I put it in the list of setupFilesAfterEnv on the jest.config.js file:

// jest.config.js

module.exports = {
  preset: 'react-native',
  
  ~ ~ ~

  setupFilesAfterEnv: [
    '<rootDir>/mocks/rn-firebase.js',
  ],
  
  ~ ~ ~

These works properly.

Vaulting answered 8/8, 2024 at 6:23 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.