Тест не начинается на заранее определенном маршруте
Я получил тест на работу многостраничного приложения. Теперь я хочу инициализировать маршрут внутри теста. Но я не могу заставить его работать, используя initialEntries реактивного маршрутизатора. Я попробовал оба Router с createMemoryHistory и MemoryRouter. Но тест всегда начинается с маршрута "/".
Как сделать так, чтобы тест запускался с "/page-1"?
Вот ссылка на codeandboxhttps://codesandbox.io/s/testing-react-89nfe?file=/src/index.js Тест не проходит на codeandbox, потому что песочница еще не поддерживает шутливую имитацию.
app.test.js
import 'mutationobserver-shim'
import React from 'react'
import {render, fireEvent, waitFor} from '@testing-library/react'
import { MemoryRouter, Router } from 'react-router-dom'
import { createMemoryHistory } from 'history'
import App from './app'
import { submitForm } from './api';
function renderWithRouter(
ui,
{
route = '/',
history = createMemoryHistory({ initialEntries: [route] }),
} = {}
) {
const Wrapper = ({ children }) => (
<Router history={history}>{children}</Router>
)
return {
...render(ui, { wrapper: Wrapper }),
// adding `history` to the returned utilities to allow us
// to reference it in our tests (just try to avoid using
// this to test implementation details).
history,
}
}
jest.mock('./api');
test('multi-step form', async () => {
submitForm.mockResolvedValue({ success: true })
const input = { food: 'pizza', drink: 'beer' }
const foodLabelRegex = /food/i;
const drinkLabelRegex = /drink/i;
const nextButtonRegex = /next/i;
const reviewButtonRegex = /review/i;
const confirmRegex = /confirm/i;
const page2Regex = /page 2/i;
const successRegex = /success/i;
// const name = container.querySelector('input[name="name"]')
const {debug, getByLabelText, getByText, getByRole, container } = renderWithRouter(<App />, {
route: '/page-1'
});
// const {debug, getByLabelText, getByText, getByRole, container } = render(
// <MemoryRouter initialEntries={['/page-1']}>
// <App />
// </MemoryRouter>
// );
fireEvent.click(getByRole('link'))
fireEvent.change(getByLabelText(foodLabelRegex), {target: {value: input.food}})
fireEvent.click(getByText(nextButtonRegex))
await waitFor(() => expect(getByRole('heading')).toHaveTextContent(page2Regex))
fireEvent.change(getByLabelText(drinkLabelRegex), {target: {value: input.drink}})
fireEvent.click(getByText(reviewButtonRegex))
await waitFor(() => expect(getByRole('heading')).toHaveTextContent(confirmRegex))
expect(getByLabelText(foodLabelRegex)).toHaveTextContent(input.food)
expect(getByLabelText(drinkLabelRegex)).toHaveTextContent(input.drink)
fireEvent.click(getByText(confirmRegex, { selector: 'button' }))
await waitFor(() => {
expect(submitForm).toHaveBeenCalledTimes(1)
expect(getByRole('heading')).toHaveTextContent(successRegex)
expect(container.querySelector('a[id="go-home"]')).toBeTruthy()
debug()
});
})
app.js
import React from 'react'
import {
Switch,
Route,
Link,
//HashRouter as Router,
BrowserRouter as Router,
} from 'react-router-dom'
import {submitForm} from './api'
function Main() {
return (
<>
<h1>Welcome to the app</h1>
<Link to="/page-1">Fill out the form</Link>
</>
)
}
function Page1({state, setState, history}) {
return (
<>
<h2>Page 1</h2>
<form
onSubmit={(e) => {
e.preventDefault()
history.push('/page-2')
}}
>
<label htmlFor="food">Favorite Food</label>
<input
id="food"
value={state.food}
onChange={(e) => setState({food: e.target.value})}
/>
</form>
<Link to="/">Go Home</Link> | <Link to="/page-2">Next</Link>
</>
)
}
function Page2({state, setState, history}) {
return (
<>
<h2>Page 2</h2>
<form
onSubmit={(e) => {
e.preventDefault()
history.push('/confirm')
}}
>
<label htmlFor="drink">Favorite Drink</label>
<input
id="drink"
value={state.drink}
onChange={(e) => setState({drink: e.target.value})}
/>
</form>
<Link to="/page-1">Go Back</Link> | <Link to="/confirm">Review</Link>
</>
)
}
function Confirm({state, onConfirmClick}) {
return (
<>
<h2>Confirm</h2>
<div>
<strong>Please confirm your choices</strong>
</div>
<div>
<strong id="food-label">Favorite Food</strong>:{' '}
<span aria-labelledby="food-label">{state.food}</span>
</div>
<div>
<strong id="drink-label">Favorite Drink</strong>:{' '}
<span aria-labelledby="drink-label">{state.drink}</span>
</div>
<Link to="/page-2">Go Back</Link> |{' '}
<button onClick={onConfirmClick}>Confirm</button>
</>
)
}
function Success() {
return (
<>
<h2>Success</h2>
<div>
<Link to="/" id="go-home">
Go home
</Link>
</div>
</>
)
}
function Error({
location: {
state: {error},
},
}) {
return (
<>
<div>Oh no. There was an error.</div>
<pre>{error.message}</pre>
<Link to="/">Go Home</Link>
<Link to="/confirm">Try again</Link>
</>
)
}
export default function App() {
const [state, setState] = React.useReducer((s, a) => ({...s, ...a}), {
food: '',
drink: '',
})
function handleConfirmClick(history) {
submitForm(state).then(
() => {
setState({food: '', drink: ''})
history.push('/success')
},
(error) => {
history.push('/error', {state: {error}})
},
)
}
return (
<Router>
<Switch>
<Route exact path="/" component={Main} />
<Route
path="/page-1"
render={(props) => (
<Page1 {...props} state={state} setState={setState} />
)}
/>
<Route
path="/page-2"
render={(props) => (
<Page2 {...props} state={state} setState={setState} />
)}
/>
<Route
path="/confirm"
render={(props) => (
<Confirm
{...props}
state={state}
onConfirmClick={() => handleConfirmClick(props.history)}
/>
)}
/>
<Route path="/success" render={(props) => <Success {...props} />} />
<Route path="/error" render={(props) => <Error {...props} />} />
</Switch>
</Router>
)
}