RTL 中的 waitForElementToBeRemoved 错误超时

Timed out in waitForElementToBeRemoved error in RTL

我有一个使用 Formik 制作的基本登录表单,只是想写一个 RTL 和笑话代码来填写详细信息,提交表单,然后导航到 主页。因此,写成如下:

 it('Fill the form and login', async () => {
    render(<Login />)

    await userEvent.type(screen.getByTestId('emailInput'), 'neeraj@gmail.com')
    await userEvent.type(screen.getByTestId('passwordInput'), 'neeraj')
    await userEvent.click(screen.getByTestId('submitBtn'))

    expect(window.location.pathname).toBe('/')
  })

以上测试已通过,但出现经典 act 错误。

When testing, code that causes React state updates should be wrapped into act(...):
    
    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

因此,参考此 blog post 并按照建议使用 waitForElementToBeRemoved 函数,但现在测试因超时错误而失败。

使用 waitForElementToBeRemoved 更新了测试用例

it('Fill the form and login', async () => {
    render(<Login />)

    await userEvent.type(screen.getByTestId('emailInput'), 'neeraj@gmail.com')
    await userEvent.type(screen.getByTestId('passwordInput'), 'neeraj')
    await userEvent.click(screen.getByTestId('submitBtn'))

    expect(window.location.pathname).toBe('/')
    await waitForElementToBeRemoved(screen.getByTestId('emailInput'))
  })

错误:

 Timed out in waitForElementToBeRemoved.

    Ignored nodes: comments, <script />, <style />
    <html>
      <head />
      <body>
        <div>
          <div>
            <div
              data-testid="loginCard"
            >
              <form
                data-testid="loginForm"
              >
                <div>
                  <label
                    for="email-input"
                  >
                    Email
                  </label>
                  <input
                    data-testid="emailInput"
                    id="email-input"
                    name="email"
                    type="email"
                    value="neeraj@gmail.com"
                  />
                </div>
                <div>
                  <label
                    for="pass-input"
                  >
                    Password
                  </label>
                  <input
                    data-testid="passwordInput"
                    id="pass-input"
                    name="password"
                    type="password"
                    value="neeraj"
                  />
                </div>
                <button
                  data-testid="submitBtn"
                  type="submit"
                >
                  Submit
                </button>
              </form>
            </div>
          </div>
        </div>
      </body>
    </html>

      19 |
      20 |     expect(window.location.pathname).toBe('/')
    > 21 |     await waitForElementToBeRemoved(screen.getByTestId('emailInput'))
         |           ^
      22 |   })
      23 | })
      24 |

      at waitForElementToBeRemoved (node_modules/@testing-library/dom/dist/wait-for-element-to-be-removed.js:22:24)
      at Object.<anonymous> (tests/login.test.js:21:11)

试图将这三个 userEvent 包装在 act 函数中,但出现相同的超时错误,无法弄清楚我在哪里出错了。

Code Sandbox link

我成功通过了测试用例,没有行为警告。

由于您在用户单击 submitBtn 按钮时调用异步函数 setTimeout,因此您必须等待承诺解决。

import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'

import Login from './../pages/login'

describe('Login Page', () => {
  it('renders without crashing', () => {
    render(<Login />)
    expect(screen.getByTestId('loginCard')).toBeInTheDocument()
  })
  
  it('Fill the form and login', async () => {
    render(<Login />)

    userEvent.type(screen.getByLabelText(/email/i), 'neeraj@gmail.com')
    userEvent.type(screen.getByLabelText(/password/i), 'neeraj')
    userEvent.click(screen.getByTestId('submitBtn'))

    await waitFor(() => expect(window.location.pathname).toBe('/'))
  })
})

您也可以对单击事件使用异步操作来完成此操作,该事件将等待解决承诺并完成状态更新。

import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'

import Login from './../pages/login'

describe('Login Page', () => {
  it('renders without crashing', () => {
    render(<Login />)
    expect(screen.getByTestId('loginCard')).toBeInTheDocument()
  })
  
  it('Fill the form and login', async () => {
    render(<Login />)

    userEvent.type(screen.getByLabelText(/email/i), 'neeraj@gmail.com')
    userEvent.type(screen.getByLabelText(/password/i), 'neeraj')
    await act(async () => userEvent.click(screen.getByTestId('submitBtn')))

    expect(window.location.pathname).toBe('/')
  })
})