2017-05-05 3 views
0

私のテストは、この(this articleをオフに基づいて)のように見えるテスト:変数のスコープの問題反応成分の

// MyComponent.test.js 


import { mount } from 'enzyme'; 
import MyComponent from './MyComponent.jsx'; 

describe('<MyComponent />',() => { 
    let props; 
    let state; 
    let mountedComponent; 

    // The problematic part to be changed 
    const component =() => { 
    if (!mountedComponent) { 
     // This enzyme mount is actually much more complex, 
     // as I'm wrapping all sorts of contexts and globals around it 
     // which is why I want to take this function outside, 
     // and use it as boilerplate in every test 
     mountedComponent = mount(<MyComponent {...props} />); 
    } 
    return mountedComponent; 
    }; 

    beforeEach(() => { 
    props = {}; 
    state = {}; 
    mountedComponent = undefined; 
    }); 

    it('Works',() => { 
    state = { val: true }; 
    component().setState(state, 
    () => expect(component().state('val')).to.equal(true), 
    ); 
    }); 
}); 

これはうまく機能で複数回呼び出された場合、component()機能が適切同じmountedComponentを返します同じitは、mountedComponentの現在の値が呼び出しの間保持され、beforeEachテストのみをリセットします。

今、私は別のファイルにこのテストの外component()機能を抽出した場合:理由はコンポーネント()、そして、このこのテストが失敗

// MyComponent.test.js 

// Cleaner problematic part 
const component =() => getMountedComponent(MyComponent, props, mountedComponent); 

// getMountedComponent.js 

const getMountedComponent = (AnyComponent, props, mountedComponent) => { 

    if (!mountedComponent) { 
    // Appears not to properly reassign mountedComponent 
    mountedComponent = mount(<AnyComponent {...props} />); 
    } 
    return mountedComponent; 
}; 

そして、これとcomponent()機能を置き換えますstate = nullで2回目に新しいコンポーネントを返します。

これは範囲の問題として表示されますが、私はこれを回避することはできません。

答えて

1

問題は、あなたのgetMountedComponent関数がmountedComponent引数を受け入れることである - それはdescribleブロックで定義された同じ名前の変数が上書きされますので、実際には、この関数内で新しいmountedComponent変数を作成します。したがって、getMountedComponentを呼び出すたびに、新しいローカル変数が作成され、describeスコープで定義されたmountedComponent変数には決して値が割り当てられません。あなたは機能自体にコンポーネントをキャッシュすることができ、それを修正する(関数はJSでファーストクラスのオブジェクトである)外部変数を使用してのinsetadするには:

delete getMountedComponent.mountedComponent; 
+0

私はdescribe関数から関数を抜き出しているのは、実際に説明したものよりも少し複雑だからです。つまり、 'getMountedComponent'を別のファイルに保存したいということです。 –

+0

更新された回答を確認してください。 –

+0

美しい!それは働いた:) 私はすぐにこれを使用して関数を書いた: 'getMountedComponent.reset =()=> {delete getMountedComponent.mountedComponent; } ' –

0

Javascript by reference vs. by value

Javascriptが値渡し常にあるが、変数(アレイを含む) オブジェクトを参照する場合、「値」は、オブジェクトへの参照です。あなたが外getMountedComponent機能を撮影した

は、あなたのdescribe機能でmountedComponent変数を設定されなくなり、それはmountedComponent毎回の新しいコピーが作成されますので、したがって、それundefinedを残します。

const getMountedComponent = (MyComponent, props, mountedComponent) => { 

    if (!mountedComponent) { 
    // You are not changing the "mountedComponent" defined in your "describe" here 
    // because "mountedComponent" is pass by value 
    mountedComponent = mount(<MyComponent {...props} />); 
    } 
    return mountedComponent; 
}; 

describe('<MyComponent />',() => { 
    let props; 
    let state; 
    let mountedComponent; // This stays undefined 
    // ... 
} 
+0

理由私は:

function getMountedComponent(MyComponent, props) { if (!getMountedComponent.mountedComponent) { // Appears not to properly reassign mountedComponent getMountedComponent.mountedComponent = mount(<MyComponent {...props} />); } return getMountedComponent.mountedComponent; }; 

機能のキャッシュをクリアするには、単にこれを使用します'mountedComponent'を使用すると' beforeEach'でリセットすることができます。なぜなら私は実際にここで多くのテストを実行しているからです。同意すると、1回のテストでは役に立たない。 mountedComponentはオブジェクトであるReactコンポーネントを参照して終了するので、関数を再度呼び出すと参照渡しが予想されましたが、それは間違っていますか? –

+0

@FlorianBienefelt私は、私は答えのその部分を削除します。最初は、あなたの変数はオブジェクトではないので、未定義のままです。オブジェクトであっても、プロパティを変更することしかできないため、新しいコンポーネントとして割り当てることはできません。 –

+0

@FlorianBienefelt "最初はあなたの変数はオブジェクトではないので無視されます。"オブジェクトであっても、参照の値を関数に渡しています。したがって、 'mountedComponent = foo'を実行すると、その参照の内部の内容は変更されませんが、参照の値が置き換えられます。説明するのはちょっと難しいです...私はちょっとした感覚を込めて願っています。 –