pistacchio
pistacchio

Reputation: 58893

How to simulate changing the value of a child with React-Enzyme

Given the following simple components:

function ValueInput (props) {
  const [val, setVal] = useState(props.value);

  return <input value={val} onChange={v => setVal(v)}/>;
}

function MyComponent (props) {
  const [val, setVal] = useState(props.value);

  return (
    <div>
      <div>{val}</div>
      <ValueInput value={val}/>
    </div>
  );
}

I'm mounting them in order to test them with Enzyme and Jest:

const component = mount(<MyComponent value={42}/>);
const inputEl = component.find('input');

How do I simulate changing the value of the inner input and have it reflected in the div? I'm trying with the following code, but it doesn't work:

console.log(component.debug());
inputEl.simulate('change', { target: { value: 24 } });
// component.update();
console.log(component.debug());

Even forcing the update doesn't change the values. The printed component stays the same:

  <MyComponent value={42}>
    <div>
      <div>
        42
      </div>
      <ValueInput value={42}>
        <input value={42} onChange={[Function: onChange]} />
      </ValueInput>
    </div>
  </MyComponent>

Upvotes: 1

Views: 525

Answers (1)

Clarity
Clarity

Reputation: 10873

In your code

function ValueInput (props) {
  const [val, setVal] = useState(props.value);

  return <input value={val} onChange={v => setVal(v)}/>;
}

You're only changing the value of the child component, the value of the parent is not affected, since you didn't call the parent's setVal method.

You need to update your code:

function ValueInput (props) {
  const [val, setVal] = useState(props.value);

  const handleChange = e => {
    const {value} = e.target;
    setVal(value);
    props.setParentVal(value) // Pass the changed value to the parent
  }

  return <input value={val} onChange={handleChange}/>;
}

function MyComponent (props) {
  const [val, setVal] = useState(props.value);

  return (
    <div>
      <div>{val}</div>
      <ValueInput value={val} setParentVal={setVal}/>
    </div>
  );
}

Also looking at the code, it is not necessary to duplicate the state inside your child component, you can use the parent's methods directly to manipulate and store input value:

function ValueInput ({val, setVal}) {
   return <input value={val} onChange={setVal}/>;
}

function MyComponent (props) {
  const [val, setVal] = useState(props.value);

 const handleChange = e => {
    const {value} = e.target;
    setVal(value);
  }

  return (
    <div>
      <div>{val}</div>
      <ValueInput value={val} setVal={handleChange}/>
    </div>
  );
}

Upvotes: 2

Related Questions