【发布时间】:2021-05-13 17:47:30
【问题描述】:
在 React 组件中,按钮提交获取页面上文本字段的值并将它们传递给 mockFetch。然后,如果 mockFetch 的 promise 成功,它会触发 history.push('/newaccount')。
我将测试设置为单击按钮,然后尝试使用我传递给它的内容来检测history.push('/newaccount') 调用,但我的模拟history.push 没有被调用。有谁知道我可以做些什么来让这个测试通过?
编辑:事实证明将当前的 jest.mock 替换为:
const history = createMemoryHistory();
const pushSpy = await jest.spyOn(history, "push");
允许我在 history.push 位于 mockFetch 函数之外时调用模拟历史记录......但当它位于函数内部时则不行。这就是我现在想要弄清楚的。
主应用路由:
function App() {
const classes = useStyles();
return (
<div className="App">
<Banner />
<div id="mainSection" className={classes.root}>
<ErrorBoundary>
<Paper>
<Router history={history}>
<Switch>
<Route path="/newaccount">
<NewAccountPage />
</Route>
<Route path="/disqualify">
<DisqualificationPage />
</Route>
<Route path="/">
<LandingPage />
</Route>
</Switch>
</Router>
</Paper>
</ErrorBoundary>
</div>
</div>
);
}
export default App;
组件:(省略了一些多余的字段)
import React, { useCallback, useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useHistory } from "react-router-dom";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import TextFieldStyled from "../TextFieldStyled/TextFieldStyled.js";
import * as actionTypes from "../../redux/actions/rootActions.js";
import {
checkAllErrors,
} from "../../validators/validators.js";
import mockFetch from "../../fetchCall/fetchCall";
import "./LandingPage.css";
const LandingPage = () => {
const dispatch = useDispatch();
const history = useHistory();
const {
changeCarPrice,
changeErrorMessage,
resetState,
} = actionTypes;
useEffect(() => {
return () => {
dispatch({ type: resetState });
};
}, [dispatch, resetState]);
const { carPrice } = useSelector(
(state) => state
);
const handleSubmit = (e) => {
e.preventDefault();
if (!checkAllErrors(allErrors)) {
// Call the API
mockFetch(carPrice)
.then((response) => {
history.push("/newaccount");
})
.catch((error) => {
dispatch({ type: changeErrorMessage, payload: error });
history.push("/disqualify");
});
}
};
const [allErrors, setAllErrors] = useState({
carValueError: false,
});
return (
<div id="landingPage">
<Grid container>
<Grid item xs={2} />
<Grid item xs={8}>
<form onSubmit={handleSubmit}>
<Grid container id="internalLandingPageForm" spacing={4}>
{/* Text Fields */}
<Grid item xs={6}>
<TextFieldStyled
info={"Enter Car Price ($):"}
value={carPrice}
adornment={"$"}
type="number"
label="required"
required
error={allErrors.carValueError}
id="carPriceField"
helperText={
allErrors.carValueError &&
"Please enter a value below 1,000,000 dollars"
}
passbackFunction={(e) => handleChange(e, changeCarPrice)}
/>
</Grid>
</Grid>
<Grid container id="internalLandingPageFormButton" spacing={4}>
<Grid item xs={4} />
<Grid item xs={3}>
<Button
variant="contained"
color="primary"
type="submit"
id="applyNowButton"
title="applyNowButton"
onSubmit={handleSubmit}
>
Apply Now
</Button>
</Grid>
<Grid item xs={5} />
</Grid>
</form>
</Grid>
<Grid item xs={2} />
</Grid>
</div>
);
};
export default LandingPage;
测试:
const wrapWithRedux = (component) => {
return <Provider store={store}>{component}</Provider>;
};
it("simulates a successful submission form process", () => {
const mockHistoryPush = jest.fn();
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
render(
wrapWithRedux(
<Router history={history}>
<Switch>
<Route path="/newaccount">
<NewAccountPage />
</Route>
<Route path="/">
<LandingPage />
</Route>
</Switch>
</Router>
)
);
const carPriceField= screen.getByTestId("carPriceField");
fireEvent.change(carPriceField, { target: { value: "5000" } });
const buttonSubmission= screen.getByTitle("buttonSubmission");
fireEvent.click(buttonSubmission);
expect(mockHistoryPush).toHaveBeenCalledWith('/newaccount');
});
【问题讨论】:
-
您能否在
if (!checkAllErrors(allErrors)) {...}块内添加console.log语句以确保它确实调用mockFetch? -
@ArunKumarMohan 刚刚将它添加到 mockFetch 的 .then 中,它确实被调用了。所以代码确实到达了 history.push("/newaccount")
-
酷。我猜期望在
mockFetch函数返回的承诺解决之前运行。您可以通过注释掉mockFetch调用并在if条件中添加history.push来测试这一点。如果你可以在你的代码中添加一个 CodeSandbox URL,它会更容易调试。 -
@ArunKumarMohan 嗯,如果我将 history.push 移出 mockFetch 调用,我仍然会遇到与从未调用过的
jest.fn()相同的错误。我开始认为这就是history.push被嘲笑的方式。 -
我在这方面取得了一些进展。如果我这样做:``` const history = createMemoryHistory(); const pushSpy = jest.spyOn(history, "push"); ``` 然后我可以在 mockFetch 之外访问模拟的 history.push。但如果它在 promise 函数 mockFetch 中......我不能。我认为这与它的承诺有关。
标签: javascript reactjs react-testing-library