Home > OS >  Snapshot testing a component that uses firebase functions - Mock in jest
Snapshot testing a component that uses firebase functions - Mock in jest

Time:04-12

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 mocking firebase/auth

  • signInWithEmailAndPassword returns a promise, so your mock would have to be something like jest.mockResolvedValue() instead of just jest.fn(), so hopefully your mockSignIn value is taking care of that

Happy Testing!

  • Related