问题 componentDidMount setState不反映在酶测试中


零件:

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>
                hello world
                {cats.length ? catsList : null}
            </div>
        )
    }
})

测试:

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('says hello world', () => {
        let wrapper = mount(<App/>)
        expect(wrapper.text()).toContain('hello worl')
    })

    it('makes ajax request', () => {
        let wrapper = mount(<App/>)
        expect(ajaxFn.isDone()).toBe(true)
    })

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

前两个测试通过,但最后一个没有,即wrapper.state('cats')。length == 0

我知道setState不保证立即更新状态, 但是,如果我在组件中记录“猫”,我可以看到它更新。


11357
2018-03-10 21:30


起源



答案:


如果您最终在某些酶不知道的情况下在组件中设置状态,则必须手动调用 .update() 在包装器上,以便获取渲染树的更新版本。

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

8
2018-03-11 01:12



试过,但它不起作用。 - Babistalikesflyingonrails
这对我有用,我想知道为什么它不会因为setState而更新,包装器是否遍历渲染树的副本或其他东西? - riscarrott
Leland,在执行wrapper.update()之前,您是否需要首先确保状态更新已经发生? - bodrin
或者我们依赖于nock-ed ajaxFn是同步的事实 - bodrin
我在这里发了一个答案 stackoverflow.com/questions/38308214/... ..它可能类似于Simon Hardman的回答 - bodrin


答案:


如果您最终在某些酶不知道的情况下在组件中设置状态,则必须手动调用 .update() 在包装器上,以便获取渲染树的更新版本。

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

8
2018-03-11 01:12



试过,但它不起作用。 - Babistalikesflyingonrails
这对我有用,我想知道为什么它不会因为setState而更新,包装器是否遍历渲染树的副本或其他东西? - riscarrott
Leland,在执行wrapper.update()之前,您是否需要首先确保状态更新已经发生? - bodrin
或者我们依赖于nock-ed ajaxFn是同步的事实 - bodrin
我在这里发了一个答案 stackoverflow.com/questions/38308214/... ..它可能类似于Simon Hardman的回答 - bodrin


我有一个类似的问题,有必要从...返回一个承诺 it 回调并检查期望 then 承诺的方法。

在你的情况下(假设ajaxFn是一个承诺,或者你可以把它变成一个)我认为这将是大约:

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

2
2017-11-03 00:18





我不熟悉您正在使用的所有库,但由于您的代码是异步执行的,因此测试在状态可以更新之前完成。我能够通过在测试中添加async / await来解决这个问题:

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

0
2018-06-17 19:12