如何使用 jest 和 react 测试库测试调用提交表单的按钮
2021-02-08
35415
因此,我尝试测试单击按钮时 onSubmit 函数是否会被触发 - 我这样做的方式是通过测试 onSubmit 函数的内部是否被调用(axios post 方法)
测试
describe('RecipeSearch', () => {
test('submit button should return post function to recipes/search/', () => {
let mock = new MockAdapter(axios);
userEvent.selectOptions(screen.getByRole('combobox'), 'Sweet');
userEvent.click(screen.getByText('Search'));
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const searchRecipes = mock.onPost(
`${process.env.REACT_APP_API_URL}/recipes/search/`,
{ flavor_type: 'Sweet' },
{ config }
);
expect(searchRecipes).toHaveBeenCalled();
});
});
错误
expect(received).toHaveBeenCalled()
Matcher error: received value must be a mock or spy function
Received has type: object
Received has value: {"abortRequest": [Function abortRequest], "abortRequestOnce": [Function abortRequestOnce], "networkError": [Function networkError], "networkErrorOnce": [Function networkErrorOnce], "passThrough": [Function passThrough], "reply": [Function reply], "replyOnce": [Function replyOnce], "timeout": [Function timeout], "timeoutOnce": [Function timeoutOnce]}
函数
const recipeSearch = (props) => {
const [formData, setFormData] = useState({
flavor_type: 'Sour',
});
const { flavor_type } = formData;
const [loading, setLoading] = useState(false);
const onChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = (e) => {
e.preventDefault();
const config = {
headers: {
'Content-Type': 'application/json',
},
};
setLoading(true);
axios
.post(
`${process.env.REACT_APP_API_URL}/recipes/search/`,
{
flavor_type,
},
config
)
.then((res) => {
setLoading(false);
props.setRecipes(res.data);
window.scrollTo(0, 0);
})
.catch((err) => {
setLoading(false);
window.scrollTo(0, 0);
});
};
return (
<form onSubmit={(e) => onSubmit(e)}>
<div>
<div>
<div>
<label htmlFor='flavor_type'>Choose Flavor</label>
<select
name='flavor_type'
onChange={(e) => onChange(e)}
value={flavor_type}
>
<option value='Sour'>Sour</option>
<option>Sweet</option>
<option>Salty</option>
</select>
</div>
<div>
<button type='submit'>Search</button>
</div>
</div>
</div>
</form>
);
};
我已经添加了整个测试和组件代码,因此帮助会更容易。 提前致谢
(添加了 onChange + onSubmit 函数)
3个回答
创建
onSubmit
模拟并将其作为 prop 传递是行不通的,因为
onSubmit
回调是组件内部的,而不是 prop - 您无法从测试中访问它。
与其测试
onSubmit
是否已被调用,不如测试触发提交事件的结果。在本例中,这可能意味着验证是否发出了
axios
请求。
有关如何在测试中模拟
axios
的示例,请参阅
如何在 Jest 中测试 axios?
。
juliomalves
2021-02-20
我个人不喜欢仅仅为了测试目的而通过传递模拟或间谍函数来更改表单组件代码的想法。
对于我的表单,我想出了这个想法 -
-
基本上我创建了
handleOnSubmitMock
函数,然后将其分配给screen.getByRole("form", { name: "signup-form" }).onsubmit
GlobalEventHandler。 (未将模拟函数传递给表单) -
然后我检查了
expect(handleOnSubmitMock).toHaveBeenCalled()
或expect(handleOnSubmitMock).not.toHaveBeenCalled()
是否通过。 -
请注意
,表单数据验证需要使用 HTML
required
属性、regex
模式和onChange
处理程序进行,以防止使用无效数据提交表单。
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import SignupForm from "../components/SignupForm";
describe("SignupForm Component", () => {
// Helper function to render the component
const renderComponent = () => {
return render(<SignupForm />);
};
const handleOnSubmitMock = jest.fn();
it("does not submit an empty form", () => {
renderComponent();
screen.getByRole("form", { name: "signup-form" }).onsubmit =
handleOnSubmitMock;
// Submit the empty form
fireEvent.click(screen.getByRole("button", { name: "Sign Up" }));
// Expectations for form submission
expect(handleOnSubmitMock).not.toHaveBeenCalled();
});
it("does not submit the form with an invalid username", () => {
// complete the test case similarly
});
it("does not submit the form with an invalid email", () => {
renderComponent();
screen.getByRole("form", { name: "signup-form" }).onsubmit =
handleOnSubmitMock;
fireEvent.change(screen.getByPlaceholderText("Username"), {
target: { value: "validUsername" },
});
fireEvent.change(screen.getByPlaceholderText("Email"), {
target: { value: "[email protected]" },
});
fireEvent.change(screen.getByPlaceholderText("Password"), {
target: { value: "ValidPassword1!" },
});
fireEvent.change(screen.getByPlaceholderText("Confirm Password"), {
target: { value: "ValidPassword1!" },
});
// Submit the form
fireEvent.click(screen.getByRole("button", { name: "Sign Up" }));
// Expectations for form submission
expect(handleOnSubmitMock).not.toHaveBeenCalled();
});
it("does not submit the form with an invalid password", () => {
// complete the test case similarly
});
it("does not submit the form without matching passwords", () => {
// complete the test case similarly
});
it("submits the form only with valid data", () => {
renderComponent();
screen.getByRole("form", { name: "signup-form" }).onsubmit =
handleOnSubmitMock;
// Fill in the form fields with valid data
fireEvent.change(screen.getByPlaceholderText("Username"), {
target: { value: "validUsername" },
});
fireEvent.change(screen.getByPlaceholderText("Email"), {
target: { value: "[email protected]" },
});
fireEvent.change(screen.getByPlaceholderText("Password"), {
target: { value: "ValidPassword1!" },
});
fireEvent.change(screen.getByPlaceholderText("Confirm Password"), {
target: { value: "ValidPassword1!" },
});
// Submit the form
fireEvent.click(screen.getByRole("button", { name: "Sign Up" }));
// Expectations for form submission
expect(handleOnSubmitMock).toHaveBeenCalled();
});
});
并且我的表单组件未接受任何
props
-
import React, { useState } from "react";
interface FormData {
username: string;
email: string;
password: string;
confirmPassword: string;
}
const SignupForm: React.FC = () => {
const [formData, setFormData] = useState<FormData>({
username: "",
email: "",
password: "",
confirmPassword: "",
});
... ...
const handleOnSubmit = (e: React.FormEvent): void => {
... ...
};
return (
<div className="bg-gray-900 h-screen flex flex-col items-center justify-center">
<img ... ... />
<div className="bg-white p-8 rounded-lg shadow-md w-96">
<h2 className="text-2xl font-semibold mb-4 text-center text-gray-800">
Register
</h2>
<form aria-label="signup-form" onSubmit={handleOnSubmit}>
<div className="mb-4">
<input
id="username"
type="text"
name="username"
placeholder="Username"
required
/>
</div>
// other input fields ... ...
<button
type="submit">
Sign Up
</button>
</form>
<div className="mt-4 text-center">
<p className="text-gray-600">
Already have an account?{" "}
<a href="/signin" className="text-blue-500 hover:underline">
Sign in
</a>
</p>
</div>
</div>
</div>
);
};
export default SignupForm;
您应该能够为您的
RecipeSearchForm
编辑上述示例,并且它应该可以工作。
Mehedi
2023-09-04
您是否尝试过通过文本选择按钮:
describe('RecipeSearch', () => {
test('test clicking the button triggers the onSubmit function', () => {
const onSubmit = jest.fn();
render(<RecipeSearch onSubmit={onSubmit} />);
userEvent.selectOptions(screen.getByRole('combobox'), 'Sour');
userEvent.click(screen.getByText('Search'));
expect(onSubmit).toHaveBeenCalled();
});
});
我不确定
getByRole
在您第一次尝试时如何处理第二个参数,但
getByText
应该可以工作。
Florian Motteau
2021-02-09