How to do unit testing in react native that uses firebase? - javascript

Im quite new to jest unit testing, so stuff like mocking modules is confusing.
In react native, there is a component that uses firebase databse that returns data from a given ref:
// when the data of the current user is available
userRef.child(user.uid).on('value', snap => {
// check of val() consists data
if (snap.val()) {
let
authUser = snap.val(),
isPatient = authUser.type === "Patient",
// We update the state object so that the component is re-rendered
this.setState({
// the ID of the current user
authUserUID: user.uid,
// the type of the current user (i.e. Doctor or Patient)
authUserType: snap.val().type,
// title of the dashboard based on the current user type
activeTitle: snap.val().type === "Doctor" ? "My Patients" : "My Doctors",
});
}
});
I'm now trying to do unit testing which uses this component:
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import LaunchScreen from "../../App/Containers/LaunchScreen";
test('LaunchScreen', () => {
const tree = renderer.create( <LaunchScreen / > ).toJSON()
expect(tree).toMatchSnapshot()
})
But it gives a weird error
RNFirebase core module was not found natively on iOS, ensure you have correctly included the RNFirebase pod in your projects Podfile and have run pod install
I have no idea since the firebase does return data if I run it. So why is it saying that RNFirebase cannot be found?
Thanks
Update
One of the answers have given a nice step by step instructions, and although it solves partially the proposed question; the error still persists. For example; I'm now getting this new error:
console.error node_modules\react-test-renderer\cjs\react-test-renderer.development.js:5530
The above error occurred in the component:
in LaunchScreen
Consider adding an error boundary to your tree to customize error handling behavior.
TypeError: _reactNativeFirebase2.default.app is not a function

https://gist.github.com/himanshusinghs/bd86262ce3c9e6f4d691b5242de707ef
Above is the link to a gist containing the mock of React Native Firebase. Implementation instructions are also there. I am summarising them here as well -
1. You will be mocking a node_module and to do so there are multiple ways depending upon your use case. But since you will need to mock Firebase for almost every component that utilizes it, we will be implementing a global mock of React Native Firebase module.
2. Create a __mocks__ folder in your project's root directory adjacent to your node_modules folder.
3. Now create a file named react-native-firebase.js inside the __mocks__ directory.
4. Copy paste the contents from RNFirebaseMock.js in the above gist to your react-native-firebase.js file.
How this works ?
Jest has an auto mocking feature. Now every time you will run your test cases using Jest, and whenever any of your test case will require react-native-firebase module, Jest will first look into __mocks__ folder and see if there is a react-native-firebase.js containing some mock implementation of the required module.
If there is then jest will require that mock implementation instead of original module otherwise it will continue on to require original react-native-firebase module.
Things to be noted
You need to observe that the name of the mock file that we created react-native-firebase.js inside __mocks__ folder is similar to the name of installation folder of actual react-native-firebase module. Just go to node_modules and scroll down till you find react-native-firebase folder.
Yes, the name of your mock implementation of a module need to be exactly same as the name of the module itself.
Things to do this point onwards
Congratulations for you started with unit testing and chose an awesome framework for the same. Trust me, testing react-native or react is such a PITA (Pain in the Ass) that you should consider going through Jest documentation seriously and primarily focus on the mock part.
Later you may very well encounter problems while setting up Jest for react-native or react and there the documentation will come in handy.
Here are some series of tutorials and references that helped me get started with Jest and unit testing react and react-native -
Jest Documentation
Testing React and React Native using Jest/Enzyme setup
Reference article for Mocks, Stubs and Fakes
Testing Redux - P1
Testing Redux - P2
Testing Redux - P3
Solution for the error after applying RNFirebaseMock
The error that you now are getting is because there doesn't exist a function named app under default export of your mock. So let create it.
Go to your mocks directory and open react-native-firebase-mock.js. look for export default class RNFirebase, inside that class there are several static methods with no implementation. Create one function doing nothing in the class with the name app.
Your default exported class should look something like this now -
export default class RNFirebase {
static initializeApp() {
RNFirebase.firebase = new MockFirebase()
RNFirebase.promises = []
return RNFirebase.firebase
}
static reset() {
RNFirebase.promises = []
RNFirebase.firebase.databaseInstance = null
}
static waitForPromises() {
return Promise.all(RNFirebase.promises)
}
static analytics () {}
static app () {}
}
This should do the trick, however I belive you are extensively using Firebase. In my case a mock implementation as simple as the one I gave you did the trick for me.
If you are extensively using most of the APIs of Firebase then you are bound to get more errors like you just saw because we haven't yet added mock implementations for all the APIs of RNFirebase in our Firebase mock.
If that case shall ever arise, I would suggest that you look at this mock implementation of Firebase which I guess covers the Firebase completely.

