如何在玩笑中模拟 AWS 库

IT技术 reactjs unit-testing async-await jestjs
2021-05-21 13:26:53

我正在使用“aws-amplify”库中的 signIn 方法。在开玩笑中运行测试用例时,我无法从这个库调用 signIn 方法。

代码:

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 });
  }
}

测试文件:

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); 
});

在测试用例上方运行时,它总是进入 handleSubmit() 函数的 catch 部分。

如何从“aws-amplify”库调用 signIn 方法并测试正面/负面场景?

指导我,提前致谢。

3个回答

一种方法是模拟 signIn 函数并使用它。对于测试文件中的导入身份验证

import { Auth } from "aws-amplify";

然后在调用 handleSubmit 函数模拟 signIn 函数之前

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); 
});

我是这样做的:

import awsAmplify from 'aws-amplify'

jest.mock('aws-amplify')

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

这就是我使用 React Native CLI 和 React 测试库 📚 做到的:

使用 CLI 在我的 React Native App 的根目录上创建了mocks文件夹,里面aws-amplify.js文件。

在此处输入图片说明

mocks/aws-amplify.js 里面我有这个代码:

export const Auth = {
  currentSession: jest.fn().mockImplementation(() => {
    const session = {
      accessToken: {
        jwtToken: '123456',
      },
      idToken: {
        payload: {
          email: 'demo@test.com',
          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: 'demo@test.com',
          accessToken: '123cvb123',
          name: 'John Rambo',
          phone: '+46761022312',
          phoneVerified: false,
          attributes: {
            sub: 'abc123',
          },
        };

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

现在,在我的测试文件中,我有这个:

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: 'demo@user.com',
      },
    };
    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: 'notexisting@user.com',
      },
    };
    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();
  });
});

请记住,我使用的是 React.Context API,这就是您看到 AuthContext.Provider 包装器的原因。