2016-12-22 6 views
4

In meinen Tests möchte ich meinen Hauptthread blockieren, bis eine meiner Komponenten die Lebenszyklusmethoden durchläuft, und zwar durch componentDidUpdate(), nachdem ich ein Ereignis ausgelöst habe, das dazu führt, dass untergeordnete Komponenten hinzugefügt werden zu sich selbst. Wie kann ich das tun?Warten, bis eine React-Komponente die Aktualisierung abgeschlossen hat

Etwas wie folgt aus:

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice',() => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    // This next line has some side effects that cause <Component /> to add 
    // some children components to itself... 
    button.simulate('click', mockEvent); 

    // ... so I want to wait for those children to completely go through 
    // their lifecycle methods ... 
    wrapper.instance().askReactToBlockUntilTheComponentIsFinishedUpdating(); 

    // ... so that I can be sure React is in the state I want it to be in 
    // when I further manipulate the <Component /> 
    button.simulate('click', mockEvent); 

    expect(whatIWant()).to.be.true; 
    }); 
}); 

(Ich möchte, dies zu tun, weil, gerade jetzt, ich diese Warnung erhalten:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. 

Ich glaube, ich bin immer es, weil meine Tests meine verursachen Um den internen Zustand schneller zu ändern, als Reacts interne Multithreading-Magie mithalten kann, hat React die neuen Kindkomponenten instanziiert, bis ich das erste Mal button.simulate('click') ausgeführt habe, aber noch nicht fertig für Reagieren, um Aktualisierung zu beenden meine Komponente und ihre Kinder ing ist der beste Weg, um dieses Problem zu lösen)

+1

Was bedeutet der Click-Handler tun? Alle Statusänderungen sollten synchron sein, es sei denn, Sie haben spezielle Timer-/Async-Funktionen. – Jacob

+1

DOM-Updates sind auch synchron, es sei denn, Sie tun etwas seltsam oder verwenden eine exotische Variante von React. Ich wäre nicht überrascht, wenn Ihre 'setState'-Warnung darauf beruht, dass Ihre Komponente selbst vor dem Einhängen einen' setState' ausführt. – Jacob

+1

@ Jacob Ich benutze eine Drittanbieter-Bibliothek, [React Widgets] (https://jquense.github.io/react-widgets/docs/). Meine '' hat ein React Widgets 'DateTimePicker' als eines seiner Kinder, und die Warnung scheint aus dem' DateTimePicker' ausgegeben zu werden. So bin ich mir leider sicher, was mein Ereignis verändert und ich kann nicht einfach versuchen, in die Komponente zu schauen, um sicherzustellen, dass sie sich nicht benimmt. – Kevin

Antwort

1

Versuchen Sie expect() Blöcke in einem setImmediate() Block Verpackung:.

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice', (done) => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    button.simulate('click', mockEvent); 
    button.simulate('click', mockEvent); 

    setImmediate(() => { 
     expect(whatIWant()).to.be.true; 
     done(); 
    }); 
    }); 
}); 

Hier ist was los: Asynchronität, Knoten und den meisten Browsern umgehen habe eine Ereigniswarteschlange hinter den Kulissen. Wenn etwas wie ein Promise- oder ein IO-Ereignis asynchron ausgeführt werden muss, fügt die JS-Umgebung es am Ende der Warteschlange hinzu. Wenn dann ein synchroner Codeabschnitt ausgeführt wird, überprüft die Umgebung die Warteschlange, wählt aus, was sich an der Spitze der Warteschlange befindet, und führt sie aus.

setImmediate() fügt der Rückseite der Warteschlange eine Funktion hinzu. Sobald alles, was gerade in der Warteschlange ist, beendet ist, wird ausgeführt, was in der Funktion an setImmediate() übergeben wird. Also, was auch immer Reaction asynchron macht, Ihr expect() s innerhalb einer setImmediate() Wrack wird Ihren Test warten, bis React mit was auch immer asynchrone Arbeit hinter den Kulissen abgeschlossen ist.

Hier ist eine große Frage, mit mehr Informationen über setImmediate(): setImmediate vs. nextTick

Hier ist die Dokumentation für setImmediate() in Knoten: https://nodejs.org/api/timers.html#timers_setimmediate_callback_args

+0

Ich habe diesen 'setImmediate()' Trick in einigen meiner Tests versucht, aber nicht in der spezifischen Situation, die in meiner Frage beschrieben wird. Es gibt also Drachen, und diese Lösung funktioniert möglicherweise nicht. – Kevin

+0

Wenn eine Assertion ('expect') im Inneren' setImmediate() 'fehlschlägt, endet der Test mit einem Fehler, statt es als' Fail' Markierung und fortzusetzen. Irgendwelche Arbeiten herum? – vleong

+0

@VLeong Werden Sie Ihre Tests als asynchrone Schreiben von Tests durch die 'done' Funktion in Ihrem' Es 'Blöcke mit? Siehe https://mochajs.org/#asynchronous-code – Kevin

Verwandte Themen