Jest runs in node and does not have access to the native apis, so you'll need to mock the react-native-firebase / RNFirebase module for this to work.
see https://github.com/invertase/react-native-firebase/issues/162

Related

Correct way to use dynamic imports in Vite + Vue

We have an app where we've been using a dynamic import syntax in our route definitions, like so:
...
component: () => import('./components/SomeComponent'),
We recently transitioned to vite, and since the switch, we've been catching TypeError: Failed to fetch dynamically imported module whenever we deploy a new version of the app.
According to this SO post, this is happening because the hash for the files are invalidated on new deploys, but why are the files still being referenced with the previous hashes, when we are shipping a new build altogether?
I also found a previous issue that ran into the same error, and found this link in its thread that talked about how rollup expects a specific syntax for dynamic imports:
// current
component: () => import('./components/SomeComponent')
// expected?
component: () => import('./components/SomeComponent.vue')
Could this be why we are getting that Failed to fetch dynamically... error? Because my dynamic imports are missing the file extensions? I am a little confused, because the dynamic imports seem to still work even without the file extensions, it's just that we are catching errors on fresh deploys.

How to get values from the context of a node_modules folder component into another react app

I want to be able to access a value from a npm package library context.
I've tried that this way:
import { DocViewerContext } from '#cyntler/react-doc-viewer/dist/esm/store/DocViewerProvider'
const test = useContext(DocViewerContext)
console.log({ test })
But unfortunatelly I cannot see the data being changed when I do some stuff in that component.
To tell you the truth I think I am not doing the right thing
I tried to do some research and I've found the following question here: Providing React Context to an imported node module

How can I use Firebase 9.x + Flow

I'm working on a NextJS project using Flow and I'm trying to import Firebase latest version 9.1.3, but when I try to use it, Flow complains that cannot find the module.
// Error: Cannot resolve module `firebase/app`.Flow(cannot-resolve-module)
import { initializeApp, getApps } from 'firebase/app';
import { getAnalytics } from 'firebase/analytics';
I only found an old solution on flow-typed for Firebase 5.x.x, but API has changed since then, and manually writing a Library Definition is super time consuming.
I noticed that Firebase uses Typescript, is there a way I can import/convert to use Flow?
No flow types and TS types are not compatible although they achieve the same goal they are different in their typing philosophy.
Regarding firebase types, because firebase doesn't use flow, flow-typed is the correct place to retrieve them if the existed but no one has done so for firebase types for a while.
I have personally made a start in a project I started a while back but you may need to add more to suit your usecase (firebase types in my project). If these suit your usecase as a base I'm happy to commit them into flow-typed but I'll just need to include some tests.

Jest: Error when trying to import Native Modules; unable to prevent with Mock

