Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to mock AWS library in jest

I am using signIn method from 'aws-amplify' library. I am not able to call signIn method from this library while running test case in jest.

Code:

import { Auth } from "aws-amplify"; // import statement

//code for function
handleSubmit = async event => {
  event.preventDefault();
  this.setState({ isLoading: true });
  try {
    await Auth.signIn(this.state.username, this.state.password);
    this.props.history.push("/dashboard");
  } catch (e) {
    this.setState({ isLoading: false });
  }
}

Test file:

it('calls event handler; "handleSubmit"', async()  => {   
    const componentInstance = Wrapper2.dive().instance();

    componentInstance.setState({
        isLoading : false,
        username : "demo",
        password : "demo"
    })
    const event = {
        preventDefault : () => {}
    };
    await componentInstance.handleSubmit(event);
    expect(componentInstance.state.isLoading).toEqual(true); 
});

While running above test case, It always goes into catch section of handleSubmit() function.

How can I achieve calling signIn method from 'aws-amplify' library and testing positive/negative scenarios ?

Guide me, Thanks in advance.

like image 380
Alpesh Prajapati Avatar asked Aug 02 '18 09:08

Alpesh Prajapati


3 Answers

One way to do this is mocking signIn function and using it. For that import Auth in test file

import { Auth } from "aws-amplify";

then before calling handleSubmit function mock signIn function

it('calls event handler; "handleSubmit"', async()  => {   
    const componentInstance = Wrapper2.dive().instance();

    componentInstance.setState({
        isLoading : false,
        username : "demo",
        password : "demo"
    })
    const event = {
        preventDefault : () => {}
    };
    Auth.signIn = jest.fn().mockImplementation(
     () => {
     // return whatever you want to test
    });
    await componentInstance.handleSubmit(event);
    expect(componentInstance.state.isLoading).toEqual(true); 
});
like image 184
GansPotter Avatar answered Sep 29 '22 18:09

GansPotter


This is how I did it:

import awsAmplify from 'aws-amplify'

jest.mock('aws-amplify')

it('does something', ()  => {
  awsAmplify.Auth.signIn.mockRejectedValue('mock error')
  awsAmplify.Auth.currentAuthenticatedUser.mockResolvedValue('mock user')
  ...
})

like image 23
haxpanel Avatar answered Sep 29 '22 20:09

haxpanel


This is how I did it with React Native CLI & React Testing Library 📚:

Created mocks folder on the root of my React Native App with CLI with aws-amplify.js file inside.

enter image description here

Inside mocks/aws-amplify.js I have this code:

export const Auth = {
  currentSession: jest.fn().mockImplementation(() => {
    const session = {
      accessToken: {
        jwtToken: '123456',
      },
      idToken: {
        payload: {
          email: '[email protected]',
          sub: 'abc123',
        },
      },
    };
    return Promise.resolve(session);
  }),
  signOut: jest.fn(),
  signIn: jest.fn().mockImplementation(
    (email, pass) =>
      new Promise((resolve, reject) => {
        const userExists = user[email];

        if (userExists && pass === '12345678') {
          const signedUser = {
            username: 'abcdfg123',
            attributes: {email, name: 'John Rambo', phone: '+460777777777'},
            signInUserSession: {
              accessToken: {jwtToken: '123456'},
            },
          };
          return resolve(signedUser);
        }

        if (userExists) {
          return reject({
            code: 'NotAuthorizedException',
            name: 'NotAuthorizedException',
            message: 'Incorrect username or password.',
          });
        }

        return reject({
          code: 'UserNotFoundException',
          name: 'UserNotFoundException',
          message: 'User does not exist.',
        });
      }),
  ),
  signUp: jest.fn().mockImplementation(
    ({username, pass, attributes}) =>
      new Promise((resolve, reject) => {
        const newUser = {
          username: 'abcdfg123',
          email: username,
          name: attributes.name,
          signInUserSession: {
            accessToken: {jwtToken: '123456'},
          },
        };
        return resolve(newUser);
      }),
  ),
  confirmSignUp: jest.fn().mockImplementation(
    (email, code) =>
      new Promise((resolve, reject) => {
        const confirmedUser = {
          userConfirmed: true,
          username: 'abcdfg123',
          user: {username: email},
        };

        if (code === '123456') {
          return resolve(confirmedUser);
        }

        return reject({
          code: 'CodeMismatchException',
          name: 'CodeMismatchException',
          message: 'Invalid verification code provided, please try again.',
        });
      }),
  ),
  currentAuthenticatedUser: jest.fn().mockImplementation(
    () =>
      new Promise((resolve, reject) => {
        const currentUser = {
          username: 'abc123',
          email: '[email protected]',
          accessToken: '123cvb123',
          name: 'John Rambo',
          phone: '+46761022312',
          phoneVerified: false,
          attributes: {
            sub: 'abc123',
          },
        };

        return resolve(currentUser);
      }),
  ),
  updateUserAttributes: jest.fn(),
};

Now, in my test files I have this:

import React from 'react';
import {render, fireEvent, act} from '@testing-library/react-native';
import {AuthContext} from '../../context/AuthProvider';
import SignInScreen from '../SignInScreen';

describe('<SignInScreen />', () => {
  const navigation = {
    setOptions: jest.fn(),
    navigate: jest.fn(),
  };

  const currentSession = {
    username: '',
    email: '',
    accessToken: '',
  };
  const dispatchAuth = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  test('should SignIn user', async () => {
    const route = {
      params: {
        email: '[email protected]',
      },
    };
    const password = '12345678';
    const {getByPlaceholderText, getByTestId} = render(
      <AuthContext.Provider value={{currentSession, dispatchAuth}}>
        <SignInScreen navigation={navigation} route={route} />
      </AuthContext.Provider>,
    );

    const passwordInput = getByPlaceholderText('Password');
    fireEvent(passwordInput, 'onChangeText', password);

    const signInButton = getByTestId('signIn-button');
    await act(async () => await fireEvent(signInButton, 'press'));

    expect(navigation.navigate).toHaveBeenCalledWith('User');
  });

  test('should Not SignIn user with not existing username or wrong password', async () => {
    const route = {
      params: {
        email: '[email protected]',
      },
    };
    const password = '123';
    const {getByPlaceholderText, getByTestId, findByText} = render(
      <AuthContext.Provider value={{currentSession, dispatchAuth}}>
        <SignInScreen navigation={navigation} route={route} />
      </AuthContext.Provider>,
    );

    const passwordInput = getByPlaceholderText('Password');
    fireEvent(passwordInput, 'onChangeText', password);

    const signInButton = getByTestId('signIn-button');
    fireEvent(signInButton, 'press');

    expect(navigation.navigate).not.toHaveBeenCalledWith('User');
    expect(findByText('User does not exist.')).toBeDefined();
  });
});

Have in mind that, I'm using React.Context API, that's why you see the AuthContext.Provider wrapper.

like image 30
Cristian Echeverria Avatar answered Sep 29 '22 19:09

Cristian Echeverria