我正在玩 react 和 jest,我遇到了以下情况,我根本不知道该怎么做。
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());
};
我的问题如下:
- 我想对 Todo 组件进行快照测试,如下所示:
- 首先,在渲染时(在 API 调用之前)
- API 调用成功完成后立即
第 1 天我应该看不到任何待办事项,但第 2 天我应该看到我的待办事项。
这是 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 仍然显示没有数据的第一个快照
return promise().then(...还是没有结果
有什么帮助吗?
编辑:
如果我从 componentDidMount 中删除 API 调用并仅使用 setState,则快照测试会显示 todos 项(没有第一种情况应该说 todos are being fetched...)为什么?不应该一样吗?
如果只有 promise 才是根本原因,我怎么能等到所有 promise 完成呢?
最佳答案
一种方法是等待队列中的最后一个事件(promise)得到解决,然后进行组件实例更新?
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();
});
});
关于javascript - React/Jest - 模拟获取并等待 componentDidMount 重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48962822/