用酶测试简单的Redux-Form(值在哪里?)

时间:2019-02-13 13:33:43

标签: reactjs redux enzyme redux-form

我有连接到redux示例的最简单的redux形式:

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);

请注意以下几点:

  • 我有自己的自定义输入(称为输入)
  • 我先连接到reduxForm,然后再连接到redux。
  • 传入的初始值应具有“名称”和“值”。

我有以下测试(Jest +酶)

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测试将带有“ testField”(及其值)的“ testForm”对象传递到商店中。

按预期,第一个输入的名称为'testField',但是'value'为空(即,空字符串)。

这是不希望的,因为如果我要在常规页面中呈现组件,则会显示“测试值”。

所以这里似乎有些破损。我不确定它是否与redux形式或酶有关,但是redux形式的Field对象似乎正在拦截传递到Input对象的属性。

我开始质疑是否甚至可以 可能 来测试 redux表格

1 个答案:

答案 0 :(得分:1)

我不确定您为什么不需要或不需要测试Redux Form的功能,因为它已经被创建者/维护者测试过。但是,redux-mock-store似乎仅用于unit测试(您将模拟middlewares并调用store.dispatch(actionType)并期望action被调用)。它不处理reducer的副作用,也不跟踪state中的变化。

在上述情况下,您只需要对自定义Input组件进行单元测试,因为这是唯一与标准Redux表单不同的组件。

也就是说,对于integration测试,您需要使用包含Redux表单的store和您的reducer状态的真实field

工作示例https://codesandbox.io/s/zl4p5w26xm(我包括一个Form集成测试和一个Input单元测试-您会注意到,{ {1}}单元测试可以满足您的大部分测试需求)

容器/表格/Form.js

Input

容器/表格/ __ test __ / 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)
);

stores / stores.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"); }); }); 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); (隐藏在文档中)之外,还有三种其他方法来更新字段值:利用redux-form的reducer.plugin并分派操作以更新表单,或者使用initialValuesthis.props.intialize({ testField: "Test Value" });enableReinitialize: true,或使用keepDirtyOnReinitialize: true,。请注意,因为有时this.props.change("SimpleForm", { testField: "Test Value" });是异步的。