Test setting text value with React and Enzyme
Asked Answered
H

6

28

How do you set the text of a text input and then test it's value with React / Enzyme?

const input = wrapper.find('#my-input');

input.simulate('change',
  { target: { value: 'abc' } }
);

const val = input.node.value;

//val is ''

All the solutions here appear not to work..

Horick answered 19/1, 2017 at 1:33 Comment(2)
It appears that you need to use mount for it to work properly.Progestational
Possible duplicate of Enzyme - How to access and set <input> value?Boy
P
33

To really understand what's happening in your code it would be useful to see your component code (specifically your onChange handler.

However, in regards to the following code:

input.simulate('change', {target: {value: 'abc'}});

This won't actually change the value of your <input /> element, instead it just causes your onChange function to be run and be provided an event object that looks like {target: {value: 'abc'}}.

The idea is that your onChange function would update your state or store, so triggering this function should result in your DOM being updated. If you don't actually have an onChange handler defined using input.simulate('change') won't do anything.

So, if your goal is to actually set the value of an input and not trigger an onChange handler then you can use JS to manually update the DOM using something like wrapper.find('#my-input').node.value = 'abc'; however this is circumventing React's render cycle and you'll likely see this value cleared/removed if you do anything to trigger a re-render.

Pedestrianize answered 19/1, 2017 at 1:48 Comment(4)
I am trying to set the value with input.node.value = "Test", and I am getting this error TypeError: Can't add property value, object is not extensible. Any ideas?Cumings
@Cumings Check out my answer below.Ehr
you might need to remove target / value: input.simulate('changeText', '6');Whaley
I also had the issue of: TypeError: Cannot add property value, object is not extensible. What resolved it for me was changing node.find('#id_name').get(0).value = to node.find('#id_name').instance().value =Feminism
E
25

I'm using React 16 and Enzyme 3.10 over here and this completely worked for me (after trying too many different suggestions out there):

wrapper.find("input").instance().value = "abc";

Apparently, in previous versions you could use node or getNode() instead of instance(), which were parts of my many previous attempts.

Ehr answered 8/11, 2017 at 13:51 Comment(4)
I used .node but Enzyme told me to use getElement() but that gave me the react element and not the dom element. Thx for sharing the instance() function.Colubrid
typescript is failing with error: TS2339: Property value does not exist on type Component<{}, {}> . Can you please help?Evalynevan
@Evalynevan Sorry, man...but I have no idea how to tackle this, given I've never worked with Typescript before.Ehr
Typescript needs to know what type of element you're dealing with specifically. In this case wrapper.find("input").instance<HTMLInputElement>().value = "abc"; would work.Apodictic
G
11

This works for both Enzyme 3 and Enzyme 2:

wrapper.find('input').getDOMNode().value = 'new value';
wrapper.find('input').simulate('change');

.getDOMNode() can be used like .node in Enzyme 2 and like .instance() in Enzyme 3.

Grieve answered 8/1, 2018 at 7:36 Comment(1)
Enzyme 3.3.x wrapper.getDOMNode is not a function. Looks like it's only for mount github.com/airbnb/enzyme/blob/master/docs/api/ReactWrapper/…Immeasurable
F
2

If using TypeScript you can do the following

wrapper.find('input').getDOMNode<HTMLInputElement>().value = 'new value';
wrapper.find('input').simulate('change');
Farrison answered 8/12, 2019 at 18:44 Comment(0)
M
0

Here it works for me..

I have change the input text, with value updation. And Update my DOM property.

.update()

After updating I am checking the button disable property with input mobile number length use cases.

const input = MobileNumberComponent.find('input')
input.props().onChange({target: {
   id: 'mobile-no',
   value: '1234567900'
}});
MobileNumberComponent.update()
const Footer = (loginComponent.find('Footer'))
expect(Footer.find('Buttons').props().disabled).equals(false)
Morril answered 2/1, 2019 at 6:31 Comment(0)
P
0

I found that I had to use Jest's fake time to give my React onChange function time to run and note the new value of the text input. Here's the full test (though, no setup), using React, jest, and enzyme:

describe('Modal with text input', () => {
  beforeEach(() => {
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.clearAllTimers();
    jest.useRealTimers();
  });

  it('enter email, get email tag', () => {
    const modal = render();
    let textField = modal.find('input[data-test-id="assignEmailInput"]');
    let tags = modal.find('[className*="spectrum-Tag--removable"]');

    // initial load
    expect(textField.prop('value')).toBe('');
    expect(tags).toHaveLength(3);

    // "write" in the input
    textField.simulate('click');
    textField.simulate('change', { target: { value: '[email protected]' } });

    // enact the writing for jest
    jest.advanceTimersByTime(150);
    modal.update();
    textField = modal.find('input[data-test-id="assignEmailInput"]');
    tags = modal.find('[className*="spectrum-Tag--removable"]');

    expect(textField.prop('value')).toBe('[email protected]');
    expect(tags).toHaveLength(3);
    const expected = ['[email protected]', '[email protected]', '[email protected]'];
    tags.forEach((tag, i) => expect(tag.contains(expected[i])).toBe(true));

    // enact the onBlur function that sets tags
    textField.simulate('blur');
    modal.update();
    textField = modal.find('input[data-test-id="assignEmailInput"]');
    tags = modal.find('[className*="spectrum-Tag--removable"]');

    expect(textField.prop('value')).toBe('');
    expect(tags).toHaveLength(4);
    expected.push('[email protected]');
    tags.forEach((tag, i) => expect(tag.contains(expected[i])).toBe(true));
  });
});
Pulpboard answered 9/1 at 0:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.