2016-04-22 20 views
7

Podsumowanie:jsdom: dispatchEvent/addEventListener nie wydają się działać

Ja próbuje przetestować React składnik, który słucha rodzimych zdarzeń DOM w componentWillMount.

Zauważyłem, że jsdom (@8.4.0) nie działa zgodnie z oczekiwaniami, jeśli chodzi o wysyłanie zdarzeń i dodawanie detektorów zdarzeń.

Najprostszym kawałek kodu można wyodrębnić:

window.addEventListener('click',() => { 
    throw new Error("success") 
}) 

const event = new Event('click') 
document.dispatchEvent(event) 

throw new Error('failure') 

To rzuca "niepowodzenie".


Kontekst:

Na ryzyko powyższego bycia XY problem, chcę, aby zapewnić więcej kontekstu.

Oto wyodrębniona/uproszczona wersja komponentu, który próbuję przetestować. You can see it working on Webpackbin.

import React from 'react' 

export default class Example extends React.Component { 
    constructor() { 
    super() 
    this._onDocumentClick = this._onDocumentClick.bind(this) 
    } 

    componentWillMount() { 
    this.setState({ clicked: false }) 
    window.addEventListener('click', this._onDocumentClick) 
    } 

    _onDocumentClick() { 
    const clicked = this.state.clicked || false 
    this.setState({ clicked: !clicked }) 
    } 


    render() { 
    return <p>{JSON.stringify(this.state.clicked)}</p> 
    } 
} 

Oto test, który próbuję napisać.

import React from 'react' 
import ReactDOM from 'react-dom' 
import { mount } from 'enzyme' 

import Example from '../src/example' 

describe('test',() => { 
    it('test',() => { 
    const wrapper = mount(<Example />) 

    const event = new Event('click') 
    document.dispatchEvent(event) 

    // at this point, I expect the component to re-render, 
    // with updated state. 

    expect(wrapper.text()).to.match(/true/) 
    }) 
}) 

Tylko dla kompletności, tutaj jest mój test_helper.js który inicjuje jsdom:

import { jsdom } from 'jsdom' 
import chai from 'chai' 

const doc = jsdom('<!doctype html><html><body></body></html>') 
const win = doc.defaultView 

global.document = doc 
global.window = win 

Object.keys(window).forEach((key) => { 
    if (!(key in global)) { 
    global[key] = window[key] 
    } 
}) 

Powielanie przypadek:

Mam repro przypadek tutaj: https://github.com/jbinto/repro-jsdom-events-not-firing

git clone https://github.com/jbinto/repro-jsdom-events-not-firing.git cd repro-jsdom-events-not-firing npm install npm test

Odpowiedz

3

Problemem tutaj było to, że jsdom dostarczonego document nie jest faktycznie przyzwyczaić za pomocą testów enzymatycznych.

Enzym wykorzystuje renderIntoDocument z React.TestUtils.

https://github.com/facebook/react/blob/510155e027d56ce3cf5c890c9939d894528cf007/src/test/ReactTestUtils.js#L85

{ 
    renderIntoDocument: function(instance) { 
    var div = document.createElement('div'); 
    // None of our tests actually require attaching the container to the 
    // DOM, and doing so creates a mess that we rely on test isolation to 
    // clean up, so we're going to stop honoring the name of this method 
    // (and probably rename it eventually) if no problems arise. 
    // document.documentElement.appendChild(div); 
    return ReactDOM.render(instance, div); 
    }, 
// ... 
} 

oznacza to, że wszystkie nasze testy enzymatyczne nie są wykonywane przed jsdom dostarczonego document, ale zamiast do węzła div oderwane od jakiegokolwiek dokumentu.

Enzym tylko używa dostarczonego przez jsdom document dla metod statycznych, np. getElementById itp. Nie jest używany do przechowywania/obsługi elementów DOM.

Aby wykonać tego rodzaju testy, odwołałem się do wywoływania ReactDOM.render i potwierdzania danych wyjściowych przy użyciu metod DOM.

6

Wysyłasz zdarzenie do document, więc window go nie zobaczy, ponieważ domyślnie nie będzie się nadawać. Musisz utworzyć wydarzenie z bubbles ustawionym na true. Przykład:

var jsdom = require("jsdom"); 

var document = jsdom.jsdom(""); 
var window = document.defaultView; 

window.addEventListener('click', function (ev) { 
    console.log('window click', ev.target.constructor.name, 
       ev.currentTarget.constructor.name); 
}); 

document.addEventListener('click', function (ev) { 
    console.log('document click', ev.target.constructor.name, 
       ev.currentTarget.constructor.name); 
}); 

console.log("not bubbling"); 

var event = new window.Event("click"); 
document.dispatchEvent(event); 

console.log("bubbling"); 

event = new window.Event("click", {bubbles: true}); 
document.dispatchEvent(event); 
+1

'nowy window.Event ("kliknięcie");' ermagerd. 'doc.createEvent ('MouseEvents'). initEvent ('click', true, true)' zwraca undefined w jsdom ... 1.5hrs aby znaleźć odpowiedź O.o – Larry

0

Kod: https://github.com/LVCarnevalli/create-react-app/blob/master/src/components/datepicker

Link: ReactTestUtils.Simulate can't trigger event bind by addEventListener?

Składnik:

componentDidMount() { 
ReactDOM.findDOMNode(this.datePicker.refs.input).addEventListener("change", (event) => { 
    const value = event.target.value; 
    this.handleChange(Moment(value).toISOString(), value); 
    }); 
} 

Test:

it('change empty value date picker',() => { 
    const app = ReactTestUtils.renderIntoDocument(<Datepicker />); 
    const datePicker = ReactDOM.findDOMNode(app.datePicker.refs.input); 
    const value = ""; 

    const event = new Event("change"); 
    datePicker.value = value; 
    datePicker.dispatchEvent(event); 

    expect(app.state.formattedValue).toEqual(value); 
}); 
Powiązane problemy