Test waits for async apollo-client functions to resolve before making assertions
devLana opened this issue · comments
@testing-library/react
version: latest- Testing Framework and version: jest@latest
- DOM Environment: jest-environment-jsdom@latest
- @apollo/client: 3.8.7
- node: 18.17.1
Relevant code or config:
Test Component
import { useState } from "react";
import { gql, useMutation } from "@apollo/client";
export const TEST_MUTATION = gql`
mutation TestMutation($name: String!) {
testing(name: $name) {
id
name
}
}
`;
function App() {
const [status, setStatus] = useState("idle");
const [mutate] = useMutation(TEST_MUTATION);
const handleRequest = () => {
setStatus("loading");
mutate({
variables: { name: "Test Name" },
onError: () => setStatus("error"),
});
};
return (
<button onClick={handleRequest} disabled={status === "loading"}>
Click Me!
</button>
);
}
Test Case
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MockedProvider } from "@apollo/client/testing";
import App, { TEST_MUTATION } from "../";
test("Should disable button", async () => {
const user = userEvent.setup();
const mocks = [
{
request: { variables: { name: "Test Name" }, query: TEST_MUTATION },
error: new Error("Network Error"),
},
];
render(
<MockedProvider mocks={mocks}>
<App />
</MockedProvider>
);
await user.click(screen.getByRole("button", { name: "Click Me!" }));
expect(screen.getByRole("button", { name: "Click Me!" })).toBeDisabled();
});
What you did:
I am trying to assert that the button is disabled when the user initiates a mutation api request on click.
What happened:
The test fails to assert that the button is in a disabled state.
Reproduction:
https://github.com/devLana/dom-testing-library-template
Problem description:
The button is supposed to be disabled as soon as it is clicked and status updates to loading
. And whenever the request resolves the onError
method would update the state to error
enabling the button again.
However, it seems the test waits for the async mutate function to resolve before running the assertion(even though I am not using any of testing library's async methods). As a result, the button remains in an enabled state which fails the assetion.
Suggested solution:
Any solution that prevents the test from waiting for the async mutate
function to resolve before making synchronous assertions will be valid
Hey Lana, the issue seems to be with how you're using Apollo rather than React Testing Library.
In Apollo's docs they note to test the loading state with a mocked response they configure it with a delay.
https://www.apollographql.com/docs/react/development-testing/testing#testing-the-loading-and-success-states
I made the following change and saw the result you're expecting with the test passing.
const mocks = [
{
delay: 30, // Add delay to ensure loading state is rendered
request: { variables: { name: "Test Name" }, query: TEST_MUTATION },
error: new Error("Network Error"),
},
];
Hey Lana, the issue seems to be with how you're using Apollo rather than React Testing Library. In Apollo's docs they note to test the loading state with a mocked response they configure it with a delay. https://www.apollographql.com/docs/react/development-testing/testing#testing-the-loading-and-success-states
I made the following change and saw the result you're expecting with the test passing.
const mocks = [ { delay: 30, // Add delay to ensure loading state is rendered request: { variables: { name: "Test Name" }, query: TEST_MUTATION }, error: new Error("Network Error"), }, ];
I have never had to pass a delay with the mocks before but this solves it. Thank you