簡體   English   中英

React / Jest-模擬獲取並等待componentDidMount重新渲染

[英]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());
};

我的問題如下:

  • 我想對Todo組件進行快照測試,如下所示:
    1. 首先,在渲染之前(在API調用之前)
    2. 在API調用成功完成之后

第一,我應該看不到待辦事項,但是第二,我應該看到待辦事項。

這是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM