0

I've written a pretty straightforward test for react-router. The test is should simply test that the button with a to prop navigates to a new route on click.

const Routes = () => {
    return (
        <Switch>
            <Route
                exact
                path="/"
                render={() => (
                    <CornerButton to="/route">{btnText}</CornerButton>
                )}
            />
            <Route exact path="/route" render={() => <div>Route</div>} />
        </Switch>
    );
};

it("renders a route change with 'to' prop", async () => {
    render(
        <div>
            <MemoryRouter initialEntries={["/"]}>
                <Routes />
            </MemoryRouter>
        </div>
    );

    const btn = screen.getByRole("button", { name: btnText });
    fireEvent.click(btn);
    const newRoute = screen.getByText(/Route/i);
    expect(newRoute).toBeInTheDocument();
});

I'm seeing the error:

TestingLibraryElementError: Unable to find an element with the text: /Route/i.

The button works fine and the rendered HTML looks good:

<body>
      <div>
        <div>
          <a
            class="sc-jgHCyG begwzL"
            href="/route"
            style="text-decoration: none;"
          >
            <button
              class="sc-bBrOnJ gZtvsD"
              color="primary"
              type="button"
            >
              <div
                class="sc-cOajty wNAWC"
              >
                <div
                  class="sc-khAkjo jvrrvJ"
                >
                  text
                </div>
                <div
                  class="sc-AzgDb fmENQv"
                />
              </div>
            </button>
          </a>
        </div>
      </div>
    </body>

I'd love some help.

Edit: I came closer to a solution but the behavior seems odd to me. If I use: const btn = screen.getByRole("link", { name: btnText });

Instead of: const btn = screen.getByRole("button", { name: btnText });

Everything works. Does this somehow relate to the default behavior of the button? I do not call preventDefault() inside the component. But again, I have no problems clicking the button outside of tests.

5
  • Do you need to await the "UI" to update? Commented Feb 22, 2021 at 23:10
  • Thanks for the answer! I've tried const newRoute = await screen.fineByText(/Route/i); and it also failed with the same message. Commented Feb 22, 2021 at 23:12
  • I've added an edit with a workaround. Commented Feb 22, 2021 at 23:27
  • It would be something more along the lines of await waitFor(() => screen.getByText(/Route/i));. Perhaps HTML buttons don't have an aria-role of "button" by default since the semantics are already clear by the element type. Perhaps it is because the button captures the click event and isn't propagating it to the link that actually has the behavior. Did you try any other queries? I.E. ByLabelText, ByText, ByDisplayValue? Commented Feb 22, 2021 at 23:40
  • It is as if the click is not detected because the resulting HTML idicates that route "/" has been taken. Commented Feb 22, 2021 at 23:56

1 Answer 1

1

When I try this code the test passes:

import { Switch, Route, MemoryRouter, Link } from "react-router-dom";
import { render, screen, fireEvent } from "@testing-library/react";

const Routes = () => {
  return (
    <Switch>
      <Route
        exact
        path="/"
        render={() => (
          <div>
            <div>
              <Link to="/route">
                <button color="primary" type="button">
                  <div>
                    <div>btnText</div>
                    <div />
                  </div>
                </button>
              </Link>
            </div>
          </div>
        )}
      />
      <Route exact path="/route" render={() => <div>Route</div>} />
    </Switch>
  );
};

it("renders a route change with 'to' prop", async () => {
  render(
    <div>
      <MemoryRouter initialEntries={["/"]}>
        <Routes />
      </MemoryRouter>
    </div>
  );

  const btn = screen.getByRole("button", { name: "btnText" });
  fireEvent.click(btn);
  const newRoute = screen.getByText(/Route/i);
  expect(newRoute).toBeInTheDocument();
});

So there is probably something else in your CornerButton that makes the button not work correctly in test.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.