javascript - 如何测试在 componentDidMount 中异步调用创建的组件?

标签 javascript unit-testing reactjs jestjs enzyme

我正在从组件的 componentDidMount 函数向我的 API http://localhost:3001/api/cards 发出 GET 请求,以便仅在组件之后发出 api 请求第一次渲染(按照react官方指南的建议)。

此 API 设置数组 data 的状态。在 render 函数中,我调用 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 个元素来尝试这个。然后我使用 enzyme 的完整 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);
});

除了找不到 Card 元素外,所有测试都通过了。甚至 fetch 模拟函数也会被调用。它失败了,直到我在尝试查找 Card 组件之前放置了一个 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);
    });
}

是否有任何我未能理解的概念?我应该如何理想地测试这种异步加载的组件?我怎样才能更好地设计它们以便于测试?任何帮助将不胜感激。谢谢

最佳答案

你必须 wait对于您的获取结果的已解决 promise 以及来自 parseJSON 的 promise 。因此,我们需要模拟 parseJSON 并让它也返回一个已解决的 promise 。请注意,路径需要与测试文件相关。

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

关于javascript - 如何测试在 componentDidMount 中异步调用创建的组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41520387/

相关文章:

javascript - 是否可以动态更改 manifest.json 文件

javascript - 所有选项卡均可点击,而不仅仅是文本

javascript - 在不转换 `height` 属性的情况下折叠展开动画?

javascript - 如何将 HTML 页面添加到 React 应用程序

javascript - 如何去除页面的白边并使其 100% 宽

javascript - nodejs 我不知道为什么帖子没有链接

unit-testing - Gameboy模拟器测试策略?

AngularJS + karma : reuse a mock service when unit testing directives or controllers

c# - 如何在 MSTest 中忽略

node.js - 当 props.match.params.id 返回未定义但 id 在 url 上可见时,如何获取 url 的 id 参数?