Jest 无法读取 null 的属性“createEvent”

Ing*_*rid 14 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'
})})
Run Code Online (Sandbox Code Playgroud)

有谁知道如何使它工作?

cst*_*992 36

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

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

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

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

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

  • 对此进行补充。我进行了测试,没有发生异步提取,但仍然收到此错误。我的问题是我在 5 秒的超时间隔内进行了测试。因此,在我单击按钮和事件处理周期完成之间,我收到了此错误,令人惊讶的是,它始终出现在同一位置。然后测试因超时而失败,破坏了 DOM,但随后在我的测试中给出了这个错误*而不是*超时错误。 (10认同)
  • 就我而言,我只是忘记添加一些“等待” (7认同)

小智 33

与@alexandre_anicio 所说的类似。我在使用查询时遇到此错误findAllByTextexpect(screen.findAllByText('word'))...

当我切换到该错误时getAllByText,错误消失了,测试通过了。 expect(screen.getAllByText('word'))...

如果我使用,expect(await screen.findAllByText('word'))...我注意到测试也通过了。

深入挖掘,这是因为findBy测试会返回一个承诺,因此await需要它。https://testing-library.com/docs/guide-disappearance/#1-using-findby-queries

不过,如果图书馆能够抛出更好的错误,那就太好了。

  • 我通常使用“getBy”,但这次我让 IDE 自动完成为:“findBy”,然后疯狂地尝试在这个项目上设置测试,我不敢相信在网上搜索这个显式错误时缺少结果。 (3认同)

小智 7

waitFor已经act在引擎盖下使用了,所以不需要使用act那里的块。

我认识到您提到的错误,但我复制它的方式是使用waitForwithout await,如下所示:

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

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

你能尝试一下吗

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'
    })
  });
})
Run Code Online (Sandbox Code Playgroud)


小智 7

类似的问题和错误消息,添加await之前userEvent就可以了

userEvent.upload(screen.getByRole('button'), ...)

userEvent.upload(screen.getByLabelText('Upload'), FILE)

await userEvent.upload(screen.getByRole('button'), ...)

await userEvent.upload(screen.getByLabelText('Upload'), FILE)


Ben*_*rth 5

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

  fireEvent.submit(form);
  await wait();
Run Code Online (Sandbox Code Playgroud)

  • 如果有人能解释这一点,我会非常高兴。另外,在react-native-testing-library文档中,他们说“wait”已被弃用,取而代之的是“waitFor”。我只是要等待有人解释原因。看看我在那里做了什么 (13认同)

小智 5

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