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в консоли, он показывает ожидаемое значение.

ffxsam
источник

Ответы:

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если у вас есть опора для этого (например, для управляемых компонентов).

Bjudson
источник
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();
  });
ffxsam
источник
Любопытно, как это у вас работает. Мы используем 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. Надеюсь, это поможет.

Y2H
источник
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();
erika_dike
источник
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. А потом утверждать.

Cabaji99
источник
0

Это сработало для меня:

let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");
Махмуд Абд Аль Карим
источник
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