【问题标题】:How to mock Firebase Auth methods? (React, Testing Library)如何模拟 Firebase Auth 方法? (反应,测试库)
【发布时间】:2020-10-13 15:43:12
【问题描述】:

我有以下组件:

import React from "react";
import Firebase from "../../Firebase";

const SignOutButton = () => (
  <button type="button" onClick={() => Firebase.auth().signOut()}>
    Sign Out
  </button>
);

export default SignOutButton;

我想测试Firebase.auth().signOut 是否被称为onClick

我在Firebase.authelsewhere 找到了这个模拟:

const authMock = jest.fn(() => {
  return {
    createUserAndRetrieveDataWithEmailAndPassword: jest.fn(() =>
      Promise.resolve(true)
    ),
    sendPasswordResetEmail: jest.fn(() => Promise.resolve(true)),
    signInAndRetrieveDataWithEmailAndPassword: jest.fn(() =>
      Promise.resolve(true)
    ),
    fetchSignInMethodsForEmail: jest.fn(() => Promise.resolve(true)),
    signOut: jest.fn(() => {
      Promise.resolve(true);
    }),
    onAuthStateChanged: jest.fn(),
    currentUser: {
      sendEmailVerification: jest.fn(() => Promise.resolve(true))
    }
  };
});

export { authMock };

在 SignOutButton.test 我有:

import React from "react";
import { render, cleanup, fireEvent } from "@testing-library/react";
import SignOutButton from "../.";
import Firebase from "../../../Firebase";
import { authMock } from "../../../../setupTests";
// @ts-ignore
Firebase.auth = authMock;

describe("<SignOutButton />", () => {
  afterEach(cleanup);

  it("calls Firebase signOut on click", async () => {
    const { getByText } = render(<SignOutButton />);
    const button = getByText("Sign Out");

    fireEvent.click(button);

    expect(Firebase.auth().signOut).toHaveBeenCalled();
  });
});

我的测试结果是预期调用为 1,但接收为 0。

我做错了什么?

谢谢!

【问题讨论】:

    标签: reactjs firebase jestjs mocking react-testing-library


    【解决方案1】:

    您的测试存在以下问题:

    1. 您应该在将Firebase.auth 方法替换为authMock 后导入SignOutButton 组件。否则,Firebase.auth 方法是原始版本而不是模拟版本。您可以使用console.log(Firebase.auth) 进行检查。

    2. 您应该为Firebase.auth 方法的返回值返回相同的引用。否则,断言将失败。

    完整的单元测试解决方案:

    SignOutButton.tsx:

    import React from 'react';
    import Firebase from './firebase';
    
    console.log(Firebase.auth);
    console.log('should keep same reference to authObject:', Firebase.auth() === Firebase.auth());
    
    const SignOutButton = () => (
      <button type="button" onClick={() => Firebase.auth().signOut()}>
        Sign Out
      </button>
    );
    
    export default SignOutButton;
    

    firebase.ts:

    export default {
      auth() {
        console.log('auth real implementation');
        return this;
      },
      async signOut() {
        console.log('signOut real implementation');
      },
    };
    

    setupTests.ts:

    const authObjectMock = {
      createUserAndRetrieveDataWithEmailAndPassword: jest.fn(() => Promise.resolve(true)),
      sendPasswordResetEmail: jest.fn(() => Promise.resolve(true)),
      signInAndRetrieveDataWithEmailAndPassword: jest.fn(() => Promise.resolve(true)),
      fetchSignInMethodsForEmail: jest.fn(() => Promise.resolve(true)),
      signOut: jest.fn(() => {
        Promise.resolve(true);
      }),
      onAuthStateChanged: jest.fn(),
      currentUser: {
        sendEmailVerification: jest.fn(() => Promise.resolve(true)),
      },
    };
    const authMock = jest.fn(() => authObjectMock);
    
    export { authMock };
    

    SignOutButton.test.tsx:

    import React from 'react';
    import { render, cleanup, fireEvent } from '@testing-library/react';
    import Firebase from './firebase';
    import { authMock } from './setupTests';
    // @ts-ignore
    Firebase.auth = authMock;
    
    describe('<SignOutButton />', () => {
      afterEach(cleanup);
    
      it('calls Firebase signOut on click', async () => {
        const SignOutButton = (await import('./SignOutButton')).default;
        const { getByText } = render(<SignOutButton />);
        const button = getByText('Sign Out');
        fireEvent.click(button);
        expect(Firebase.auth().signOut).toHaveBeenCalled();
      });
    });
    

    带有覆盖率报告的单元测试结果:

     PASS  src/stackoverflow/58562583/SignOutButton.test.tsx
      <SignOutButton />
        ✓ calls Firebase signOut on click (76ms)
    
      console.log src/stackoverflow/58562583/SignOutButton.tsx:382
        { [Function: mockConstructor]
          _isMockFunction: true,
          getMockImplementation: [Function],
          mock: [Getter/Setter],
          mockClear: [Function],
          mockReset: [Function],
          mockRestore: [Function],
          mockReturnValueOnce: [Function],
          mockResolvedValueOnce: [Function],
          mockRejectedValueOnce: [Function],
          mockReturnValue: [Function],
          mockResolvedValue: [Function],
          mockRejectedValue: [Function],
          mockImplementationOnce: [Function],
          mockImplementation: [Function],
          mockReturnThis: [Function],
          mockName: [Function],
          getMockName: [Function] }
    
      console.log src/stackoverflow/58562583/SignOutButton.tsx:386
        should keep same reference to authObject: true
    
    -------------------|----------|----------|----------|----------|-------------------|
    File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    -------------------|----------|----------|----------|----------|-------------------|
    All files          |    63.64 |      100 |    36.36 |       60 |                   |
     SignOutButton.tsx |      100 |      100 |      100 |      100 |                   |
     firebase.ts       |       25 |      100 |        0 |       25 |             3,4,7 |
     setupTests.ts     |       50 |      100 |    28.57 |    44.44 |        2,3,4,5,11 |
    -------------------|----------|----------|----------|----------|-------------------|
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        3.943s
    

    【讨论】:

      猜你喜欢
      • 2022-07-13
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2021-08-19
      • 2021-05-25
      • 2020-07-07
      • 1970-01-01
      相关资源
      最近更新 更多