开玩笑无法读取null的属性'createEvent'

时间:2020-03-03 10:05:43

标签: jestjs react-testing-library

我正在尝试模拟拒绝的值并出现此错误。奇怪的是,这种构造在“成功” addUser.mockImplementation(value => jest.fn().mockResolvedValue(value))的情况下有效,但是当我尝试通过拒绝执行相同的技巧时,它不起作用,并说“无法读取null的属性'createEvent'”

这是我的测试用例

it('receives invalid value and throws an error', async () => {
  addUser.mockImplementation(() =>
    jest.fn().mockRejectedValue(new Error('Sample error'))
  )

  const enqueueSnackbar = jest.fn()
  useSnackbar.mockReturnValue({ enqueueSnackbar })

  const { emailInput, form, submitButton } = setup()

  await act(async () => {
    fillIn(emailInput, 'sample@mail.com')
  })

  expect(emailInput.value).toBe('sample@mail.com')
  expect(submitButton).toHaveProperty('disabled', false)

  await act(async () => {
    fireEvent.submit(form)
  })

  expect(enqueueSnackbar).toHaveBeenCalledTimes(1)
  expect(enqueueSnackbar).toHaveBeenCalledWith(`Sample error`, {
    variant: 'error'
})})

有人知道如何使它工作吗?

5 个答案:

答案 0 :(得分:23)

这似乎是当有人在 Google 上搜索“无法读取 null 的属性‘createEvent’”时发现的第一个问题,因此将这个答案留在这里给那些读者:

对我来说,这个错误是在测试过程中出现的。
在执行一系列测试时,某些测试或其他测试曾经因此错误而失败,并且没有任何迹象表明哪里出了问题。但结果证明不是测试而是组件本身:

这是一个未模拟的 API 调用。
在一个钩子中进行了一个 API 调用,并且该钩子被用于测试失败的组件中。显然 Jest 在完成测试后清理了所有内容,当调用返回时,它什么也没找到,因此出错了。

模拟钩子解决了这个问题。

如果有人遇到这样的错误,请确保模拟您拥有的任何异步逻辑,尤其是当它返回时与 DOM 交互时。

答案 1 :(得分:2)

这似乎对我有用,但我无法解释。尝试删除act()包装器,并在调用fireEvent函数后立即使用await。

  fireEvent.submit(form);
  await wait();

答案 2 :(得分:2)

当我遇到同样的错误消息时,我发现我在更新期望以包含 async 后忘记将我的测试函数声明为 await

答案 3 :(得分:1)

waitFor 已经在底层使用了 act,因此无需在那里使用 act 块。

我知道您提到的错误,但我复制它的方式是使用没有 waitForawait,如下所示:

it('works', async() => {
  render(<SomeComponent />);
  // (some setup here)

  waitFor(() => { // notice that we are not awaiting this promise
    expect(someChange).toBeInTheDocument();
  });
});

你可以试试吗

it('receives invalid value and throws an error', async () => {
  addUser.mockImplementation(() =>
    jest.fn().mockRejectedValue(new Error('Sample error'))
  )

  const enqueueSnackbar = jest.fn()
  useSnackbar.mockReturnValue({ enqueueSnackbar })

  const { emailInput, form, submitButton } = setup()

  fillIn(emailInput, 'sample@mail.com') // This is using some fireEvent under the hood right?

  await waitFor(() => {
    expect(emailInput.value).toBe('sample@mail.com')
    expect(submitButton).toHaveProperty('disabled', false)
  });
  fireEvent.submit(form)

  await waitFor(() => {
    expect(enqueueSnackbar).toHaveBeenCalledTimes(1)
    expect(enqueueSnackbar).toHaveBeenCalledWith(`Sample error`, {
      variant: 'error'
    })
  });
})

答案 4 :(得分:0)

我在同时使用 mockImplementation(() => Promise)(返回一些 promise)和 await waitFor(()=> ...) 时遇到了一些问题。

如果您使用的是 react-testing-library,则可以使用 findBy 查询解决此问题,该查询是 getBy 查询和 waitFor 的组合。唯一的缺点是您必须找到一些可以告诉您模拟函数已被调用的视觉内容(文本、数据测试 ID、标签等)。在您的代码中,您可以尝试这样的操作:

it('receives invalid value and throws an error', async () => {
  addUser.mockImplementation(() =>
    jest.fn().mockRejectedValue(new Error('Sample error'))
  )

await screen.findByText('Sample Error message reflected in your component')

... rest of your tests ...

})