Javascript 测试不需要';不要按预先确定的路线出发
我得到了一个多页面应用程序的测试。现在我想在测试中初始化一个路由。但我无法使用react路由器初始条目使其工作。我尝试了CreateMoryHistory路由器和MemoryRouter路由器。但是测试总是以“/”路线开始 如何使测试从“/第1页”开始 这里是codesandbox的链接 代码沙盒上的测试失败,因为沙盒还不支持jest mock app.test.jsJavascript 测试不需要';不要按预先确定的路线出发,javascript,reactjs,react-router,react-testing-library,testing-library,Javascript,Reactjs,React Router,React Testing Library,Testing Library,我得到了一个多页面应用程序的测试。现在我想在测试中初始化一个路由。但我无法使用react路由器初始条目使其工作。我尝试了CreateMoryHistory路由器和MemoryRouter路由器。但是测试总是以“/”路线开始 如何使测试从“/第1页”开始 这里是codesandbox的链接 代码沙盒上的测试失败,因为沙盒还不支持jest mock app.test.js import 'mutationobserver-shim' import React from 'react' import
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()
});
})
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>
)
}
import'mutationobserver shim'
从“React”导入React
从'@testing library/react'导入{render,firevent,waitFor}
从“react Router dom”导入{MemoryRouter,Router}
从“历史”导入{createMemoryHistory}
从“./App”导入应用程序
从“/api”导入{submitForm};
功能渲染器WithRouter(
ui,
{
路由=“/”,
history=createMemoryHistory({initialEntries:[route]}),
} = {}
) {
常量包装器=({children})=>(
{儿童}
)
返回{
…呈现(ui,{wrapper:wrapper}),
//将“历史记录”添加到返回的实用程序以允许
//要在测试中引用它(请尽量避免使用
//这是为了测试实现细节)。
历史
}
}
笑话模拟('./api');
测试('multi-step form',async()=>{
submitForm.mockResolvedValue({success:true})
常量输入={食物:“比萨饼”,饮料:“啤酒”}
const foodLabelRegex=/food/i;
const drinkLabelRegex=/drink/i;
const nextButtonRegex=/next/i;
const reviewButtonRegex=/review/i;
const confirmRegex=/confirm/i;
常数page2Regex=/page2/i;
const successRegex=/success/i;
//const name=container.querySelector('input[name=“name”]”)
const{debug,getByLabelText,getByText,getByRole,container}=renderWithRouter({
路线:'/page-1'
});
//const{debug,getByLabelText,getByText,getByRole,container}=render(
//
//
//
// );
firevent.click(getByRole('link'))
change(getByLabelText(foodLabelRegex),{target:{value:input.food})
firevent.click(getByText(nextButtonRegex))
等待waitFor(()=>expect(getByRole('heading')).toHaveTextContent(page2Regex))
change(getByLabelText(drinkLabelRegex),{target:{value:input.drink})
fireEvent.click(getByText(reviewButtonRegex))
wait waitFor(()=>expect(getByRole('heading')).toHaveTextContent(confirmRegex))
期望(getByLabelText(foodLabelRegex)).toHaveTextContent(input.food)
期望(getByLabelText(drinkLabelRegex)).toHaveTextContent(input.drink)
firevent.click(getByText(confirmRegex,{selector:'button'}))
等待等待(()=>{
期望(提交表单)。已收集时间(1)
expect(getByRole('heading')).toHaveTextContent(successRegex)
expect(container.querySelector('a[id=“go home”]”)).toBeTruthy()
调试()
});
})
app.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()
});
})
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>
)
}
从“React”导入React
进口{
转换
路线,,
链接
//HashRouter作为路由器,
BrowserRouter作为路由器,
}从“反应路由器dom”
从“/api”导入{submitForm}
函数Main(){
返回(
欢迎使用该应用程序
填表
)
}
函数Page1({state,setState,history}){
返回(
第1页
{
e、 预防默认值()
history.push(“/page-2”)
}}
>
喜爱的食物
setState({food:e.target.value})
/>
下一个回家
)
}
函数页2({state,setState,history}){
返回(
第2页
{
e、 预防默认值()
history.push(“/confirm”)
}}
>
最爱的饮料
setState({drink:e.target.value})
/>
回顾
)
}
函数确认({state,onConfirmClick}){
返回(
证实
请确认您的选择
喜爱的食品:{'}
{州食品}
喜爱的饮料:{'}
{州。饮料}
返回|{''}
证实
)
}
函数成功(){
返回(
成功
回家吧
)
}
函数误差({
地点:{
状态:{error},
},
}) {
返回(
哦,不,有个错误。
{error.message}
回家吧
再试一次
)
}
导出默认函数App(){
const[state,setState]=React.useReducer((s,a)=>({…s,…a}){
食物:,
喝酒:'',
})
函数handleConfigClick(历史记录){
提交表单(状态)。然后(
() => {
设置状态({食物:'',饮料:'})
history.push(“/success”)
},
(错误)=>{
history.push('/error',{state:{error}})
},
)
}
返回(
(
)}
/>
(
)}
/>
(
handleConfirmClick(props.history)}
/>
)}
/>
} />
} />
)
}