Тестирование простой Redux-формы с ферментом (где значение ??) - PullRequest
0 голосов
/ 13 февраля 2019

У меня самая простая форма редукса, подключенная к примеру редукса:

import * as React from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';

class TestForm extends React.PureComponent {
    render() {
        return (
            <form>
                <Field component={Input} name={'testField'}/>
            </form>
        );
    }
}

class Input extends React.PureComponent {
    render(): React.Node {
        let { input } = this.props;
        // input = {name: 'testField', value: 'test value'};
        return (
                <input name={input.name} value={input.value} type='text' onChange={()=>1}/>
        );
    }
}

const mapStateToProps = ({ testForm }) => {
    return {
        initialValues: testForm,
    };
};

export const TestFormWithReduxForm = reduxForm({ form: 'test form'})(TestForm);

export default connect(mapStateToProps)(TestFormWithReduxForm);

Обратите внимание на следующее:

  • У меня есть свой собственный пользовательский ввод (называемый Input)
  • Я подключаюсь к reduxForm, а затем подключаюсь к redux.
  • Переданные начальные значения должны иметь 'name' и 'value'.

У меня естьследующий тест (Jest + Enzyme)

import React from 'react';
import { Provider } from 'react-redux';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import configureStore from 'redux-mock-store';

import TestForm from './TestForm';

Enzyme.configure({ adapter: new Adapter() });

describe('Redux Form Test', () => {
    let wrapper;

    let mockStoreData = {
        testForm: {
            testField: 'test value',
        },
    };

    const mockStore = configureStore();
    const store = mockStore(mockStoreData);

    beforeEach(() => {
        wrapper = mount(
            <Provider store={store}>
                    <TestForm />
            </Provider>
        );
    });

    it('Check Value', () => {
        let inputs = wrapper.find('input');
        expect(inputs.at(0).prop('name')).toBe('testField'); //OK!!!
        expect(inputs.at(0).prop('value')).toBe('test value'); //empty string!!
    });
});

Тест Jest передает объект 'testForm' с 'testField' (и его значением) в хранилище.

Как и ожидалось,имя на первом входе - «testField», однако «значение» пустое (т. е. пустая строка).

Это не ожидается, потому что, если бы мне пришлось визуализировать компонент на нормальной странице,появится «тестовое значение».

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

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

1 Ответ

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

Я не уверен, почему вы хотите или не должны тестировать функциональность Redux Form, так как она уже была протестирована создателями / сопровождающими.Тем не менее, redux-mock-store, по-видимому, предназначен только для unit тестов (где вы будете издеваться middlewares и позвоните store.dispatch(actionType) и ожидаете, что будет вызван action).Он не обрабатывает reducer побочных эффектов и не отслеживает изменения в state.

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

При этом ... для теста integration вам нужно будет использовать реальный store, который содержит reducer в форме-избыточности и ваше состояние field.

Рабочий пример : https://codesandbox.io/s/zl4p5w26xm (я включил интеграционный тест Form и модульный тест Input - как вы заметите, модульный тест Inputпокрывает большинство ваших потребностей в тестировании)

контейнеры / Form / Form.js

import React, { Component } from "react";
import { Form, Field, reduxForm } from "redux-form";
import { connect } from "react-redux";
import Input from "../../components/Input/input";

const isRequired = value => (!value ? "Required" : undefined);

class SimpleForm extends Component {
  handleFormSubmit = formProps => {
    alert(JSON.stringify(formProps, null, 4));
  };

  render = () => (
    <div className="form-container">
      <h1 className="title">Text Field</h1>
      <hr />
      <Form onSubmit={this.props.handleSubmit(this.handleFormSubmit)}>
        <Field
          className="uk-input"
          name="testField"
          component={Input}
          type="text"
          validate={[isRequired]}
        />
        <button
          type="submit"
          className="uk-button uk-button-primary uk-button-large submit"
          disabled={this.props.submitting}
        >
          Submit
        </button>
        <button
          type="button"
          className="uk-button uk-button-default uk-button-large reset"
          disabled={this.props.pristine || this.props.submitting}
          onClick={this.props.reset}
          style={{ float: "right" }}
        >
          Clear
        </button>
      </Form>
    </div>
  );
}

export default connect(({ field }) => ({
  initialValues: { [field.name]: field.value }
}))(
  reduxForm({
    form: "SimpleForm"
  })(SimpleForm)
);

контейнеры / Form / __ test __ / Form.js

import React from "react";
import { Provider } from "react-redux";
import { mount } from "enzyme";
import SimpleForm from "../Form";
import store from "../../../store/store";

const wrapper = mount(
  <Provider store={store}>
    <SimpleForm />
  </Provider>
);

describe("Redux Form Test", () => {
  it("renders without errors", () => {
    expect(wrapper.find(".form-container")).toHaveLength(1);
  });

  it("fills the input with a default value", () => {
    expect(wrapper.find("input").prop("name")).toBe("testField");
    expect(wrapper.find("input").prop("value")).toBe("Test Value");
  });

  it("updates input value when changed", () => {
    const event = { target: { value: "Test" } };
    wrapper.find("input").simulate("change", event);
    expect(wrapper.find("input").prop("value")).toBe("Test");
  });

  it("resets the input value to defaults when the Clear button has been clicked", () => {
    wrapper.find("button.reset").simulate("click");
    expect(wrapper.find("input").prop("value")).toBe("Test Value");
  });
});

stores / stores.js (для простоты я объединил reducers и store в один файл)

import { createStore, combineReducers } from "redux";
import { reducer as formReducer } from "redux-form";

const initialValues = {
  name: "testField",
  value: "Test Value"
};

const fieldReducer = (state = initialValues, { type, payload }) => {
  switch (type) {
    default:
      return state;
  }
};
const reducer = combineReducers({
  field: fieldReducer,
  form: formReducer
});

export default createStore(reducer);

Примечание: кромеиспользуя initialValues, скрытую в документации, существует три других способа обновления значений полей: использование reducer.plugin в формате redux-формы и отправка действия для обновления формы, или by используя this.props.intialize({ testField: "Test Value" }); с enableReinitialize: true и keepDirtyOnReinitialize: true, или this.props.change("SimpleForm", { testField: "Test Value" });.Важно отметить, потому что иногда mapStateToProps является асинхронным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...