Reputation: 1436
I'm looking for the simplest solution to this problem using the popular React Testing Library. I've looked at a lot of links out there and nothing seems to fit..
Here is the component in it's simplest form below:
import React, { useState, useEffect } from "react";
function App() {
const [loggedIn, setLoggedIn] = useState(false)
useEffect(() => {
setTimeout(() => setLoggedIn(true), 1000)
}, [])
return (
<button data-testid="login-button">{loggedIn ? "Log Out" : "Log In"}</button>
);
}
export default App;
And below is the test for the 'no wait' state of the button but would like to know how to implement 'waitFor' within the same test for the change in text in the button after 1 second..
import { render, screen, waitFor } from "@testing-library/react";
import App from "./App";
test('Check the text "Log out" is eventually there', () => {
render(<App />);
const LoginButton = screen.getByText(/Log/)
expect(LoginButton).toHaveTextContent(/Log In/i);
/*How to use waitFor here*/
});
I know we can mock the return from an API call easily and for this problem we probably have to return a promise before we can test using 'waitFor'. How can we use 'WaitFor' in the example test file above?
Upvotes: 0
Views: 2143
Reputation: 1436
Thankyou Shyam for helping me discover the solution, which was not using 'waitFor' from the testing-library in this case:
test('Check the text "Log out" is eventually there', () => {
jest.useFakeTimers();
render();
//Reference the element by locating using Regex
const LoginButton = screen.getByText(/Log/);
//Search in real time for the initial/default text on the button
expect(LoginButton).toHaveTextContent(/Log In/i);
// advance the timer
act(() => jest.advanceTimersByTime(1000));
// assert the changed text of the button
expect(LoginButton).toHaveTextContent(/Log Out/i);
// switch back to use real timers
jest.useRealTimers();
});
Upvotes: 0
Reputation: 5497
You can use jest's Timer Mocks to handle the setTimeouts.
import { act, render, screen } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
// use the fake timer
jest.useFakeTimers();
render(<App />);
// assert the initial text of the button
expect(screen.getByRole("button", { name: "Log In" })).toBeInTheDocument();
// advance the timer
act(() => jest.advanceTimersByTime(1000));
// assert the changed text of the button
expect(screen.getByRole("button", { name: "Log Out" })).toBeInTheDocument();
// switch back to use real timers
jest.useRealTimers();
});
Reference:
Upvotes: 1