testing-library / react-testing-library

🐐 Simple and complete React DOM testing utilities that encourage good testing practices.

Home Page:https://testing-library.com/react

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

test-error-image

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