I have a basic login form made using Formik, just trying to write an RTL and jest code to fill out the details, submit the form, and navigate to the Home page. Therefore, wrote the following:
it('Fill the form and login', async () => {
render(<Login />)
await userEvent.type(screen.getByTestId('emailInput'), '[email protected]')
await userEvent.type(screen.getByTestId('passwordInput'), 'neeraj')
await userEvent.click(screen.getByTestId('submitBtn'))
expect(window.location.pathname).toBe('/')
})
The above test is getting passed but getting the classic act error.
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
So, referred to this blog post and used waitForElementToBeRemoved function as suggested but now the test is getting failed with a timeout error.
Updated test case with waitForElementToBeRemoved
it('Fill the form and login', async () => {
render(<Login />)
await userEvent.type(screen.getByTestId('emailInput'), '[email protected]')
await userEvent.type(screen.getByTestId('passwordInput'), 'neeraj')
await userEvent.click(screen.getByTestId('submitBtn'))
expect(window.location.pathname).toBe('/')
await waitForElementToBeRemoved(screen.getByTestId('emailInput'))
})
Error:
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="[email protected]"
/>
</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)
Tried to wrap those three userEvent s in act function but getting the same timeout error, couldn't figure out where I am going wrong.
Code Sandbox link
I managed to pass the test case with no act warnings.
Since you are calling an setTimeout which is an asynchronous function when the user clicks on the submitBtn
button, therefore you have to wait for the promise to resolve.
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), '[email protected]')
userEvent.type(screen.getByLabelText(/password/i), 'neeraj')
userEvent.click(screen.getByTestId('submitBtn'))
await waitFor(() => expect(window.location.pathname).toBe('/'))
})
})
You could also do it using async act on the click event which will going to be wait for the promise to resolve and state updates to complete.
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), '[email protected]')
userEvent.type(screen.getByLabelText(/password/i), 'neeraj')
await act(async () => userEvent.click(screen.getByTestId('submitBtn')))
expect(window.location.pathname).toBe('/')
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With