javascript - 测试未从预定义的路线开始
问题描述
我对多页应用程序进行了测试。现在我想在测试中初始化一个路由。但我无法使用 react-router initialEntries 使其工作。我尝试了使用 createMemoryHistory 和 MemoryRouter 的路由器。但测试总是以“/”路由开始。
如何使测试从“/page-1”开始?
这是代码沙盒的链接 https://codesandbox.io/s/testing-react-89nfe?file=/src/index.js 由于沙盒还不支持玩笑模拟,因此测试在代码沙盒上失败。
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()
});
})
应用程序.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>
)
}
解决方案
推荐阅读
- swiftui - 使用 SwiftUI 时如何隐藏键盘?
- spring-boot - Spring Boot JMS 在 Wildfly 中无限重新连接
- php - 发送 xls 文件 Telegram bot
- javascript - 使用 Fetch 和 MongoDb Atlas 进行摘要授权
- java - 使用 JPA/Hibernate 的装饰器设计模式
- javascript - Mint localhost 模板工具包上的元素返回:来自 API 调用的意外错误
- html - 标题中没有响应的 Href 和按钮
- python - 如何检查可迭代的元素是否包含某些内容
- javascript - ReactJs 组件动态数据未准备成列表
- python - 如何根据值的范围从其他 2 个列表创建嵌套列表?