Skip to content

Commit fe42193

Browse files
alexkrolickKent C. Dodds
authored andcommitted
docs(react-router): examples for react-router (testing-library#261)
* docs(react-router): examples for react-router - extract out "renderWithRouter" helper and explain when it is needed - add some "getBy" queries instead of just container.innerHTML assertions, to show more idiomatic RTL usage * docs(react-router): md/js syntax * docs(react-router): show wrapper option to render * docs(react-router): show memoryrouter instead of browserrouter * docs(react-router): use wrapper option
1 parent 9321584 commit fe42193

File tree

1 file changed

+71
-16
lines changed

1 file changed

+71
-16
lines changed

docs/example-react-router.md

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ title: React Router
44
---
55

66
```jsx
7+
// app.js
78
import React from 'react'
89
import { withRouter } from 'react-router'
910
import { Link, Route, Router, Switch } from 'react-router-dom'
10-
import { createMemoryHistory } from 'history'
1111
import { render, fireEvent } from '@testing-library/react'
1212

1313
const About = () => <div>You are on the about page</div>
@@ -32,42 +32,96 @@ function App() {
3232
</div>
3333
)
3434
}
35+
```
3536

36-
// Ok, so here's what your tests might look like
37+
```jsx
38+
// app.test.js
39+
import { Router } from 'react-router-dom'
40+
import { createMemoryHistory } from 'history'
3741

38-
// this is a handy function that I would utilize for any component
39-
// that relies on the router being in context
42+
test('full app rendering/navigating', () => {
43+
const history = createMemoryHistory()
44+
const { container, getByText } = render(
45+
<Router history={history}>
46+
<App />
47+
</Router>
48+
)
49+
// verify page content for expected route
50+
// often you'd use a data-testid or role query, but this is also possible
51+
expect(container.innerHTML).toMatch('You are home')
52+
53+
fireEvent.click(getByText(/about/i))
54+
55+
// check that the content changed to the new page
56+
expect(container.innerHTML).toMatch('You are on the about page')
57+
})
58+
59+
test('landing on a bad page shows 404 page', () => {
60+
const history = createMemoryHistory()
61+
history.push('/some/bad/route')
62+
const { getByRole } = render(
63+
<Router>
64+
<App />
65+
</Router>
66+
)
67+
expect(getByRole('heading')).toHaveTextContent('404 Not Found')
68+
})
69+
70+
test('rendering a component that uses withRouter', () => {
71+
const route = '/some-route'
72+
window.history.pushState({}, '', route)
73+
const { getByTestId } = render(
74+
<Router>
75+
<LocationDisplay />
76+
</Router>
77+
)
78+
expect(getByTestId('location-display').textContent).toBe(route)
79+
})
80+
```
81+
82+
## Reducing boilerplate
83+
84+
1. You can use the `wrapper` option to wrap a `MemoryRouter` around the component you want to render (`MemoryRouter` works when you don't need access to the history object itself in the test, but just need the components to be able to render and navigate).
85+
86+
```jsx
87+
import { MemoryRouter } from 'react-router-dom'
88+
89+
test('full app rendering/navigating', () => {
90+
const { container, getByText } = render(<App />, {wrapper: MemoryRouter})
91+
// verify page content for expected route
92+
expect(getByRole('heading')).toMatch('Home')
93+
})
94+
```
95+
96+
2. If you find yourself adding Router components to your tests a lot, you may want to create
97+
a helper function that wraps around `render`.
98+
99+
```jsx
100+
// test utils file
40101
function renderWithRouter(
41102
ui,
42103
{
43104
route = '/',
44105
history = createMemoryHistory({ initialEntries: [route] }),
45106
} = {}
46107
) {
108+
const Wrapper = ({children}) => <Router history={history}>{children}</Router>
47109
return {
48-
...render(<Router history={history}>{ui}</Router>),
110+
...render(ui, {wrapper: Wrapper}),
49111
// adding `history` to the returned utilities to allow us
50112
// to reference it in our tests (just try to avoid using
51113
// this to test implementation details).
52114
history,
53115
}
54116
}
117+
```
55118

56-
test('full app rendering/navigating', () => {
57-
const { container, getByText } = renderWithRouter(<App />)
58-
// normally I'd use a data-testid, but just wanted to show this is also possible
59-
expect(container.innerHTML).toMatch('You are home')
60-
const leftClick = { button: 0 }
61-
fireEvent.click(getByText(/about/i), leftClick)
62-
// normally I'd use a data-testid, but just wanted to show this is also possible
63-
expect(container.innerHTML).toMatch('You are on the about page')
64-
})
65-
119+
```jsx
120+
// app.test.js
66121
test('landing on a bad page', () => {
67122
const { container } = renderWithRouter(<App />, {
68123
route: '/something-that-does-not-match',
69124
})
70-
// normally I'd use a data-testid, but just wanted to show this is also possible
71125
expect(container.innerHTML).toMatch('No match')
72126
})
73127

@@ -77,3 +131,4 @@ test('rendering a component that uses withRouter', () => {
77131
expect(getByTestId('location-display').textContent).toBe(route)
78132
})
79133
```
134+

0 commit comments

Comments
 (0)