Reputation: 145
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.
Upvotes: 13
Views: 8368
Reputation: 32472
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.
Upvotes: 1
Reputation: 3309
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(),
})),
}));
Upvotes: 0
Reputation: 1629
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(),
});
});
Upvotes: 0
Reputation: 123
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
}
})
Upvotes: 2
Reputation: 101
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
});
});
})();
Upvotes: 10