[英]React/Jest - mock fetch and wait for componentDidMount to re-render
我在玩弄反應和開玩笑,並且遇到了以下情況,我根本無法弄清楚該怎么做。
Todo.js
import React from 'react';
import PropTypes from 'prop-types';
import TodoItem from './TodoItem';
import {fetchTodoItems} from '../helpers/todo';
class Todo extends React.Component {
constructor(props) {
super(props);
this.state = {
todos: [],
error: false,
loading: true
};
this.updateMockState = this.updateMockState.bind(this);
}
updateMockState() {
this.setState({
todos: [{ id: 8101, text: "Cook fresh food", status: "completed" }],
loading: false
});
}
componentDidMount() {
// TODO: add error handling
fetchTodoItems().then(response => {
this.setState({
todos: response.data,
loading: false
})
}, error => {});
}
render() {
let content;
// TODO: add error handling
if (this.state.loading) {
return (
<div>
<div>
<button id="update-data" onClick={this.updateMockState}>Update State</button>
</div>
<p>Todos are being fetched...</p>
</div>
);
}
return (
content ||
<div>
<div>
<button id="update-data" onClick={this.updateMockState}>Update State</button>
</div>
<p><b>{this.state.todos.length}</b> todos fetched so far</p>
{this.state.todos.map(
(todo) => <TodoItem key={todo.id} id={todo.id} status={todo.status} text={todo.text} />)}
</div>
);
}
}
Todo.proptypes = {
timeout: PropTypes.number
};
export default Todo;
Todo.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import renderer from 'react-test-renderer';
import { mount, shallow, render } from 'enzyme';
import Todo from '../components/Todo';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
// TODO: remove sinon from NPM packages
Enzyme.configure({ adapter: new Adapter() });
const todos = { data: [{
"id": 4404,
"status": "active",
"text": "Shopping List"
}, {
"id": 7162,
"status": "completed",
"text": "Time Registration"
}]};
describe('Todo', () => {
it('calls mock API', async () => {
fetch = jest.fn().mockReturnValue(Promise.resolve(todos));
const spy = jest.spyOn(Todo.prototype, 'componentDidMount');
var component = mount(<Todo timeout={2000} />);
component.instance().componentDidMount();
expect(spy).toHaveBeenCalled();
expect(toJson(component)).toMatchSnapshot();
});
});
如您所見,Todo組件是一個簡單的組件,在componentDidMount內部調用一個API,獲取響應並顯示。 在等待api調用時,會顯示一些信息...還有一個用於虛擬狀態更新的按鈕,但這暫時並不重要。
fetchTodoItems(文件為todo.js)
export const fetchTodoItems = () => {
return fetch("data/todo.json").then(res => res.json());
};
我的問題如下:
第一,我應該看不到待辦事項,但是第二,我應該看到待辦事項。
這是TodoItem
import React from 'react';
import PropTypes from 'prop-types';
const TodoItem = (props) => {
let htmlClass = [];
if (props.status === 'completed') {
htmlClass.push("todo-completed");
}
return (
<ul>
<p className={htmlClass.join(" ")}>
<small>[#{props.id}]</small> {props.text} <i>({props.status})</i>
</p>
</ul>
);
}
TodoItem.proptypes = {
id: PropTypes.number.required,
text: PropTypes.string.required,
status: PropTypes.string.required
};
export default TodoItem;
到目前為止,我已經嘗試了以下方法:
使用Expect(component.toJSON())。toMatchSnapshot()進行純快照測試-API調用后不顯示結果
jest.spyON ...該方法被調用,但是之后toMatchSnapshot仍然顯示第一個沒有數據的快照
返回promise()。然后(...仍然沒有結果
有什么幫助嗎?
編輯:
如果我從componentDidMount中刪除API調用並僅使用setState,那么快照測試將顯示待辦事項(沒有第一種情況,應該說待辦事項正在獲取... )為什么? 不應該一樣嗎?
如果只有承諾是根本原因,我如何等待所有承諾完成?
一種方法是等待隊列中的最后一個事件(承諾)得到解決,然后進行組件實例更新?
const allOver = () => new Promise((resolve) => setImmediate(resolve));
describe('Todo', () => {
it('calls mock API', async () => {
fetch = jest.fn().mockReturnValue(Promise.resolve(todos));
var component = mount(<Todo timeout={2000} />);
await allOver();
component.update();
expect(toJson(component)).toMatchSnapshot();
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.