使用开玩笑的假定时器测试redux-saga debounce

时间:2018-03-12 10:13:56

标签: javascript reactjs jest redux-saga

我有一个传奇,它会侦听模型更新并向网络发起一次保存,并以1秒的速度去除:

export default function* graphModelUpdate() {
    const modelChangeDebounceTime = 1000;
    let task;

    while (true) {
        const action = yield take(IllustrationsActions.GRAPH_MODEL_CHANGED);
        if (task) {
            yield cancel(task);
        }
        task = yield fork(function* (payload) {
            yield call(delay, modelChangeDebounceTime);
            yield put(IllustrationsActions.apiUpdateGraph(payload));
        }, action.payload);
    }
}

然后我按照redux-saga docsjest docs regarding timers编写了这个测试,测试saga的效果而不是它的实现:

jest.useFakeTimers();

describe('graphModelUpdate saga', () => {
    let dispatched;
    let mockState;
    let subscribers = [];
    const emitAction = (action) => {
        subscribers.forEach(cb => cb(action));
    };
    const options = {
        subscribe: callback => {
            subscribers.push(callback);
            return () => subscribers = subscribers.filter(cb => cb !== callback);
        },
        dispatch: (action) => dispatched.push(action),
        getState: () => mockState
    };

    beforeEach(() => {
        dispatched = [];
        mockState = {};
    });

    it('should listen for IllustrationsActions.GRAPH_MODEL_CHANGED and dispatch IllustrationsActions.apiUpdateGraph, debounced by 1 second', () => {
        runSaga(options, graphModelUpdate);
        emitAction(IllustrationsActions.graphModelChanged('model one'));
        emitAction(IllustrationsActions.graphModelChanged('model two'));
        emitAction(IllustrationsActions.graphModelChanged('model three'));
        expect(dispatched).toEqual([]);
        jest.runTimersToTime(1500);
        expect(dispatched).toEqual([
            IllustrationsActions.apiUpdateGraph('model three')
        ]);
    });
});

问题在于,由于saga使用异步运行的fork,所以在调度去抖动作之前执行最终expect,无论假冒时间过多({{1} }),使测试总是失败。

我该如何处理这种情况?

1 个答案:

答案 0 :(得分:0)

伪造的计时器可以正确地提前时间,但是仍然有必要释放事件循环,以便生成器可以恢复执行,并且只有在我们可以继续执行期望的情况下

不使用setTimeout的情况下执行此操作的示例(因为它已经被玩笑嘲笑了):

jest.runTimersToTime(1500);
await Promise.resolve(); // generator resumes execution
expect(dispatched).toEqual([
   IllustrationsActions.apiUpdateGraph('model three')
]);