在React-Router的路由中进行基于路由的测试的推荐方法 [英] Recommended approach for route-based tests within routes of react-router

查看:119
本文介绍了在React-Router的路由中进行基于路由的测试的推荐方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在我的项目中使用react-testing-library,并试图编写可验证应用内路由的测试.

I'm using react-testing-library within a project of mine and am trying to write tests that validate in-app routing.

例如测试AccessDenied页面上的按钮是否会将您带回到主页.

e.g. testing that a button on the AccessDenied page brings you back to the Home page.

我已经能够为我的App组件成功编写这些类型的测试,因为它定义了所有的App路由.但是,如果AccessDenied 是其中的一条路线,我该如何设置我的测试以验证单击的按钮将把我返回首页?

I've been able to write these sorts of tests successfully for my App component because it defines all of the app routes. But if AccessDenied is one of those routes, how do I need to set up my tests to validate a button clicked there will route my back to Home?

这是一个人为的例子:

App.tsx

<>
  <Router>
    <Route exact path="/" component={Home} />
    <Route exact path="/access-denied" component={AccessDenied} />
  </Router>
  <Footer />
</>

AccessDenied.tsx

AccessDenied.tsx

<div>
  <div>Access Denied</div>
  <p>You don't have permission to view the requested page</p>
  <Link to="/">
    <button>Go Home</button>    <--- this is what i want tested
  </Link>
</div>

正如我之前说的,我的测试在App.test.tsx之内工作的原因是因为我的App组件定义了其内部的路由,而我的AccessDenied只是这些路由之一.但是,是否可以在AccessDenied.test.tsx测试中利用在App.tsx中定义的路由器?也许我正在错误地解决这个问题?那就是我在努力的地方.作为参考,这是我正在工作的App.test.tsx测试.

As I said earlier the reason my tests work inside App.test.tsx is because my App component defines the routes inside itself, whereas my AccessDenied is just one of those routes. However, is it possible to leverage the router defined in my App.tsx in my AccessDenied.test.tsx tests? Perhaps I'm approaching this problem incorrectly? That's where I'm struggling. For reference, here is my working App.test.tsx tests.

App.test.tsx

App.test.tsx

describe('App', () => {
  it('should allow you to navigate to login', async () => {
    const history = createMemoryHistory()
    const { findByTestId, getByTestId } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <AuthContext.Provider
          value={{
            authState: AUTH_STATES.UNAUTHENTICATED,
          }}
        >
          <Router history={history}>
            <App />
          </Router>
        </AuthContext.Provider>
      </MockedProvider>,
    )

    fireEvent.click(getByTestId('sidebar-login-button'))
    expect(await findByTestId('login-page-login-button')).toBeInTheDocument()

    fireEvent.click(getByTestId('login-page-register-button'))
    expect(await findByTestId('register-page-register-button')).toBeInTheDocument()
  })
})

任何想法或建议都值得赞赏!

Any thoughts or suggestions are appreciated!

推荐答案

如果您考虑AccessDenied组件的职责,实际上并没有向用户发送 home .这就是您想要的整体行为,但是组件的作用仅仅是将用户发送到"/".因此,在组件单元级别,测试可能看起来像这样:

If you think about the responsibility of the AccessDenied component, it isn't really to send the user home. That's the overall behaviour you want, but the component's role in that is simply to send the user to "/". At the component unit level, therefore, the test could look something like this:

import React, { FC } from "react";
import { Link, Router } from "react-router-dom";
import { fireEvent, render, screen } from "@testing-library/react";
import { createMemoryHistory } from "history";

const AccessDenied: FC = () => (
    <div>
        <div>Access Denied</div>
        <p>You don't have permission to view the requested page</p>
        <Link to="/">
            <button>Go Home</button>
        </Link>
    </div>
);

describe("AccessDenied", () => {
    it("sends the user back home", () => {
        const history = createMemoryHistory({ initialEntries: ["/access-denied"] });
        render(
            <Router history={history}>
                <AccessDenied />
            </Router>
        );

        fireEvent.click(screen.getByText("Go Home"));

        expect(history.location.pathname).toBe("/");
    });
});

请注意"/"是默认路径,因此,如果您不提供initialEntries,即使点击没有任何作用,测试也会通过...

Note that "/" is the default path, so if you don't provide initialEntries the test passes even if the click doesn't do anything...

到那时,您可能会想",但是如果家庭路线更改了该怎么办?" 例如,如果您将主页移动到"/home",则该测试将继续通过,但是该应用程序将不再实际运行.这是过分依赖非常低级测试的常见问题,并且是高阶测试发挥作用的地方,其中包括:

At that point you might be thinking "but what if the home route changes?" If you moved the home page to "/home", for example, this test would continue to pass but the application would no longer actually work. This is a common problem with relying too much on very low-level tests and is where higher-level tests come into play, including:

  • 集成:渲染整个App并使用fireEvent模拟导航.在当前的设置中,这很有挑战性,因为Router处于App级别.我将Router移至index.tsx并在App.tsx中使用了Switch,因此您可以在MemoryRouter中渲染App或使用上面显示的createMemoryHistory方法(我已经例如,在此入门工具包中完成了此操作.

  • Integration: render the whole App and use fireEvent to simulate navigation. This is challenging in your current setup, because the Router is at the App level; I'd move the Router to index.tsx and have a Switch in App.tsx instead, so you can render App within a MemoryRouter or use the createMemoryHistory method I show above (I've done this in this starter kit for example).

端到端:使用浏览器驱动程序(例如Cypress或各种基于Selenium的选项)自动实现用户与应用程序的实际交互.

End-to-end: use a browser driver (e.g. Cypress or the various Selenium-based options) to automate actual user interactions with the app.

我还没有展示路由测试,但确实涵盖了一个简单的React应用的这些不同级别的测试

I haven't got as far as showing tests for routing, but do cover these different levels of test for a simple React app on my blog.

这篇关于在React-Router的路由中进行基于路由的测试的推荐方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