简体   繁体   English

如何使用 React 和 React-Router 测试私有路由

[英]How to Test Private Routing with React & React-Router

I'm trying to test Private Routing in my React App.我正在尝试在我的 React 应用程序中测试私有路由。 I'm using the following versions:我正在使用以下版本:

"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",

In my PrivateRoute.js I'm simply checking if user is logged in and redirecting accordingly:在我的PrivateRoute.js 中,我只是检查用户是否已登录并相应地重定向:

...
const PrivateRoute = (props) => {
  const { component: Component, ...rest } = props;
  const user = useContext(AuthContext);
  return (
    <Route
      {...rest}
      render={(matchProps) =>
        user ? <Component {...matchProps} /> : <Redirect to="/SignIn" />
      }
    />
  );
};
...

In my PrivateRoute.test.js I'm simply rendering <PrivateRoute> and checking the history.location.pathname .在我的PrivateRoute.test.js 中,我只是渲染<PrivateRoute>并检查history.location.pathname However, I always get / when expecting /SignIn .但是,我总是在期待/SignIn时得到/

describe("<PrivateRoute/>", () => {
  it("redirects unauthenticated users to SignIn", async () => {
    const history = createBrowserHistory();
    render(
      <BrowserRouter>
        <Switch>
          <PrivateRoute exact path="/SomeRoute" component={SomeComponent} />
        </Switch>
      </BrowserRouter>
    );

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

What am I missing?我错过了什么?

The answer is to use <Router history={history}> along with createMemoryHistory as seen below:答案是使用<Router history={history}>createMemoryHistory ,如下所示:

This comes from React Router Documentaiton这来自React Router Documentaiton

See example test below:请参阅下面的示例测试:

it("redirects unauthenticated users to SignIn", async () => {
    const history = createMemoryHistory ({ initialEntries: ["/Private"] });
    const PrivateComponent = () => <>Private!</>
    const PublicComponent = () => <>Redirected!</>
    render(
        <Router history={history}>
          <Switch>
            <PrivateRoute exact path="/Private" component={PrivateComponent} />
            <Route exact path="/SignIn" component={PublicComponent} />
          </Switch>
        </Router>
    );
    expect(screen.queryByText("Private!")).not.toBeInTheDocument();
    expect(screen.queryByText("Redirected!")).toBeInTheDocument();
    expect(history.location.pathname).toBe("/SignIn")
  });

The reason maybe is that you're redirecting the user to the SignIn component if the AuthContext isn't present.原因可能是如果 AuthContext 不存在,您将用户重定向到 SignIn 组件。 But I think the AuthContext is always present.但我认为 AuthContext 总是存在的。 So, you should pass a value to the context when a user logs in. And check if the value is present.因此,您应该在用户登录时将值传递给上下文。并检查该值是否存在。

 function PrivateRoute({ children, ...rest }) { const [loggedInUser] = useContext(AuthContext); return ( <Route {...rest} render={({ location }) => loggedInUser.isSignedIn? ( children ): ( <Redirect to={{ pathname: "/SignIn", state: { from: location } }} /> ) } /> ); }

And you'll have to use the PrivateRoute component in the app.js just like you use a Route component.而且您必须在 app.js 中使用 PrivateRoute 组件,就像使用 Route 组件一样。

 import React from 'react' import PrivateRoute from 'path/to/PrivateRoute/component' export const UserContext = createContext(); export default function App() { const [loggedInUser, setLoggedInUser] = useState({}); return ( <UserContext.Provider value={[loggedInUser, setLoggedInUser]}> <Router> <Switch> <PrivateRoute path="/top-secret"> <SecretDoor></SecretDoor> </PrivateRoute> <Route path="/SignIn"> <SignIn></SignIn> </Route> </Switch> </Router> </UserContext.Provider> ) }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM