如何在反应路由器v4中对组件进行单元测试? 我尝试使用jest和酶重定向单元测试一个简单的组件是不成功的。
我的组件:
const AppContainer = ({ location }) =>
(isUserAuthenticated()
? <AppWithData />
: <Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>);
我尝试测试它:
function setup() {
const enzymeWrapper = mount(
<MemoryRouter initialEntries={["/"]}>
<AppContainer />
</MemoryRouter>
);
return {
enzymeWrapper
};
}
jest.mock("lib/authAPI", () => ({
isUserAuthenticated: jest.fn(() => false)
}));
describe("AppContainer component", () => {
it("renders redirect", () => {
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find("<Redirect></Redirect>")).toBe(true);
});
});
答案 0 :(得分:18)
回答我自己的问题。 基本上,我正在对我的组件进行浅层渲染,并验证如果经过身份验证正在呈现重定向组件,那么另一个是App。 代码如下:
function setup() {
const enzymeWrapper = shallow(<AuthenticatedApp />);
return {
enzymeWrapper
};
}
describe("AuthenticatedApp component", () => {
it("renders Redirect when user NOT autheticated", () => {
authApi.isUserAuthenticated = jest.fn(() => false);
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find(Redirect)).toHaveLength(1);
});
it("renders AppWithData when user autheticated", () => {
authApi.isUserAuthenticated = jest.fn(() => true);
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find(AppWithData)).toHaveLength(1);
});
});
答案 1 :(得分:6)
这两个答案都不适合我,也需要大量的挖掘工作,因此我认为我会借鉴我的经验。
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
auth.isAuthenticated
? <Component {...props} />
: <Redirect to={{
pathname: '/',
state: { from: props.location }
}} />
)} />
)
该测试对我没有任何问题,当PrivateComponent
评估为true时,它呈现了auth.isAuthenticated
。
it('renders the component when the user is authorised', () => {
auth.login()
expect(auth.isAuthenticated).toBe(true)
const privateRoute = mount(
<MemoryRouter initialEntries={['/privateComponent']}>
<PrivateRoute path='/privateComponent' component={PrivateComponent} />
</MemoryRouter>
)
expect(privateRoute.find('PrivateComponent').length).toEqual(1)
})
这是给我带来很多问题的测试。最初,我正在检查Redirect
组件。
我试图做类似的事情
expect(privateRoute.find('Redirect').length).toEqual(1)
但是,不管我做了什么,都无法找到Redirect
组件。最后,我最终查看了历史记录,但无法在线找到任何可靠的文档,并最终查看了React Router代码库。
在MemoryRouter.js (line 30)中,我看到它呈现了一个Router
组件。我注意到它也将history
作为对Router
的支持,所以我认为我可以从那里抓住它。
我最终使用Router
从privateRoute.find('Router').prop('history')
抓取了历史道具,然后最终为我提供了确实发生了重定向到正确位置的证据。
it('renders a redirect when the user is not authorised', () => {
auth.logout()
expect(auth.isAuthenticated).toBe(false)
const privateRoute = mount(
<MemoryRouter initialEntries={['/privateComponent']}>
<PrivateRoute path='/privateComponent' component={PrivateComponent} />
</MemoryRouter>
)
expect(privateRoute.find('PrivateComponent').length).toEqual(0)
expect(
privateRoute.find('Router').prop('history').location.pathname
).toEqual('/')
})
通过此测试,您正在测试PrivateRoute
组件的实际功能,并确保它按照说的去做。
文档还有很多不足之处。例如,我花了很多时间才找到initialEntries
作为MemoryRouter
的道具,您需要它,所以它实际上符合条件并执行有条件,我花了很长时间尝试覆盖两个分支只是意识到这是需要的。
希望这对某人有帮助。
答案 2 :(得分:2)
以下是我测试实际网址更改的最小示例,而不仅仅是页面上存在Redirect
组件:
RedirectApp.js
:
import React from "react";
import { Route, Switch, Redirect } from "react-router-dom";
const RedirectApp = props => {
return (
<Switch>
<Redirect from="/all-courses" to="/courses" />
</Switch>
);
};
export default RedirectApp;
RedirectApp.test.js
:
import React from "react";
import { MemoryRouter, Route } from "react-router-dom";
import { mount } from "enzyme";
import RedirectApp from "./RedirectApp";
it("redirects /all-courses to /courses", () => {
const wrapper = mount(
<MemoryRouter initialEntries={[`/all-courses`]}>
<Route component={RedirectApp} />
</MemoryRouter>
);
expect(wrapper.find(RedirectApp).props().location.pathname).toBe("/courses");
});
通过将RedirectApp
包裹在Route
中,MemoryRouter
会注入react-router
道具(match
,location
和history
)RedirectApp
。
enzyme
可让您抓取这些props()
,location
道具包含重定向后的pathname
,因此可以匹配重定向的位置。
这种方法有点笨拙,但具有测试重定向到正确位置的优势,而不仅仅是Redirect
存在。
或者,您可以export default withRouter(RedirectApp)
RedirectApp.js
自动获取react-router
道具注入。