Javascript 如何在componentDidMount中测试由异步调用创建的组件?
我正在向我的API发出GET请求Javascript 如何在componentDidMount中测试由异步调用创建的组件?,javascript,unit-testing,reactjs,jestjs,enzyme,Javascript,Unit Testing,Reactjs,Jestjs,Enzyme,我正在向我的API发出GET请求http://localhost:3001/api/cards来自组件的componentDidMount函数,因此只有在第一次呈现组件后才发出api请求(如react官方指南所建议) 此API设置数组数据的状态。在render函数中,我调用data.map函数来渲染该数组中的多个组件。我应该如何测试是否渲染了所需数量的组件 我的组成部分: //CardGrid.js import React from 'react'; import { Card, Col,
http://localhost:3001/api/cards
来自组件的componentDidMount函数,因此只有在第一次呈现组件后才发出api请求(如react官方指南所建议)
此API设置数组数据的状态。在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>
);
}
};
除了找不到卡元素外,所有测试都通过了。甚至调用了fetchmock函数。在我尝试查找卡组件之前,它一直失败,直到我放置了一个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);
});
}
//成功了
从“React”导入React;
从“antd”导入{Card};
从“酶”导入{mount};
从“sinon”进口sinon;
从“/CardGrid”导入CardGrid;
它('呈现1个卡片元素',异步()=>{
fetch=jest.fn().mockImplementation(()=>
解析(mockResponse(200,null,“{”id:“1234”}”);
const wrapper=mount();
expect(fetch).toBeCalled();
expect(wrapper.find(CardGrid.length).toEqual(1);
等待setTimeoutP();
expect(包装器.查找(卡片).长度).toEqual(1);
});
函数setTimeoutP(){
返回新承诺(功能(解决、拒绝){
设置超时(()=>{
console.log('111111');
解决();
}, 2000);
});
}
有什么我不理解的概念吗?理想情况下,我应该如何测试这种异步加载组件?如何更好地将它们设计为易于测试?任何帮助都将不胜感激。感谢您对获取结果的承诺以及parseJSON
的承诺。因此,我们需要模拟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);
});
从“/commonfunction”导入{parseJSON}
jest.mock('./commonfunction',()=>{parseJSON:jest.fn()})//这将用一个间谍替换模块中的parseJSON,如果我们稍后返回一个已解析的承诺
它('呈现1个卡片元素',异步()=>{
const result=Promise.resolve(mockResponse(200,null,“{”id:“1234”}”))
parsedResult=Promise.resolve({“id”:“1234”})
mockImplementation(()=>parsedResult)
fetch=jest.fn(()=>result)
const wrapper=mount();
等待结果;
等待解析结果;
expect(fetch).toBeCalled();
expect(wrapper.find(CardGrid.length).toEqual(1);
expect(包装器.查找(卡片).长度).toEqual(1);
});
如果没有setTimeoutP,它就无法工作。我甚至更新了()最后一行中的包装器我想如果你也添加一个模拟的parseJSON
,那么你的答案就行了。从OP:await-parseJSON(await-fetch(…
argh,你是对的,这会让测试很难进行,会更新答案你真的需要await-parseJSON
?你没有包括这个源代码,但我猜它不是异步的。MDN文档说“如果该值不是承诺,它会将该值转换为已解析的承诺,并等待它。”因此,它似乎应该可以工作,但可能与此方法和测试框架有关?抱歉,我没有包含parseJSON的源代码。它基本上调用.json()
在fetch API调用返回的响应对象上。我需要等待它,因为它返回一个承诺。在这种情况下,我认为解决方案是wait
两个承诺(对于fetch
和parseJSON
)。使用wait(wait result).json()
,我得到类型错误:已读
。这是因为正文已使用.json()读取,无法再次读取。您在这里有两个承诺,因此都需要解决。您正在模拟获取
以返回已解决的承诺,这样可能就可以了(以及下面Andreas的等待),但似乎您还需要模拟parseJSON
方法,例如parseJSONPromise=Promise.resolve({id:“1234”});
parseJSON=jest.fn().mock实现(()=>parseJSONPromise);
和等待parseJSONPromise;
和expect(parseJSON.).toBeCalled();
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);
});