2015-09-04 3 views
10

Фоновые

React Shallow Rendering testsРеагировать Тестирование: обработчики событий в React Shallow Rendering модульных тестов

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

Вопрос

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

Шаги по воспроизведению

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

ответ

8

Есть целый ряд вопросов, предотвращающих тесты с прохождения ,

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

  1. Accordion.toggle в тесте является свойством Accordion класса и this.toggle в коде является свойством экземпляра Accordion класса - поэтому в этом случае вы сравниваете две разные вещи. Чтобы получить доступ к методу «экземпляр» в вашем тесте, вы можете заменить 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()" on this page и this react issue.

1

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

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

2

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

Учитывая вложенный элемент с 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'); 
}); 
0

Я успешно проверил свой клик в своем компоненте без гражданства. Вот как:

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

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> 

Надеется, что это поможет!

Смежные вопросы