web-dev-qa-db-ja.com

componentDidMountで使用されるsetState値は、酵素テストに反映されません

Component.js

_import React from 'react'
import request from 'superagent'

export default React.createClass({
    getInitialState() {
        return {cats: []}
    },

    componentDidMount() {
        request('/api', (err, res) => {
            if (err) return;
            this.setState({
                cats: res.body.results
            })
        })
    },

    render() {
        let cats = this.state.cats
        let catsList = (
            <ul>
                {cats.map((c) => <li key={c.id}>cat</li>)}
            </ul>
        )
        return (
            <div>
                {cats.length ? catsList : null}
            </div>
        )
    }
})
_

Component.test.js

_jest.unmock('../app.js')
jest.unmock('superagent')

import React from 'react'
import {mount} from 'enzyme'
import nock from 'nock'
import App from '../app.js'

describe('App', () => {
    let ajaxFn
    beforeEach(() => {
        ajaxFn = nock('http://localhost')
            .get('/api')
            .reply(200, {
                results: [{id: 1}, {id: 2}, {id: 3}]
            })
    })

    it('renders correct number of cats', () => {
        let wrapper = mount(<App />)
        expect(wrapper.state('cats').length).toBe(3)
    })
})
_

テストに合格しません。 wrapper.state('cats').lengthは常に_0_です。

setStateが状態をすぐに更新することを保証しないことを理解していますが、コンポーネントに「cats」を記録すると、更新されていることがわかります。

酵素が認識していないコンテキストでコンポーネントに状態を設定することになった場合、レンダリングツリーの更新バージョンを取得するには、ラッパーで.update()を手動で呼び出す必要があります。

it('renders correct number of cats', () => {
    let wrapper = mount(<App />)
    expect(wrapper.update().state('cats').length).toBe(3)
})
9

同様の問題があり、itコールバックからpromiseを返し、promiseのthenメソッドで期待値を確認する必要がありました。

あなたの場合(ajaxFnが約束だったと仮定するか、それを1つに変えることができると仮定して)、これはおおよそ次のようになると思います。

it('renders correct number of cats', () => {
    let wrapper = mount(<App />) 
    return ajaxFn.then(() => {
        expect(wrapper.state('cats').length).toBe(3);
    }
})
2
Simon Hardman

使用しているすべてのライブラリに精通しているわけではありませんが、コードが非同期で実行されているため、状態を更新する前にテストが終了しています。テストにasync/awaitを追加することで、この問題を解決することができました。

it('renders correct number of cats', async () => {
    let wrapper = await mount(<App />)
    expect(wrapper.state('cats').length).toBe(3)
})
0
David