使用 Jest 和 React 测试库在 React 应用程序中模拟 firebase 时出错

IT技术 reactjs firebase unit-testing jestjs react-testing-library
2021-05-20 14:39:31

我想测试一个调用firebase.auth().sendPasswordResetEmail()click的组件,所以我想测试 firebase 被调用 onClick,但我不确定如何实现 - 我不想在测试中调用 api。

我希望得到一些关于模拟/拦截 firebase 调用的指导。

我正在将 React 与 Jest 和 React 测试库一起使用。

这是有问题的组件:

import React from 'react'
import { withFirebase } from '../Firebase'

interface PFProps {
  firebase: firebase.app.App
}

interface S {
  email: string
}

interface Error {
  message?: string
}

const PasswordForget = ({ firebase }: PFProps) => {
  const initialState = { email: '' }
  const stateReducer = (state: S, update: { [x: string]: string }) => ({
    ...state,
    ...update,
  })
  const [state, dispatch] = React.useReducer(stateReducer, initialState)
  const [error, setError] = React.useState<Error>()

  const isValid = () => validator.isEmail(state.email)

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault()

    if (!isValid()) {
      return setError({ message: messages.emailIsInvalid })
    }

    firebase
      .auth()
      .sendPasswordResetEmail(state.email)
      .then(success => console.log(success))
      .catch(error => setError(error))
    dispatch(initialState)
  }

  const handleChange = ({
    currentTarget: { name, value },
  }: React.ChangeEvent<HTMLInputElement>) => {
    setError(undefined)
    dispatch({ [name]: value })
  }

  return (
    <>
      <form onSubmit={handleSubmit} data-testid="form" noValidate>
        {error && error.message && <FormErrorPanel message={error.message} />}
        <Input
          type="email"
          name="email"
          data-testid="pwf-email"
          value={state.email}
          onChange={handleChange}
          placeholder="Enter your email address"
        />
        <Button>Reset password</Button>
      </form>
    </>
  )
}

const PasswordForgetLink = () => (
  <p>
    <Link to={ROUTES.PASSWORD_FORGET}>Forgotten password</Link>
  </p>
)

export { PasswordForgetLink }
export default withFirebase(PasswordForget)

这就是我目前尝试模拟 firebase 的方式:

import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import { render, cleanup, fireEvent } from '@testing-library/react'
import { FirebaseContext } from '../../Firebase'
import firebase from '../../Firebase'

import PasswordForget from '../index'

jest.mock('../../Firebase/firebase', () => {
  return {
    auth: jest.fn(() => ({
      sendPasswordResetEmail: jest.fn(() => Promise.resolve()),
    })),
  }
})

afterEach(cleanup)

const setup = () => {
  const utils = render(
    <FirebaseContext.Provider value={firebase}>
      <PasswordForget />
    </FirebaseContext.Provider>,
  )
  const form = utils.getByTestId('form')
  const emailInput = utils.getByTestId('pwf-email') as HTMLInputElement
  const h1 = utils.getByText(/Forgotten Password/i)
  return {
    h1,
    form,
    emailInput,
    ...utils,
  }
}

test('should call sendPasswordResetEmail method when the form is submitted with a valid email', () => {
  const { form, emailInput } = setup()
  const email = 'peterparker@foo.com'
  fireEvent.change(emailInput, { target: { value: email } })
  expect(emailInput.value).not.toBeNull()
  fireEvent.submit(form)
  expect(firebase.auth().sendPasswordResetEmail).toHaveBeenCalledTimes(1)
})

但我收到错误:

预期模拟函数已被调用一次,但被调用了零次。

有谁知道我做错了什么?

多谢

1个回答

如果您使用的是 create-react-app,您可以尝试在“src”文件夹中添加一个“ mocks ”文件夹,然后在“ mocks ”文件夹中添加一个“firebase.js”

在“firebase.js”中:

const mockFirebase = {
  auth: jest.fn(() => mockFirebase ),
  sendPasswordResetEmail: jest.fn(() => Promise.resolve(fakeResponse))
};

export { mockFirebase as default };

“fakeResponse”是您的预期响应。

然后在你的 test.js 中删除这些:

jest.mock('../../Firebase/firebase', () => {
  return {
    auth: jest.fn(() => ({
      sendPasswordResetEmail: jest.fn(() => Promise.resolve()),
    })),
  }
})

查看 Jest 官方网站了解更多信息:https : //jestjs.io/docs/en/manual-mocks