it-swarm.com.ru

React Тестирование: обработчики событий в React Модульные тесты мелкой визуализации

Фон

React Shallow Rendering tests

Я пытаюсь узнать, как использовать React Shallow Rendering TestUtil, и тесты проходили, пока я не добавил обработчик событий onClick в оба; Кажется, что должна быть какая-то разница с функцией Accordion.toggle, которую я пытаюсь использовать в Accordion.test.js против this.toggle в Accordian.js..., но я не могу понять это.

Вопрос

Как я могу пройти два выделенных теста в Accordian.test.js для прохождения?

Действия по воспроизведению

  1. Клон https://github.com/trevordmiller/shallow-rendering-testing-playground
  2. npm install
  3. npm run dev - увидеть, что компонент работает, когда вы нажимаете "Lorem Ipsum"
  4. npm run test:watch - увидеть, что тесты не пройдены
11
trevordmiller

Существует ряд проблем, препятствующих прохождению ваших тестов.

Глядя на тест «должен быть неактивным по умолчанию»:

  1. Accordion.toggle в вашем тесте является свойством класса Accordion, а this.toggle в вашем коде является свойством экземпляра класса Accordion - так что в этом случае вы сравниваете две разные вещи. Чтобы получить доступ к методу instance в вашем тесте, вы можете заменить Accordion.toggle на Accordion.prototype.toggle. Что бы работало, если бы не this.toggle = this.toggle.bind(this); в вашем конструкторе. Что приводит нас ко второму пункту.

  2. Когда вы вызываете .bind () для функции, она создает новую функцию во время выполнения - поэтому вы не можете сравнить ее с исходным Accordion.prototype.toggle. Единственный способ обойти это - извлечь «связанную» функцию из результата рендеринга:

    let toggle = result.props.children[0].props.onClick;
    
    assert.deepEqual(result.props.children, [
      <a onClick={toggle}>This is a summary</a>,
      <p style={{display: 'none'}}>This is some details</p>
    ]);
    

Что касается вашего второго провального теста «должен стать активным при нажатии»:

  1. Вы пытаетесь вызвать result.props.onClick(), который не существует. Вы хотели позвонить result.props.children[0].props.onClick();

  2. В React есть ошибка, которая требует объявления глобальной переменной «document» при вызове setState с неглубоким рендерингом - как обойти это в любых обстоятельствах выходит за рамки этого вопроса, но быстрый способ обойти тесты это добавить global.document = {}; прямо перед вызовом метода onClick. Другими словами, где ваш первоначальный тест имел:

    result.props.onClick();
    

    Должен теперь сказать:

    global.document = {};
    result.props.children[0].props.onClick();
    

    См. Раздел «Устранение неисправности setState ()» на этой странице и эта проблема .

9
David Mininger

Marcin Grzywaczewski написал отличную статью с обходным путем для тестирования обработчика щелчков, который работает с поверхностным рендерингом.

Дан вложенный элемент с опцией onClick и обработчиком с контекстом, связанным с компонентом:

render() {
  return (
    <div>
      <a className="link" href="#" onClick={this.handleClick}>
        {this.state.linkText}
      </a>
      <div>extra child to make props.children an array</div>
    </div>
  );
}

handleClick(e) {
  e.preventDefault();
  this.setState({ linkText: 'clicked' });
}

Вы можете вручную вызвать значение функции опоры onClick, заглушки в объекте события:

it('updates link text on click', () => {
  let tree, link, linkText;

  const renderer = TestUtils.createRenderer();
  renderer.render(<MyComponent />);

  tree = renderer.getRenderOutput();
  link = tree.props.children[0];
  linkText = link.props.children;

  // initial state set in constructor
  expect(linkText).to.equal('Click Me');

  // manually invoke onClick handler via props
  link.props.onClick({ preventDefault: () => {} });

  tree = renderer.getRenderOutput();
  link = tree.props.children[0];
  linkText = link.props.children;

  expect(linkText).to.equal('Clicked');
});
3
cantera

Для тестирования пользовательских событий, таких как onClick, вы должны использовать TestUtils.Simulate.click. К сожалению :

В настоящее время невозможно использовать ReactTestUtils.Simulate с неглубоким рендерингом, и я думаю, что проблема должна быть следующей: https://github.com/facebook/react/issues/1445

1
romseguy

Я успешно проверил мой щелчок в компоненте без сохранения состояния. Вот как:

Мой компонент:

import './ButtonIcon.scss';

import React from 'react';
import classnames from 'classnames';

const ButtonIcon = props => {
  const {icon, onClick, color, text, showText} = props,
    buttonIconContainerClass = classnames('button-icon-container', {
      active: showText
    });

  return (
    <div
      className={buttonIconContainerClass}
      onClick={onClick}
      style={{borderColor: color}}>
      <div className={`icon-container ${icon}`}></div>
      <div
        className="text-container"
        style={{display: showText ? '' : 'none'}}>{text}</div>
    </div>
  );
}

ButtonIcon.propTypes = {
  icon: React.PropTypes.string.isRequired,
  onClick: React.PropTypes.func.isRequired,
  color: React.PropTypes.string,
  text: React.PropTypes.string,
  showText: React.PropTypes.bool
}

export default ButtonIcon;

Мой тест:

it('should call onClick prop when clicked', () => {
  const iconMock = 'test',
    clickSpy = jasmine.createSpy(),
    wrapper = ReactTestUtils.renderIntoDocument(<div><ButtonIcon icon={iconMock} onClick={clickSpy} /></div>);

  const component = findDOMNode(wrapper).children[0];

  ReactTestUtils.Simulate.click(component);

  expect(clickSpy).toHaveBeenCalled();
  expect(component).toBeDefined();
});

Важно обернуть компонент:

<div><ButtonIcon icon={iconMock} onClick={clickSpy} /></div>

Надеюсь, это поможет!

0
Albert Olivé