我希望为LoginForm触发提交处理程序。但是,由于某种原因,不是调用我的模拟函数,而是触发了组件的实际处理程序(调用外部api)。如何确保我的模拟处理程序被调用?
感兴趣的三个组件如下(演示,容器和测试套件)
LoginForm.js
import { Formik, Form, Field } from 'formik';
import { CustomInput } from '..';
const LoginForm = ({ initialValues, handleSubmit, validate }) => {
return (
<Formik
initialValues={initialValues}
validate={validate}
onSubmit={handleSubmit}
>
{({ isSubmitting, handleSubmit }) => {
return (
<Form onSubmit={handleSubmit}>
<div className="d-flex flex-column justify-content-center align-items-center">
<Field
data-testid="usernameOrEmail"
type="text"
name="identifier"
placeholder="Username/Email"
component={CustomInput}
inputClass="mb-4 mt-2 text-monospace"
/>
<Field
data-testid="login-password"
type="password"
name="password"
placeholder="Password"
component={CustomInput}
inputClass="mb-4 mt-4 text-monospace"
/>
<button
data-testid="login-button"
className="btn btn-primary btn-lg mt-3 text-monospace"
type="submit"
disabled={isSubmitting}
style={{ textTransform: 'uppercase', minWidth: '12rem' }}
>
Submit
</button>
</div>
</Form>
)}}
</Formik>
);
};
export default LoginForm;
LoginPage.js
import React, { useContext } from 'react';
import { loginUser } from '../../services';
import { userContext } from '../../contexts';
import { loginValidator } from '../../helpers';
import { setAuthorizationToken, renderAlert } from '../../utils';
import LoginForm from './login-form';
const INITIAL_VALUES = { identifier: '', password: '' };
const LoginPage = props => {
const { handleUserData, handleAuthStatus } = useContext(userContext);
const handleSubmit = async (values, { setSubmitting }) => {
try {
const result = await loginUser(values);
handleAuthStatus(true);
handleUserData(result.data);
setAuthorizationToken(result.data.token);
props.history.push('/habits');
renderAlert('success', 'Login Successful');
} catch (err) {
renderAlert('error', err.message);
}
setSubmitting(false);
};
return (
<LoginForm
initialValues={INITIAL_VALUES}
validate={values => loginValidator(values)}
handleSubmit={handleSubmit}
/>
);
};
export default LoginPage;
LoginPage.spec.js
import React from 'react';
import { cleanup, getByTestId, fireEvent, wait } from 'react-testing-library';
import { renderWithRouter } from '../../../helpers';
import LoginPage from '../login-page';
afterEach(cleanup);
const handleSubmit = jest.fn();
test('<LoginPage /> renders with blank fields', () => {
const { container } = renderWithRouter(<LoginPage />);
const usernameOrEmailNode = getByTestId(container, 'usernameOrEmail');
const passwordNode = getByTestId(container, 'login-password');
const submitButtonNode = getByTestId(container, 'login-button');
expect(usernameOrEmailNode.tagName).toBe('INPUT');
expect(passwordNode.tagName).toBe('INPUT');
expect(submitButtonNode.tagName).toBe('BUTTON');
expect(usernameOrEmailNode.getAttribute('value')).toBe('');
expect(passwordNode.getAttribute('value')).toBe('');
});
test('Clicking the submit button after entering values', async () => {
const { container } = renderWithRouter(<LoginPage handleSubmit={handleSubmit} />);
const usernameOrEmailNode = getByTestId(container, 'usernameOrEmail');
const passwordNode = getByTestId(container, 'login-password');
const submitButtonNode = getByTestId(container, 'login-button');
fireEvent.change(usernameOrEmailNode, { target: { value: fakeUser.username }});
fireEvent.change(passwordNode, { target: { value: fakeUser.password }});
fireEvent.click(submitButtonNode);
await wait(() => {
expect(handleSubmit).toHaveBeenCalledTimes(1);
});
expect(usernameOrEmailNode.tagName).toBe('INPUT');
expect(passwordNode.tagName).toBe('INPUT');
expect(submitButtonNode.tagName).toBe('BUTTON');
expect(usernameOrEmailNode.getAttribute('value')).toBe('');
expect(passwordNode.getAttribute('value')).toBe('');
});```
答案 0 :(得分:1)
要回答您的问题,您需要首先使handleSubmit常数在LoginPage.js外部可访问,以便可以对其进行模拟然后进行测试。例如,
LoginPage.js
export const handleSubmit = async (values, { setSubmitting }) => {
... code to handle submission
})
在您的测试中- LoginPage.spec.js
jest.unmock('./login-page');
import LoginPage, otherFunctions from '../login-page'
otherFunctions.handleSubmit = jest.fn();
...
test('Clicking the submit button after entering values', () => {
...
fireEvent.click(submitButtonNode);
expect(handleSubmit).toHaveBeenCalledTimes(1);
})
我希望以上内容能解决您的问题。
但是,按照单元测试的原理,上述组件 切勿对您的操作方式进行测试。而是您的测试设置 应该是这样-
- 添加一个名为
LoginForm.spec.js
的新测试文件,以测试您的LoginForm
组件。您将在此测试以下内容-
- 检查是否所有输入字段都已呈现。
- 检查是否在提交时使用正确的参数调用了正确的处理程序。
- 名为
LoginPage.spec.js
的现有测试文件将仅测试是否呈现了特定的表单,然后您也可以进行测试handleSubmit
方法分别做什么。我相信以上内容将使您的测试更加清晰易读 也是如此,因为关注点分离,这也将使您 测试更多边缘情况。