Я не уверен, почему вы хотите или не должны тестировать функциональность 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
является асинхронным.