Фермент - Як отримати доступ та встановити значення <input>?


90

Мене бентежить, як отримати доступ до <input>значення під час використання mount. Ось те, що я отримав як тест:

  it('cancels changes when user presses esc', done => {
    const wrapper = mount(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    console.log(input.render().attr('value'));
    input.simulate('focus');
    done();
  });

Консоль роздруковується undefined. Але якщо я трохи модифікую код, це працює:

  it('cancels changes when user presses esc', done => {
    const wrapper = render(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    console.log(input.val());
    input.simulate('focus');
    done();
  });

За винятком, звичайно, input.simulateрядка не вдається, оскільки я використовую renderзараз. Мені потрібні обидва, щоб нормально працювати. Як це виправити?

РЕДАГУВАТИ :

Слід зазначити, що <EditableText />це не контрольований компонент. Але коли я проходжу defaultValueв <input />, по- видимому , щоб встановити значення. Другий блок коду вище роздруковує значення, і також, якщо я перевіряю вхідний елемент у Chrome і ввожу $0.valueв консолі, він показує очікуване значення.

Відповіді:


99

Я думаю, що ви хочете:

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

Ось моє джерело .

Вам не потрібно render()ніде використовувати для встановлення значення. І просто FYI, ви використовуєте два різні render(). Один у вашому першому блоці коду - від Enzyme, і є методом на об'єкті-обгортці mountта findнадає вам. Другий, хоча це і не на 100% зрозуміло, є, мабуть, тим, від якого react-dom. Якщо ви використовуєте фермент, просто використовуйте shallowабо, mountякщо це доречно, і немає необхідності у renderвід react-dom.


input.render()Чи не react-domроблять. Це: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam

3
Крім того, shallow()не працює з якихось причин .. focusподія запускає метод, який намагається здійснити посилання this.refs.input, який не вдається. Але коли я замінююся shallowна mount, це працює, як очікувалося. В основному .. (ще одне питання із імітацією клавіші ESC)
ffxsam

Я повинен був бути більш чітким. Я мав на увазі візуалізацію, яка виглядає render(<EditableText defaultValue="Hello" />). Я думаю, що ваш варіант використання є більш спеціалізованим, ніж я думав; Я бачу, що це стосується лише встановлення вхідного значення, але з фокусом та "скасуванням змін". Було б чудово, якби ви могли створити плункер .
Тайлер Коллер

44

За допомогою ферменту 3 , якщо вам потрібно змінити вхідне значення, але не потрібно запускати onChangeфункцію, ви можете просто зробити це ( nodeвластивість видалено ):

wrapper.find('input').instance().value = "foo";

Ви можете використовувати wrapper.find('input').simulate("change", { target: { value: "foo" }})для виклику, onChangeякщо у вас є підтримка для цього (тобто для контрольованих компонентів).


7
NOTE: can only be called on a wrapper instance that is also the root instance.- з документів на airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html
davidjb

2
instance()можна викликати на будь-якій дочірній обгортці, якщо вона була відтворена через mount.
Володимир Черванев

41

Зрозумів. (оновлена ​​/ вдосконалена версія)

  it('cancels changes when user presses esc', done => {
    const wrapper = mount(<EditableText defaultValue="Hello" />);
    const input = wrapper.find('input');

    input.simulate('focus');
    input.simulate('change', { target: { value: 'Changed' } });
    input.simulate('keyDown', {
      which: 27,
      target: {
        blur() {
          // Needed since <EditableText /> calls target.blur()
          input.simulate('blur');
        },
      },
    });
    expect(input.get(0).value).to.equal('Hello');

    done();
  });

Цікаво, як це працює для вас. Ми використовуємо PhantomJS і mount()не вставляємо компоненти в DOM. Отже, вони не можуть отримати фокус. Ми повинні додати елемент DOM і використовувати contextопцію дляmount()
Pre101,

@ Pre101 Я насправді почав використовувати Jest замість Enzyme. Настійно рекомендується!
ffxsam

1
@ffxsam: input.get (0) .value завжди відображає "undefined"
Siddharth_Vyas

3
@Siddharth_Vyas tryinput.prop('value')
Ersel Aker

16

Так багато різних думок тут. Єдине, що працювало у мене, - це нічого з перерахованого вище, а використання input.props().value. Я сподіваюся, що це допоможе.


1
Це єдина відповідь, яка дозволила мені допитати значення вводу.
mojave

1
Варто зазначити, що ви також можете використовувати: input.prop('value')якщо ви знаєте назву вашого ключа проп.
Стерлінг Борн,

4

Я використовую програму create-response-, яка за замовчуванням поставляється з жартом та ферментом 2.7.0.

Це працювало для мене:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input')[index]; // where index is the position of the input field of interest
input.node.value = 'Change';
input.simulate('change', input);
done();

3

Жодне з перерахованого не працювало для мене. Це те, що працювало для мене в Enzyme ^ 3.1.1:

input.instance().props.onChange(({ target: { value: '19:00' } }));

Ось решта коду для контексту:

const fakeHandleChangeValues = jest.fn();
  const fakeErrors = {
    errors: [{
      timePeriod: opHoursData[0].timePeriod,
      values: [{
        errorIndex: 2,
        errorTime: '19:00',
      }],
    }],
    state: true,
  };
const wrapper = mount(<AccessibleUI
    handleChangeValues={fakeHandleChangeValues}
    opHoursData={opHoursData}
    translations={translationsForRendering}
  />);
const input = wrapper.find('#input-2').at(0);
input.instance().props.onChange(({ target: { value: '19:00' } }));
expect(wrapper.state().error).toEqual(fakeErrors);

3

Я використовую реакцію з TypeScript, і наступне працює для мене

wrapper.find('input').getDOMNode<HTMLInputElement>().value = 'Hello';
wrapper.find('input').simulate('change');

Встановлення значення безпосередньо

wrapper.find('input').instance().value = 'Hello'` 

викликав у мене попередження про компіляцію.


1

Це працює для мене з використанням ферменту 2.4.1:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');

console.log(input.node.value);

4
Коли я починав використовувати Jest / фермент, я часто console.logперебирав предмет і перебирав (під-) властивості, щоб отримати те, що мені потрібно. Роблячи це, я часто закінчував використовувати .nodeв якійсь формі, як у вас. Однак я не пам’ятаю, щоб я .nodeзгадував про це в будь-якій офіційній документації, припускаючи, що це може змінюватися / перериватися між випусками, оскільки це офіційно не є частиною публічно рекламованого API. Крім того, часто здаються альтернативи. наприклад input.node.value=== input.get(0).value. Отже, це .nodeможе спрацювати, і я підозрюю, що іноді це забезпечить хороший хак, але використовуйте з обережністю.
Ендрю Віллемс,

Це вже не публічний метод.
Faissaloo

1

ось мій код ..

const input = MobileNumberComponent.find('input')
// when
input.props().onChange({target: {
   id: 'mobile-no',
   value: '1234567900'
}});
MobileNumberComponent.update()
const Footer = (loginComponent.find('Footer'))
expect(Footer.find('Buttons').props().disabled).equals(false)

Я оновлюю свій DOM за допомогою, componentname.update() а потім перевіряю перевірку кнопки подання (вимкнути / увімкнути) довжиною 10 цифр.


0

У моєму випадку я використовував зворотні виклики ref,

  <input id="usuario" className="form-control" placeholder="Usuario"
                                                       name="usuario" type="usuario"
                                                       onKeyUp={this._validateMail.bind(this)}
                                                       onChange={()=> this._validateMail()}
                                                       ref={(val) =>{ this._username = val}}
                                                    >

Для отримання значення. Тож фермент не змінить значення this._username.

Тому мені довелося:

login.node._username.value = "mario@com.com";
    user.simulate('change');
    expect(login.state('mailValid')).toBe(true);

Щоб мати змогу встановити значення, потім виклик зміни. А потім стверджуйте.



0

У випадку, якщо хтось бореться, я виявив, що для мене працює наступне

const wrapper = mount(<NewTask {...props} />); // component under test
const textField = wrapper.find(TextField);

textField.props().onChange({ target: { value: 'New Task 2' } })
textField.simulate('change');
// wrapper.update() didn't work for me, need to find element again

console.log(wrapper.find(TextField).props()); // New Task 2

Здається, спочатку потрібно визначити, що відбувається в події зміни, а потім змоделювати це (замість того, щоб імітувати подію зміни даними)


0

Я вирішив дуже простим способом:

  1. Встановіть значення з реквізиту :
  const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
  1. Код HTML :
  <input type='text' defaultValue={props.name} className='edituser-name' />
  1. Доступ до атрибута з wrapper.find(element).props().attribute-name:
  it('should render user name', () => {
    expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
  });

Ура


0

Жодне з наведених вище рішень не спрацювало для мене, оскільки я використовував Formik, і мені потрібно було позначити поле "торкнутим" разом із зміною значення поля. Наступний код працював для мене.

const emailField = orderPageWrapper.find('input[name="email"]')

emailField.simulate('focus')
emailField.simulate('change', { target: { value: 'test@example.com', name: 'email' } })
emailField.simulate('blur')


-1

.simulate()у мене якось не працює, я змусив це працювати, просто отримавши доступ до node.valueбез необхідності дзвонити .simulate(); у вашому випадку:

const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input').at(0);

// Get the value
console.log(input.node.value); // Hello

// Set the value
input.node.value = 'new value';

// Get the value
console.log(input.node.value); // new value

Сподіваюся, це допомагає іншим!


Викидає `` Спроба отримати доступ до ReactWrapper :: node, який раніше був приватною власністю на екземплярах Enzyme ReactWrapper, але більше не є і на нього не слід покладатися. Подумайте про використання методу getElement (). ``
Даві Ліма,

2
@DaviLima для нової версії Enzyme, замість того, щоб .nodeви використовували .instance()або .getDOMNode(), залежить, якщо ви використовували результат як ReactElement або DOMComponent.
Jee
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.