2016-05-24 8 views
5
  • ruft Reagieren v15.1.0
  • Jest v12.1.1
  • Enzyme v2.3.0

Ich versuche, finde heraus, wie man eine Komponente testet, die eine Zusage in einer Funktion aufruft, die durch einen Klick aufgerufen wird. Ich habe erwartet, dass die runAllTicks() Funktion von Jest mir hier hilft, aber es scheint das Versprechen nicht auszuführen.Testen mit Reagieren des Jest und Enzyme, wenn simuliert Klicks eine Funktion aufrufen, die ein Versprechen

Komponente:

import React from 'react'; 
import Promise from 'bluebird'; 

function doSomethingWithAPromise() { 
    return new Promise((resolve) => { 
    setTimeout(() => { 
     resolve(); 
    }, 50); 
    }); 
} 

export default class AsyncTest extends React.Component { 
    constructor(props) { 
    super(props); 

    this.state = { 
     promiseText: '', 
     timeoutText: '' 
    }; 

    this.setTextWithPromise = this.setTextWithPromise.bind(this); 
    this.setTextWithTimeout = this.setTextWithTimeout.bind(this); 
    } 

    setTextWithPromise() { 
    return doSomethingWithAPromise() 
     .then(() => { 
     this.setState({ promiseText: 'there is text!' }); 
     }); 
    } 

    setTextWithTimeout() { 
    setTimeout(() => { 
     this.setState({ timeoutText: 'there is text!' }); 
    }, 50); 
    } 

    render() { 
    return (
     <div> 
     <div id="promiseText">{this.state.promiseText}</div> 
     <button id="promiseBtn" onClick={this.setTextWithPromise}>Promise</button> 
     <div id="timeoutText">{this.state.timeoutText}</div> 
     <button id="timeoutBtn" onClick={this.setTextWithTimeout}>Timeout</button> 
     </div> 
    ); 
    } 
} 

Und die Tests:

import AsyncTest from '../async'; 
import { shallow } from 'enzyme'; 
import React from 'react'; 

jest.unmock('../async'); 

describe('async-test.js',() => { 
    let wrapper; 

    beforeEach(() => { 
    wrapper = shallow(<AsyncTest />); 
    }); 

    // FAIL 
    it('displays the promise text after click of the button',() => { 
    wrapper.find('#promiseBtn').simulate('click'); 

    jest.runAllTicks(); 
    jest.runAllTimers(); 

    wrapper.update(); 

    expect(wrapper.find('#promiseText').text()).toEqual('there is text!'); 
    }); 

    // PASS 
    it('displays the timeout text after click of the button',() => { 
    wrapper.find('#timeoutBtn').simulate('click'); 

    jest.runAllTimers(); 

    wrapper.update(); 

    expect(wrapper.find('#timeoutText').text()).toEqual('there is text!'); 
    }); 
}); 
+0

Sie können stattdessen doSomethingWithAPromise Funktion als Stütze zu AsyncTest Komponente zu übergeben, so dass Sie es in Ihrem Test verspotten: http://stackoverflow.com/questions/38308214/react-enzyme-test-componentdidmount-async-call/40875174 # 40875174 – bodrin

Antwort

1

Es gibt nicht viel um ist, um das Versprechen irgendwie warten, bevor sie beendet den Test zu erfüllen. Es gibt zwei Möglichkeiten, dies über Ihren Code zu tun, den ich sehen kann.

  1. unabhängig testen, dass onClick und Ihre Versprechen Methoden. Überprüfen Sie also, ob onClick die richtige Funktion aufruft, aber spionieren Sie setTextWithPromise aus, lösen Sie einen Klick aus und bestätigen Sie, dass setTextWithPromise aufgerufen wurde. Dann können Sie auch die Komponenteninstanz abrufen und diese Methode aufrufen, die das Versprechen zurückgibt, dass Sie einen Handler anhängen können, und bestätigen, dass sie das Richtige getan hat.

  2. Setzen Sie eine Callback-Prop, die Sie übergeben können, die aufgerufen wird, wenn das Versprechen verrechnet wird.

17

ich dieses Problem erfolgreich gelöst haben, indem sie die folgenden Elemente kombiniert:

  • das Versprechen Mock und es sofort
  • Verwenden Knotens machen lösen setImmediate den Test bis zum nächsten Tick zu verschieben, Dann wird das Versprechen gelöst.
  • Rufen Sie Jests done, um den Test asynchron zu beenden.

In Ihrem Beispiel, die wie folgt aussehen könnte:

global.doSomethingWithAPromise =() => Promise.resolve({}); 

it('displays the promise text after click of the button', (done) => { 
    wrapper.find('#promiseBtn').simulate('click'); 

    setImmediate(() => { 
    expect(wrapper.find('#promiseText').text()).toEqual('there is text!'); 
    done(); 
    }) 
}); 

Enzyms update() ist weder ausreichend noch notwendig, wenn Sie diese Methode verwenden, weil Versprechen nie in der gleichen tick lösen sie erstellt werden - von Design . Für eine sehr detaillierte Erklärung dessen, was hier vor sich geht, siehe this question.

+0

BINGO! 'setImmediate' war das, was ich in meiner Callback-Funktion verwenden musste, die über eine der componentDidUpdate-Lebenszyklus-Methoden meiner Komponente ausgelöst wurde. –

+0

Ich hatte ein ähnliches Problem, aber ich löste es stattdessen mit 'setTimeout (() => {...}, 0)'. Aus irgendeinem Grund ließ 'setImmediate' die Tests so fehlschlagen, dass sogar der' Garntest'-Befehl abrupt beendet wurde. – Ernesto