tl,dr;
<MemoryRouter>
使えば良い。
例示
シンプルなパターン
例えばこんなrouter設定で考える。
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from "react-router"
export const SomeRouter = ({path = ""}) => {
return (
<Switch>
<Route path={`${path}/foo`}><div className="foo">foo</div></Route>
<Route path={`${path}/baz`}><div className="baz">baz</div></Route>
<Route path={`${path}/shallow`}><div><div className="shallowTarget">shallow</div></div></Route>
<Route><div className="default">default</div></Route>
</Switch>
)
}
class App extends Component {
render() {
// RouterとRoute定義は分けておくとテストしやすい
return (
<BrowserRouter>
<SomeRouter />
</BrowserRouter>
);
}
}
そしてtestコード。
今回はenzyme + jestでのサンプル。
import { mount, render } from "enzyme"
it('memory routing', () => {
const wrapper = render(
<MemoryRouter initialEntries={["/mount"]}><SomeRouter /></MemoryRouter>
)
expect(wrapper.find(".testTarget").length).toBe(1)
})
<MemoryRouter initialEntries={["対象にしたいパス"]}><SomeRouter /></MemoryRouter>
という感じでwrapするとテストが出来るようになる
MemoryRouterは、ReactNativeなど、ブラウザのnavigationに依存せず、配列でのみhistoryを擬似的に再現しているので、どんなテスト環境でも使える。
storybookなどで、<Link>
を利用してコケたりする場合もMemoryRouter
で解決する。
enzymeについては、shallow
だとうまくfindのテストなどができなそうだったので、mount
かrender
を利用する必要があるようだ(理由あんま深く調べてない)。
最近avaでも出来るようになったsnapshotテストならばこんな感じ。
import React from 'react';
import { MemoryRouter } from "react-router-dom"
import { create } from 'react-test-renderer'
it('default routing', () => {
const tree = create(
<MemoryRouter initialEntries={["/"]} ><SomeRouter /></MemoryRouter>
).toJSON()
expect(tree).toMatchSnapshot()
})
it('/foo routing', () => {
const tree = create(
<MemoryRouter initialEntries={["/foo"]}><SomeRouter /></MemoryRouter>
).toJSON()
expect(tree).toMatchSnapshot()
})
it('/baz routing', () => {
const tree = create(
<MemoryRouter initialEntries={["/baz"]}><SomeRouter /></MemoryRouter>
).toJSON()
expect(tree).toMatchSnapshot()
})
ちょっとだけ入り組んだパターン
例えば/user/:name
みたいなのも同じ要領でテスト可能
const Hello = ({match}) => (
<div>Hello {match.params.name}</div>
)
const NotFound = () => (
<div>Oops</div>
)
export const DynamicRouter = ({path = ""}) => {
return (
<Switch>
<Route path={`${path}/user/:name`} component={Hello}></Route>
<Route component={NotFound}></Route>
</Switch>
)
}
describe("dynamic snapshot", () => {
it('/user/bob', () => {
const wrapper = render(
<MemoryRouter initialEntries={["/user/bob"]} ><DynamicRouter /></MemoryRouter>
)
expect(wrapper.text()).toBe("Hello bob")
})
it('/user/sam', () => {
const wrapper = render(
<MemoryRouter initialEntries={["/user/sam"]} ><DynamicRouter /></MemoryRouter>
)
expect(wrapper.text()).toBe("Hello sam")
})
it('/unknown', () => {
const wrapper = render(
<MemoryRouter initialEntries={["/unknown"]} ><DynamicRouter /></MemoryRouter>
)
expect(wrapper.text()).toBe("Oops")
})
})