【问题标题】:How to mock an asynchronous function using Jest如何使用 Jest 模拟异步函数
【发布时间】:2021-08-11 21:49:31
【问题描述】:

我一直在开玩笑地模拟我的提交功能,但我总是收到这个错误:

expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

我该如何解决这种错误?

这是我的测试文件。

it('checks the function submitTodo', () => {
    const submitTodo = jest.fn();
    const { getByTestId } = render(<InputField />);
    const input = getByTestId('input');
    fireEvent.change(input, { target: { value: 'test' } })

    fireEvent.submit(getByTestId('form'))
    expect(submitTodo).toHaveBeenCalled()
})

这是我调用异步函数的功能组件。

import { useState } from 'react';
import { firestore } from 'firebase/firebaseConfig';
import firebase from 'firebase/firebaseConfig';
import styles from 'theme/main.module.scss';

const InputField = () => {
  const [todo, setTodo] = useState('');

  const submitTodo = async (e) => {
    e.preventDefault();
    try {
      await firestore.collection('todo').add({
        todo,
        timestamp: firebase.firestore.FieldValue.serverTimestamp(),
      });
    } catch (error) {
      alert(error);
    }
    setTodo('');
  };
  return (
    <form
      data-testid='form'
      className={styles.inputFieldContainer}
      onSubmit={(e) => submitTodo(e)}
    >
      <input
        data-testid='input'
        className={styles.inputFieldContainer__input}
        placeholder='Please enter a todo.'
        required
        value={todo}
        onChange={(e) => setTodo(e.target.value)}
      />
      <button
        data-testid='submitBtn'
        className={styles.inputFieldContainer__btn}
        type='submit'
      >
        Submit
      </button>
    </form>
  );
};

export default InputField;

【问题讨论】:

    标签: javascript reactjs unit-testing testing react-testing-library


    【解决方案1】:

    submitTodoInputField 的内部函数。你不能直接使用 jest.fn() 来模拟它。如果你只是想测试 submitTodo 函数是否被调用,那么你可以这样做。

    it('checks the function submitTodo', () => {
        const submitTodoForTest = jest.fn();
        const { getByTestId } = render(<InputField submitTodoForTest={submitTodoForTest} />);
        const input = getByTestId('input');
        fireEvent.change(input, { target: { value: 'test' } })
    
        fireEvent.submit(getByTestId('form'))
        expect(submitTodoForTest).toHaveBeenCalled()
    })
    
    // In your component
      const InputField = ({submitTodoForTest = null}) => {
      const [todo, setTodo] = useState('');
    
      const submitTodo = async (e) => {
      submitTodoForTest && submitTodoForTest();
        e.preventDefault();
        try {
          await firestore.collection('todo').add({
            todo,
            timestamp: firebase.firestore.FieldValue.serverTimestamp(),
          });
        } catch (error) {
          alert(error);
        }
        setTodo('');
      };
      return (
        ....
      );
    };
    

    但是如果你需要测试fireStore是否被调用,那么你也需要模拟fireStore。

    【讨论】:

    • 我可以知道你为什么将道具传递给 InputField 组件吗?
    • 这是因为我们不能直接模拟另一个函数内部的函数。 submitTodo 是 InputField 中的一个函数。所以我们在这里传递一个附加道具仅用于测试目的。再次反应测试库不推荐这个。因为我们现在要做的是检查 submitTodo 是否被调用。测试应该更倾向于用户将如何使用我们的应用程序。看看这个 。 testing-library.com/docs/guiding-principlestesting-library.com/docs/…
    • 这是否意味着我应该创建另一个包含 submitFunction 的文件?
    • 不需要,你应该避免断言是否调用了xyz函数。因为用户不在乎你是否在调用某个函数。您需要做的就是断言应用程序的行为方式以及用户在进行交互之前和之后看到的内容。例如,在提交新的 todo 之前断言有多少个 todo -> 现在提交一个新的 todo -> 现在断言新添加的 todo 是否存在于文档中。
    猜你喜欢
    • 2019-03-13
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 2019-02-25
    • 2019-07-31
    • 2021-03-28
    • 1970-01-01
    相关资源
    最近更新 更多