如何使用RouteComponentProps测试React组件? [英] How to test a React component with RouteComponentProps?
问题描述
我有一个组件,该组件具有扩展RouteComponentProps
的道具,如下所示:
I have a component that has props which extend RouteComponentProps
that looks like this:
export interface RouteComponentProps<P> {
match: match<P>;
location: H.Location;
history: H.History;
staticContext?: any;
}
现在,当我在应用程序中使用组件时,会将这些道具传递给它:
Now, when I use my component in the app, I pass these props to it:
<MyComponent
match={this.props.match}
location={this.props.location}
history={this.props.history}
/>
道具已经可用,因为它在React Router中运行.
The props are available already because it's running inside react router.
现在,如何在没有match
,location
,history
可用的情况下测试此组件?
Now, how do I test this component without match
, location
, history
available?
我需要模拟它们还是应该以某种辅助功能自动加载它们?
Do I need to mock them or is it supposed to somehow automatically load them with some helper function?
推荐答案
要回答您的最后一个问题,建议的方法是在测试中使用<MemoryRouter>< *your component here* ></MemoryRouter>
. Typescript不会接受此组件会将所需的属性传递给您的组件,因此,我认为不是一种类型安全的方法.
To answer your last question, the recommended approach is to use <MemoryRouter>< *your component here* ></MemoryRouter>
in your tests. Typescript does not pick up that this component will pass the required props to your component, as such I assume it not to be a type safe approach.
这适用于React Router v4,不适用于以前的版本.
对于类型安全的方法来测试HOC withRouter
包装的组件,可以从react-router
和history
包中构建位置,历史记录和匹配项.
For a typesafe method to test components that are wrapped with the HOC withRouter
you can build the location, history and match from the react-router
and history
packages.
此示例使用了酶和快照测试,但可以像其他任何测试一样容易.
This example uses enzyme and snapshot testing but could just as easily be any other test.
这避免了我需要使用<MemoryRouter>
作为打字稿不喜欢的包装器.
This avoided me needing to use <MemoryRouter>
as a wrapper that typescript did not like anyhow.
// Other imports here
import { createMemoryHistory, createLocation } from 'history';
import { match } from 'react-router';
const history = createMemoryHistory();
const path = `/route/:id`;
const match: match<{ id: string }> = {
isExact: false,
path,
url: path.replace(':id', '1'),
params: { id: "1" }
};
const location = createLocation(match.url);
test('shallow render', () => {
const wrapper = shallow(
<MyComponent history={history}
location={location}
match={match} />
);
expect(wrapper).toMatchSnapshot();
});
注意请勿使用它来测试实现细节,这可能很诱人,但是如果您要重构,它会给您带来很多痛苦.
CAUTION Do not use this to test implementation detail, it can be tempting but it will cause you a lot of pain should you want to refactor.
为此提供帮助可能是使它可重复使用的最佳方法.
Making a helper for this would probably be the best way to make this re-usable.
import { createLocation, createMemoryHistory } from 'history';
import { match as routerMatch } from 'react-router';
type MatchParameter<Params> = { [K in keyof Params]?: string };
export const routerTestProps = <Params extends MatchParameter<Params> = {}>
(path: string, params: Params, extendMatch: Partial<routerMatch<any>> = {}) => {
const match: routerMatch<Params> = Object.assign({}, {
isExact: false,
path,
url: generateUrl(path, params),
params
}, extendMatch);
const history = createMemoryHistory();
const location = createLocation(match.url);
return { history, location, match };
};
const generateUrl = <Params extends MatchParameter<Params>>
(path: string, params: Params): string => {
let tempPath = path;
for (const param in params) {
if (params.hasOwnProperty(param)) {
const value = params[param];
tempPath = tempPath.replace(
`:${param}`, value as NonNullable<typeof value>
);
}
}
return tempPath;
};
现在我们可以在测试中使用routerTestProps
函数
Now we can just use the routerTestProps
function in our tests
const { history, location, match } = routerTestProps('/route/:id', { id: '1' });
这篇关于如何使用RouteComponentProps测试React组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!