2017-01-07 11 views
4

APIのhttp://localhost:3001/api/cardsからコンポーネントのcomponentDidMount関数からGET要求を出しています。これにより、コンポーネントが初めてレンダリングされた後にのみapiリクエストが行われるようになりました。componentDidMountで非同期呼び出しによって作成されたコンポーネントをテストするにはどうすればよいですか?

このAPIは、配列dataの状態を設定します。レンダー機能では、data.map関数を呼び出して、この配列から複数のコンポーネントをレンダリングします。必要な数のコンポーネントがレンダリングされたかどうかをテストするにはどうすればよいですか?

マイコンポーネント:

//CardGrid.js 

import React from 'react'; 
import { Card, Col, Row } from 'antd'; 
import 'antd/dist/antd.css'; 

import { parseJSON } from './commonfunction'; 
import './CardGrid.css'; 

export default class extends React.Component { 
    constructor() 
    { 
     super(); 
     this.state = { 
      data: {}, 
     }; 
    } 

    fetchData = async() => { 
     try 
     { 
      const data = await parseJSON(await fetch('http://localhost:3001/api/cards')); 
      console.log('data'); 
      console.log(data); 
      this.setState({ data }); 
     } 
     catch (e) 
     { 
      console.log('error is: '); 
      console.log(e); 
     } 
    } 

    componentDidMount() { 
     this.fetchData(); 
    } 

    render() { 
     return (
      <div style={{ background: '#ECECEC', padding: '30px' }}> 
       <Row gutter={16}> 
        {Object.keys(this.state.data).map((title) => { 
         return (<Col span="6" key={title}> 
          <Card title={title} bodyStyle={{ 
           'fontSize': '6em', 
          }}>{this.state.data[title]}</Card> 
         </Col>); 
        })} 
       </Row> 
      </div> 
     ); 
    } 
}; 

今、私は私のAPIで指定されたレンダリングされているなど、多くのCardコンポーネントがあるかどうかを確認します。

最初にfetch関数を嘲って1要素を返すことでこれを試みました。次に、酵素のFull DOMレンダリングと上記の成分のmountを使用して、それに1つの要素が含まれると考えます。

テストケース:

// It fails 
import React from 'react'; 
import { Card } from 'antd'; 
import { mount } from 'enzyme'; 
import CardGrid from './CardGrid'; 

it('renders 1 Card element',() => { 
    fetch = jest.fn().mockImplementation(() => 
     Promise.resolve(mockResponse(200, null, '{"id":"1234"}'))); 
    const wrapper = mount(<CardGrid />); 
    expect(fetch).toBeCalled(); 
    expect(wrapper.find(CardGrid).length).toEqual(1); 
    expect(wrapper.find(Card).length).toEqual(1); 
}); 

すべてのテストは、それがカードの要素を見つけることができないことを除いて渡しています。 fetch mock関数も呼び出されます。私はカードコンポーネントを見つける前にsetTimeout関数を置くまで失敗します。

//It succeeds 
import React from 'react'; 
import { Card } from 'antd'; 
import { mount } from 'enzyme'; 
import sinon from 'sinon'; 
import CardGrid from './CardGrid'; 
it('renders 1 Card elements', async() => { 
    fetch = jest.fn().mockImplementation(() => 
     Promise.resolve(mockResponse(200, null, '{"id":"1234"}'))); 
    const wrapper = mount(<CardGrid />); 
    expect(fetch).toBeCalled(); 
    expect(wrapper.find(CardGrid).length).toEqual(1); 
    await setTimeoutP(); 
    expect(wrapper.find(Card).length).toEqual(1); 

}); 

function setTimeoutP() { 
    return new Promise(function (resolve, reject) { 
     setTimeout(() => { 
      console.log('111111111'); 
      resolve(); 
     }, 2000); 
    }); 
} 

私には理解できない概念はありますか?このような非同期ロードコンポーネントをテストするにはどうすればよいですか?簡単にテスト可能にするにはどうすればよいでしょうか?どんな助けでも大歓迎です。ありがとう

+0

本当に 'await parseJSON'が必要ですか?そのソースは含まれていませんが、非同期ではないと思います。 MDNの文書は、「価値が約束でなければ、価値を約束したものに変換し、それを待つ」と述べている。だから、それはうまくいくはずだが、このアプローチとテストフレームワークの何かがあるだろうか? – pherris

+0

申し訳ありませんがparseJSONのソースは含まれていません。基本的には、fetch API呼び出しによって返されたResponseオブジェクトに対して '.json()'を呼び出します。私はそれが約束を返すので、それを待つ必要があります。 https://developer.mozilla.org/en-US/docs/Web/API/Body/json – Ayush

+0

その場合、解決策は両方のことを約束することです( 'fetch'と' parseJSON'のために) )。 – pherris

答えて

5

あなたの取って来た結果の約束された約束とparseJSONからの約束のためには、waitが必要です。そのためにはparseJSONを模倣し、解決済みの約束を返すようにする必要があります。パスはテストファイルに関連している必要があることに注意してください。

import {parseJSON} from './commonfunction' 

jest.mock('./commonfunction',() => {parseJSON: jest.fn()}) //this will replace parseJSON in the module by a spy were we can later on return a resolved promise with 


it('renders 1 Card elements', async() => { 
    const result = Promise.resolve(mockResponse(200, null, '{"id":"1234"}')) 
    parsedResult = Promise.resolve({"id":"1234"}) 
    parseJSON.mockImplementation(()=>parsedResult) 
    fetch = jest.fn(() => result) 
    const wrapper = mount(<CardGrid />); 
    await result; 
    await parsedResult; 

    expect(fetch).toBeCalled(); 
    expect(wrapper.find(CardGrid).length).toEqual(1); 
    expect(wrapper.find(Card).length).toEqual(1); 
}); 
+0

setTimeoutPなしで動作しませんでした。私は最後の行のラッパーをupdate()しています – Ayush

+0

'parseJSON'を擬似的に追加すると、あなたの答えがうまくいくと思います。OPから: 'parseJSONを待つ(フェッチを待つ(...' < - 2つの約束が解決されていることに注意してください) – pherris

+1

ああ、そうです、これはテストを本当に難しくし、答えを更新します –

関連する問題