Форма подачи Formik с библиотекой реагирования - PullRequest
0 голосов
/ 23 февраля 2019

Я хочу запустить обработчик отправки для 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('');
});```

1 Ответ

0 голосов
/ 24 февраля 2019

Чтобы ответить на ваш вопрос, вам нужно сначала сделать константу 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);
})

Надеюсь, что вышеизложенное решит вашу проблему.

Но, исходя из философии модульного тестирования, вышеперечисленные компоненты не должны тестироваться так, как вы это делаете.Вместо этого ваша тестовая установка должна выглядеть следующим образом -

  1. Добавьте новый тестовый файл с именем LoginForm.spec.js, который тестирует ваш LoginForm компонент.В этом вы должны проверить следующее:
    1. Проверить, были ли обработаны все поля ввода.
    2. Проверить, вызывается ли правильный обработчик при отправке и с правильными параметрами.
  2. Существующий тестовый файл с именем LoginPage.spec.js будет проверять только то, была ли отрисована конкретная форма, а затем вы также можете проверить, что метод handleSubmit делает по отдельности.

Я считаю,вышеизложенное сделает ваши тесты более четкими и удобочитаемыми из-за разделения проблем, а также позволит вам протестировать больше крайних случаев.

...