遵循 RTL 自己的指南时,React 测试库 Router 测试未通过

React testing library Router tests not passing when following RTL's own guide

我正在尝试使用 React 测试库对一个简单的导航应用程序进行简单测试。我目前正在尝试使用 RTL's own guide 中所示的示例方法,但它似乎不起作用。

App.js

return (
    <BrowserRouter>
      <div>
        <Route exact path="/" component={Home} />
        <Route exact path="/hello" component={Hello} />
      </div>
    </BrowserRouter>
  );

Home.jsx

return (
    <div data-testid="home-container">
      <Link to="/hello">Link to hello</Link>
    </div>
  );

Hello.jsx

return (
    <div data-testid="hello-container">
      <Link to="/">&lt; Back</Link>
      <h1 data-testid="hello-title">Hello component</h1>
    </div>
  );

在 Home.spec.js

中测试 Home.jsx
test("Navigate to hello page when clicked", async () => {
    const history = createMemoryHistory();
    render(
      <Router history={history}>
        <Home />
      </Router>
    );

    // check pre-nav page
    expect(screen.getByText(/Link to hello/i)).toBeInTheDocument();

    const leftClick = { button: 0 };
    userEvent.click(screen.getByText(/Link to hello/i), leftClick);

    // check we have navigated to the correct path - THIS PASSES!
    expect(history.location.pathname).toBe("/hello");

    // check that the content changed to the new page - THIS FAILS!
    expect(screen.getByText(/Hello component/i)).toBeInTheDocument();
  });

错误...

我似乎得到的错误是它找不到 /Hello component/ 文本,仍然认为它在 Home 组件上......这很奇怪,因为历史位置检查清楚地表明它在 Hello 路径上。

Unable to find an element with the text: /Hello component/i. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Ignored nodes: comments, <script />, <style />
<body>
  <div>
    <div
      data-testid="home-container"
    >
      <a
        href="/hello"
      >
        Link to hello
      </a>
    </div>
  </div>
</body>
    render(
      <Router history={history}>
        <App /> // <<--
      </Router>
    );

您想使用 App 组件,因为它有路由, 您的 Home 组件不知道路由。

感谢@BrunoNoriller 帮助我在这里看到我的方法的错误。

我最初提出的问题的主要问题是让我自己对我认为正在测试的内容感到困惑。

我以为我正在对我的组件执行单元测试,只是测试从组件继续显示 <Hello/> 组件的路由。事实上,我真正在做的 是对更广泛的应用程序及其路由的伪 E2E 测试,其中 - 是的 - Bruno 的回答是正确的,以呈现 <App />组件并使用 window 历史让测试知道我们 are/where 我们去了哪里。

我真正想要的是单独对 组件进行单元测试,而我只是忘记了这样做的范围。主要的类比是想像您的组件采用某种 handleClick 函数来在您单击该组件中的按钮时触发。当涉及到测试时,您并不真正关心可触发函数是什么,只是我们传入一个并测试它是否触发。这类似于组件内的隔离测试路由...假设您有一个 <Link>,单击时将像我的组件一样路由到 /hello;我们实际上并不关心在此结束时呈现的组件或页面(就像您在 E2E 测试中所做的那样),我们只关心 呈现的东西,我们可以在我们的测试中控制它。

Home.jsx

return (
    <div data-testid="home-continer">
        <Link to="/hello">Link to hello</Link>
    </div>
);

Hello.jsx

return (
    <div data-testid="hello-continer">
        <Link to="/">Back</Link>
        <div>This is the real hello component</div>
    </div>
);

Home.spec.js

test('should render whatever is at /hello path when clicked', () => {
    /* 
      Essentially we are rendering a new, custom router for the 
      test to route to a test-specific version of the route we 
      render in the component under test
    */
    render(
      <BrowserRouter>
        <Home />
        <Route path="/hello">
          <div data-testid="hello-container">
             TEST HELLO
          </div>
        </Route>
      </BrowserRouter>
    );

    // Test we're at the correct starting point in the <Home> component
    expect(rendered.getByText(/Link to hello/i)).toBeInTheDocument();

    // Click the link to the /hello path
    fireEvent.click(rendered.getByText(/Link to hello/i));

    // Test we can now see the path-specific component contents
    expect(rendered.getByTestId("hello-container")).toBeTruthy();

    /* 
      This test shows that we are showing the test-specific path 
      contents, not the real <App/> path route component contents
    */
    expect(rendered.getByTestId("hello-container").textContent)
        .toContain("TEST HELLO");

});