2016-04-22 4 views
7

概要を動作するようには思えません。私はそのcomponentWillMountでネイティブのDOMイベントをリスンするコンポーネントに反応テストしようとしていますjsdom:は、dispatchEvent /のaddEventListenerは

イベントのディスパッチとイベントリスナーの追加に関してjsdom(@8.4.0)が期待どおりに機能しないことが判明しました。

私は抽出することができ、コードの最も簡単なビット:

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

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

throw new Error('failure') 

これは、 "失敗" をスローします。


コンテキスト:上記はXY problemされる危険が

、私はより多くのコンテキストを提供します。

私がテストしようとしているコンポーネントの抽出/簡略化されたバージョンです。 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> 
    } 
} 

ここで私が書いてみようとしているテストです。ただ、完全を期すために、ここでjsdomを初期化し、私のtest_helper.js

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/) 
    }) 
}) 

されています:

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

再生の場合:https://github.com/jbinto/repro-jsdom-events-not-firing

私はここにREPROケースを持っています git clone https://github.com/jbinto/repro-jsdom-events-not-firing.git cd repro-jsdom-events-not-firing npm install npm test

答えて

3

問題はここにjsdom-提供documentが実際に酵素テストで慣れていないということでした。

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); 
    }, 
// ... 
} 

これが私たちの酵素のテストの全てがjsdom-提供documentに対して実行、代わりに任意の文書から切り離さするdivノードにされていないことを意味します。

酵素は、静的方法にjsdom-provided documentのみを使用します。 getElementByIdなど。これはDOM要素の保存/操作には使用されません。

これらのテストを行うために、私は実際にReactDOM.renderを呼び出し、DOMメソッドを使用して出力をアサートしました。

6

あなたはdocumentにイベントをディスパッチしますので、windowはデフォルトではバブルアップしないため、表示されません。 bubblestrueに設定してイベントを作成する必要があります。例:

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

'新しいwindow.Event( "クリック");' ermagerd。 'doc.createEvent( 'MouseEvents')。initEvent( 'click'、true、true)' jsdom ... 1.5時間でundefinedを返します。 – Larry

0

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

リンク:ReactTestUtils.Simulate can't trigger event bind by addEventListener?

コンポーネント:

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

テスト:

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); 
}); 
関連する問題