I've recently been brought on to a team as Test Engineer and I'm trying to get Jest unit tests up and running on our React Native app. My predecessor has already authored dozens of unit tests, most of which are not running successfully.
I'm getting the following error when running npm test
FAIL __tests__/index.test.js
● Test suite failed to run
TypeError: Cannot read property '_addDeviceToGroup' of undefined
4 | } from 'react-native';
5 | const {
> 6 | _addDeviceToGroup,
| ^
7 | } = NativeModules._BleAssociator
8 | const {
9 | _queryName,
at Object._addDeviceToGroup (app/utils/mesh.js:6:3)
at Object.<anonymous> (app/actions/hierarchy.js:26:1)
at Object.<anonymous> (app/actions/organizations.js:14:1)
It seems as though the issue arose when we implemented custom Native Modules written by our backend team (again, before my joining the team).
After some research, I decided to proceed under the assumption that this has to do with Jest's inability to parse the Objective-C in the Engine that's feeding in the Native Modules and not some issue with our stack (happy to consider that possibility, though).
I've reviewed the Jest documentation, combing specifically through a couple relevant documents (Mock Functions, Using Jest with ES Module Imports, Testing Native Modules with Jest Mock, React Native Modules Guide)
My issue appears to be identical to this issue; however, the fix is not working for me. Even when mocking the NativeModules, I get the same error.
I've become familiar with the notion that Jest mocks are hoisted above the import statements, but it's not clear to me why the mocks are in the describe block in the issue I linked above (other than maybe to reset the mock function for each new test in case so as to not confound the .mock property's return data... I digress).
To me, it seems the error is occurring during the imports, before any of the code is executed. To test this, I've gone back and forth, commenting out everything but the import statements and the mocks. Doing this, I still get the same error. This is also the case when I use a beforeEach() mocha statement, as in the solution to the issue linked above.
The only thing that fixes this error commenting out the imports altogether.
I have not tried error handling (try/catch), as I'm not certain how I could still successfully import the component I'm testing if the catch block is executed.
Sorry for all that background. I have spent a couple workdays on this, so I want to make certain all my bases are covered.
Here's an example test:
/__tests__/app/components/Onboarding/Splash/Splash.test.js
import {
NativeModules,
} from 'react-native';
import { Splash } from '../../../../../app/components/Onboarding/Splash/Splash.js';
// import login from '../../../../../app/actions/login';
// NativeModules._BleAssociator._addDeviceToGroup = jest.fn();
// login = jest.fn;
export default function({React, shallow}) {
const props = {
// some test props
};
function make({navigation, getUserInfo, verifyUser, login} = props) {
return shallow(
// renders the component with props
);
}
describe('<Splash />', () => {
// I added this part (didn't help)
beforeEach(() => {
NativeModules._BleAssociator._addDeviceToGroup = jest.fn();
login = jest.fn;
});
// end part I added
// stuff (all the tests are in here)
});
}
The NativeModules and login imports, the commented out lines, and the beforeEach() block are things I've tried intermittently to no avail.
When trying to trace this error, I found that commenting out import statement in the original Splash.js that run scripts (as ES6 import runs the script it references) that try to import NativeModules fixes the error I see. As you might have gleaned from the stack trace, these go many levels deep.
PHEW. If you've read this far, I really appreciate the help.
Sorry to have such a long and complicated question. As you can see, we have a large and convoluted stack. It's possible the fix from the issue above isn't working because of how many chained imports happen before getting to the error.
I'd love it if it's a tiny fix that I'm missing or if there was some sort of "shallow"-ish import that I'm not aware of.
Thanks a bajillion for your help. Any input is welcome.
I found the solution to this. I had been worried that perhaps the mocks weren't being tracked through all the import statement. What was really happening was I was formatting the mocks wrong.
I did not see this in the standard Jest documentation, but instead found it here.
Adding this to my *.test.js files worked:
import { NativeModules } from 'react-native';
jest.mock('NativeModules', () => {
return {
_BleAssociator: {
_addDeviceToGroup: jest.fn()
},
// ... and so on for all the other methods expected in NodeModules
};
});
Just for posterity's sake, I think this would be best kept in its own script and imported into the tests... I haven't tried this yet.

Using Firebase with Webpack and TypeScript

I'm trying to pull some data from a Firebase instance, but am running into an issue when trying to bind it to a variable. I'm using TypeScript and Webpack to build.
main.ts
import * as Firebase from 'firebase';
class filter {
constructor(){
let ref = new Firebase('my-url-here');
}
}
The typings and npm module are installed and working, and Visual Code brings up no errors, but when I hit the browser I get:
ERROR
TypeError: Firebase is not a constructor
..
Logging Firebase to the console returns an object with methods like auth, app and database, but none of these seem to work either (or I'm calling them incorrectly). Any ideas?
A general best practice on how to incorporate Firebase into a Webpack/TypeScript would be just as welcome.
In my project i had the same error: It was caused by the firebase.json file which i guess got picked up by webpack.
As i can only guess why it happened: Webpack creating a symbol "Firebase" which replaced the constructor of firebase itself.
Have you done a firebase init in your directory?
Also see : https://github.com/angular/angularfire2/issues/187

Categories

Resources