Enzyme - Как получить доступ и установить значение <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()нигде использовать для установки значения. И, к вашему сведению, вы используете два разных render(). Один в первом блоке кода от Enzyme, и является методом на объекте wraper mountи findдать вам. Второй, хоть и не на 100% ясен, вероятно, из react-dom. Если вы используете энзимы, просто использовать shallowили mountв зависимости от обстоятельств , и нет никакой необходимости renderс react-dom.


Это input.render()не react-domрендеринг. Это так: airbnb.io/enzyme/docs/api/ShallowWrapper/render.html
ffxsam 05

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

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

44

С Enzyme 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')
Эрсель Акер

16

Так что здесь много разных мнений. Единственное, что у меня сработало, это ничего из вышеперечисленного, я использовал input.props().value. Надеюсь, это поможет.


1
Это единственный ответ, который позволил мне узнать значение ввода.
Мохаве

1
Следует отметить, что вы также можете использовать: input.prop('value')если вы знаете имя своего проп-ключа.
Стерлинг Борн

4

Я использую приложение create-react-app, которое по умолчанию поставляется с jest и ферментом 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);

Чтобы иметь возможность установить значение, тогда вызовите change. А потом утверждать.



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. Установите значение из props :
  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 Mok
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.