I'm working in a React Native project, where i want to do a snapshot test of my LoginComponent with Jest.
LoginComponent.js is seen here, where i'm using some functions from firebase:
import { StyleSheet, View, Image } from 'react-native'
import React, { useEffect, useState } from 'react'
import { useNavigation } from '@react-navigation/native';
import { getAuth, onAuthStateChanged, signInWithEmailAndPassword } from 'firebase/auth';
import {Title, Button, Headline, Subheading, Text, TextInput} from 'react-native-paper';
export default function LoginComponent() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigation = useNavigation();
const auth = getAuth();
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
navigation.navigate("Category");
}
})
return unsubscribe
}, [])
const handleLogin = () => {
signInWithEmailAndPassword(auth, email, password)
.then(userCredentials => {
const user = userCredentials.user;
console.log('Logged in with: ', user);
})
.catch(error => alert(error.message))
}
return (
<View style={styles.container}>
<View>
<Image style={{width: 120, height: 80, resizeMode: 'center'}} source=
{require('./41-410195_blue-cloud-clipart.png')} />
</View>
<View>
<Title style={styles.title}>The Organizer {"\n"}</Title>
</View>
<View>
<Headline>Sign in</Headline>
<Subheading>Hi there! Nice to see you again</Subheading>
</View>
<View>
<Text style={styles.inputText}>E-mail:</Text>
<TextInput style={styles.input} placeholder="Enter your email" value={email}
onChangeText={text => setEmail(text)}/>
<Text style={styles.inputText}>Password:</Text>
<TextInput style={styles.input} secureTextEntry placeholder="Enter your
password"
value={password} onChangeText={text => setPassword(text)}/>
</View>
<View>
<Button style={styles.buttonLogin} mode="contained" uppercase={false}
onPress={handleLogin}>
Login
</Button>
</View>
<View style={styles.buttonSignUpAndPassword}>
<Button style={styles.buttonContainer} uppercase={false} onPress={() =>
{navigation.navigate("SignUp")}}>
Sign up here
</Button>
<View style={styles.space} />
<Button style={styles.buttonContainer} uppercase={false} onPress={() =>
{navigation.navigate("ForgotPassword")}}>
Forgot password?
</Button>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
marginTop: 50
},
title: {
fontSize: 32,
fontWeight: 'bold',
},
inputText: {
paddingLeft: 14,
paddingTop: 8
},
input: {
padding: 10,
margin: 15,
width: 320,
height: 30,
},
buttonLogin: {
width: 200
},
buttonSignUpAndPassword: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 180
},
buttonContainer: {
flex: 1
},
space: {
width: 50,
height: 20,
},
});
I believe i need to create three mock functions because of auth, onAuthStateChanged and signInWithEmailAndPassword before my snapshot test can run succesfully.
This is how i have done it in my login.test.js:
import React from 'react';
import renderer from 'react-test-renderer'
import LoginComponent from '../components/Login/LoginComponent';
jest.mock('firebase/auth', () => {
return {
auth: jest.fn().mockReturnThis(),
signInWithEmailAndPassword: jest.fn(() => mockSignIn),
onAuthStateChanged: jest.fn(() => mockUserState)
}
})
test('renders loginComponent correctly', () => {
const tree = renderer.create(<LoginComponent/>).toJSON();
expect(tree).toMatchSnapshot();
});
And this is the error i am getting: The error
I don't know why i'm getting the navigation error, when it's a snapshot test. I'm more worried that my mocks of the firebase functions are not done in the right way.
CodePudding user response:
The issue seems to be with the useNavigation
hook. You might need to
(1) setup a mock for useNavigation:
const mockedNavigate = jest.fn();
jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
return {
...actualNav,
useNavigation: () => ({
navigate: mockedNavigate,
})
};
});
OR
(2) import NavigationContainer
from @react-navigation/native
and wrap your component with it when doing your tests like so:
import { NavigationContainer } from '@react-navigation/native';
...
...
test('renders loginComponent correctly', () => {
const tree = renderer.create(
<NavigationContainer>
<LoginComponent/>
</NavigationContainer>
).toJSON();
expect(tree).toMatchSnapshot();
});
NOTE: the above is just some dummy code for brevity.
Some other considerations/food for thought:
You might also have to setup a mock for
getAuth
when you are mockingfirebase/auth
signInWithEmailAndPassword
returns a promise, so your mock would have to be something likejest.mockResolvedValue()
instead of justjest.fn()
, so hopefully yourmockSignIn
value is taking care of that
Happy Testing!