在酶/反应单元测试中模拟形状变化不会改变字段值

时间:2018-01-14 18:07:51

标签: javascript reactjs enzyme

我正在进行一些基本的表格互动测试

const setup = (errors=false) => {
  let props = {
    budget: {}, errors: {},
    onChange: () => {},
    onSave: () => {}
  };

  if (errors === true) {
    props.errors.budgetCategory= "error";
  }

  return shallow(<AddBudgetForm {...props} />);
};


describe("Fluctuating errors based on input values", () => {
  it("Renders an error when a number is present in the cost field", () => {
    let wrapper = setup();
    wrapper.find('[name="budgetCategory"]').simulate('change', { target: { value: '7' } });
    console.log(wrapper.find('[name="budgetCategory"]').props());
  });
});

我分析控制台上的道具,看到value字段仍未定义...

{ className: 'form-control',
  placeholder: 'Enter Name of Budget Category',
  onChange: [Function: onChange],
  value: undefined,
  name: 'budgetCategory' }

理想情况下,我要测试的是,模拟非按数字的按键应触发onChange处理程序以向表单传播错误。

我尝试在设置中添加一个新的onChange处理程序,但不起作用:

  let props = {
    budget: {}, errors: {},
    onChange: (e) => {props.budget.budgetCategory = e.target.value;},
    onSave: () => {}
  };

AddBudgetForm组件

import React, { Component, PropTypes } from 'react';
import Alert from '../common/Alert';
import TextInput from '../common/TextInput';

const renderDays = () => {
  return Array(31).fill().map((_, i = 1) => <option key={i+1}>{i+1}</option>);
};

const errorsInForm = errors => {
  let error = false;
  Object.keys(errors).map(item => {
    if (errors[item]) { error = true; }
  });

  return error;
};

const generateValidationError = error => {
  return (
    <span style={{color: "red"}}>{error}</span>
  );
};

const AddBudgetForm = ({budget, onChange, onSave, errors}) => {
  return (
    <div name="AddBudgetForm">
      <form>
      {!errorsInForm(errors) &&
        <Alert
          name="add-budget-alert"
          alertType = "alert alert-info"
          fontAwesomeIcon = "fa fa-info"
          alertDescription = " Adding a budget is simple. Add a category such as groceries
          , allocate $200.00 per month and the day you'd like the budget to reset."
        />
      }

      {errorsInForm(errors) &&
        <Alert
          name="add-budget-alert"
          alertType = "alert alert-danger"
          fontAwesomeIcon = "fa fa-warning"
          alertDescription = " There are problems with the form submission. Ensure all values in the form are valid."
        />
      }

    <TextInput
        className="form-control"
        placeholder="Enter Name of Budget Category"
        onChange={onChange}
        value={budget.category}
        name="budgetCategory"
      />
    {errors.budgetCategory != "" && generateValidationError(errors.budgetCategory)}

      <div className="form-group input-group">
        <span className="input-group-addon"><i className="fa fa-usd"></i></span>
        <input
          className="form-control"
          placeholder="Monthly Budget Cost"
          onChange={onChange}
          value={budget.cost}
          name="budgetCost"
        />
      </div>
    {errors.budgetCost != "" && generateValidationError(errors.budgetCost)}

      <select
        className="form-control"
        onChange={onChange}
        value={budget.date}
        name="budgetDate"
      >
        <option>Select Day of Month Budget Item is Due</option>
          {renderDays()}
      </select>
    {errors.budgetDate != "" && generateValidationError(errors.budgetDate)}

      <br/>
      {(!errorsInForm(errors)) &&
        <button className="btn btn-primary" type="submit" onClick={() => onSave(budget)}>Add Budget</button>
      }
      {(errorsInForm(errors)) &&
        <button className="btn btn-primary" type="submit" disabled>Fix Form Errors</button>
      }
      </form>
    </div>
  );
};

