2015-09-04 13 views
10

Hintergrund

React Shallow Rendering testsReagieren Testing: Event-Handler in Shallow Rendering Unit-Tests Reagieren

ich zu lernen bin versucht, wie man die Shallow Rendering TestUtil Reagieren verwenden und hatte die Tests vorbei, bis ich eine onClick Event-Handler hinzugefügt beide; Es scheint, dass es einen Unterschied mit der Accordion.toggle Funktion geben muss, die ich versuche, in Accordion.test.js vs this.toggle in Accordian.js zu verwenden ... aber ich kann es nicht herausfinden.

Frage

Wie kann ich die beiden markierten Tests in Accordian.test.js passieren bekommen?

Schritte

  1. Klon https://github.com/trevordmiller/shallow-rendering-testing-playground
  2. npm install
  3. npm run dev zu reproduzieren - sehen, dass Komponente funktioniert, wenn Sie "Lorem Ipsum" klicken
  4. npm run test:watch - sehen, dass Tests versagen

Antwort

8

Es gibt eine Reihe von Fragen, die Tests von Vergehen zu verhindern .

  1. Accordion.toggle in Ihrem Test ist eine Eigenschaft der Accordion Klasse und this.toggle in Ihrem Code ist eine Eigenschaft einer Instanz der Accordion Klasse:

    beim Test der Suche „sollte standardmäßig inaktiv sein“ - In diesem Fall vergleichen Sie zwei verschiedene Dinge. Um auf die Instanzmethode in Ihrem Test zuzugreifen, können Sie Accordion.toggle durch Accordion.prototype.toggle ersetzen. Was würde funktionieren, wenn es in Ihrem Konstruktor nicht für this.toggle = this.toggle.bind(this); wäre. Was uns zum zweiten Punkt führt.

  2. Wenn Sie anrufen .bind() auf eine Funktion erstellt es eine neue Funktion zur Laufzeit - so können Sie es nicht auf den ursprünglichen Accordion.prototype.toggle vergleichen. Der einzige Weg, dies zu umgehen, ist die „gebunden“ Funktion aus dem Ergebnis ziehen aus machen:

    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> 
    ]); 
    

Was Ihren zweiten andernfalls Test „sollte aktiv werden, wenn darauf geklickt“:

  1. Sie versuchen, result.props.onClick() aufzurufen, die nicht existiert.Sie wollten anrufen result.props.children[0].props.onClick();

  2. Es gibt einen Fehler in React, der eine globale Variable "Dokument" beim Aufrufen von SetState mit seichtem Rendering deklariert erfordert - wie man dies unter allen Umständen umgehen kann, sprengt den Rahmen dieser Frage, aber eine schnelle Arbeit, um Ihre Tests zu erhalten, ist es, global.document = {}; direkt vor dem Aufruf der OnClick-Methode hinzuzufügen. Mit anderen Worten, wo Ihr Original-Test hatte:

    result.props.onClick(); 
    

    Sollte jetzt sagen:

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

    Siehe Abschnitt "Reparieren beschädigter setState()" on this page und this react issue.

2

Marcin Grzywaczewski schrieb eine große article mit einer Vermeidung des Problems einen Click-Handler für die Prüfung, die mit flachem Rendering funktioniert.

ein verschachteltes Element mit einer onClick Stütze und einen Handler mit Kontext Gegeben an die Komponente gebunden:

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' }); 
} 

Sie können manuell den Funktionswert der onClick prop aufrufen, im Ereignisobjekt Anstoßen:

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

Ich habe erfolgreich meinen Klick in meiner zustandslosen Komponente getestet. Hier ist, wie:

Meine Komponente:

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; 

Mein Test:

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(); 
}); 

Das Wichtigste ist, um die Komponente zu wickeln:

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

Hoffe, es hilft!

Verwandte Themen