AddBudgetForm.propTypes = {
  budget: PropTypes.object,
  onChange: PropTypes.func,
  onSave: PropTypes.func,
  errors: PropTypes.object
};

export default AddBudgetForm;

2 个答案:

答案 0 :(得分:1)

docs开始,.simulate()方法仅影响您正在模拟的事件的事件道具。在这种情况下,您传递的合成事件args将仅提供给您的onChange()函数。实际的value道具不受影响。

要确认,只需将自定义onChange()处理程序更新为console.log提供给它的事件对象,例如

let props = {
    budget: {}, errors: {},
    onChange: (event) => { console.log(event); },
    onSave: () => {}
};

另一个问题是,此模拟不会发生正常事件冒泡 - 请确保直接在要触发事件的节点上运行.simulate()方法。

重构的AddBudgetForm 注意:这些只是一些小建议,并不一定是唯一正确的方法。

import React, { Component, PropTypes } from 'react';
import Alert from '../common/Alert';
import TextInput from '../common/TextInput';

const renderDays = () => Array(31).fill().map( 
    (_, i = 1) => <option key={i+1}>{i+1}</option> 
);

/**
 * Returns true if a key has a non-null value.
 * @param  {Object} errors - Errors object
 * @return {Boolean} Is there an error?
 */
const errorsInForm = errors => 
    Object.keys(errors).reduce( (hasError, item) => hasError || item != null, false);

const generateValidationError = error => <span style={{color: "red"}}>{error}</span>;

const AddBudgetForm = ({ budget, onChange, onSave, errors = {} }) => (
  <div name="AddBudgetForm">
    <form>
    { ! errorsInForm(errors)
      ? (
      <Alert
        name="add-budget-alert"
        alertType = "alert alert-info"
        fontAwesomeIcon = "fa fa-info"
        alertDescription = " Adding a budget is simple. Add a category such as groceries
        , allocate $200.00 per month and the day you'd like the budget to reset."
      />)
      : (
      <Alert
        name="add-budget-alert"
        alertType = "alert alert-danger"
        fontAwesomeIcon = "fa fa-warning"
        alertDescription = " There are problems with the form submission. Ensure all values in the form are valid."
      />
      )
    }

  <TextInput
      className="form-control"
      placeholder="Enter Name of Budget Category"
      onChange={onChange}
      value={budget.category}
      name="budgetCategory"
    />
  { errors.budgetCategory != "" && 
    generateValidationError(errors.budgetCategory)
  }

    <div className="form-group input-group">
      <span className="input-group-addon"><i className="fa fa-usd"></i></span>
      <input
        className="form-control"
        placeholder="Monthly Budget Cost"
        onChange={onChange}
        value={budget.cost}
        name="budgetCost"
      />
    </div>
  { errors.budgetCost != "" && 
    generateValidationError(errors.budgetCost) 
  }

    <select
      className="form-control"
      onChange={onChange}
      value={budget.date}
      name="budgetDate"
    >
      <option>Select Day of Month Budget Item is Due</option>
        { renderDays() }
    </select>
  { errors.budgetDate != "" && 
    generateValidationError(errors.budgetDate)
  }

    <br/>
    { ! errorsInForm(errors) 
      ? <button className="btn btn-primary" type="submit" onClick={() => onSave(budget)}>Add Budget</button>
      : <button className="btn btn-primary" type="submit" disabled>Fix Form Errors</button>
    }
    </form>
  </div>
);

AddBudgetForm.propTypes = {
  budget: PropTypes.object,
  onChange: PropTypes.func,
  onSave: PropTypes.func,
  errors: PropTypes.object
};

export default AddBudgetForm;

答案 1 :(得分:0)

您正在使用一个以实际DOM元素为目标wrapper.find('[name="budgetCategory"]')的选择器。我假设在TextInput内你有一个输入相同的name。为什么不直接选择TextInput并调用其支柱,例如:

wrapper.find('TextInput').prop('onChange')(<some value here>)