如何测试使用 setTimeout 调用另一个操作的异步操作创建者

Posted

技术标签:

【中文标题】如何测试使用 setTimeout 调用另一个操作的异步操作创建者【英文标题】:How do I test an async action creator that calls another action with setTimeout 【发布时间】:2017-07-22 14:52:32 【问题描述】:

我有以下显示通知然后将其删除的操作,我正在尝试为其编写单元测试,但我似乎无法弄清楚如何模拟 setTimeout。

export const addNotification = (text, notificationType = 'success', time = 4000) => 
        return (dispatch, getState) =>
            let newId = new Date().getTime();
            dispatch(
                type: 'ADD_NOTIFICATION',
                notificationType,
                text,
                id: newId
            );
            setTimeout(()=>
                dispatch(removeNotification(newId))
            , time)
        
    ;
    export const removeNotification = (id) => (
    
        type: 'REMOVE_NOTIFICATION',
        id
    );

按照 redux 网站上关于异步测试的教程,我想出了以下测试:

    import * as actions from '../../client/actions/notifyActionCreator'
    import configureMockStore from 'redux-mock-store'
    import thunk from 'redux-thunk'

    const middlewares = [ thunk ];
    const mockStore = configureMockStore(middlewares);


    describe('actions', ()=>

        it('should create an action to add a notification and then remove it', ()=>

            const store = mockStore( notifications:[] );

            const text = 'test action';
            const notificationType = 'success';
            const time = 4000;
            const newId = new Date().getTime();

            const expectedActions = [
                type: 'ADD_NOTIFICATION',
                notificationType,
                text,
                id: newId
            ,
                type: 'REMOVE_NOTIFICATION',
                id: newId
            ];

            return store.dispatch(actions.addNotification(text,notificationType,time))
                .then(() => 
                    expect(store.getActions()).toEqual(expectedActions)
                );
        );
    );

现在它只是抛出一个错误 Cannot read property 'then' of undefined at store.dispatch,非常感谢任何帮助。

【问题讨论】:

你在开玩笑吗? 【参考方案1】:

首先,由于您的操作创建者不返回任何内容,因此当您调用store.dispatch(actions.addNotification()) 时,它会返回undefined,这就是您收到错误Cannot read property 'then' of undefined 的原因。要使用.then(),它应该返回一个承诺。

因此,您应该修复您的动作创建者或测试以反映动作创建者实际所做的事情。要使您的测试通过,您可以将测试更改为以下内容:

// set up jest's fake timers so you don't actually have to wait 4s
jest.useFakeTimers();

store.dispatch(actions.addNotification(text,notificationType,time));
jest.runAllTimers();
expect(store.getActions()).toEqual(expectedActions);

另一种选择是使用详细的策略in the Jest docs。

// receive a function as argument
test('should create an action to add a notification and then remove it', (done)=>

    // ...

    store.dispatch(actions.addNotification(text,notificationType,time));
    setTimeout(() => 
      expect(store.getActions()).toEqual(expectedActions);
      done();
    , time);
);

使用该策略时,Jest 会等待done() 被调用,否则会在测试体执行完毕时认为测试结束。

【讨论】:

以上是关于如何测试使用 setTimeout 调用另一个操作的异步操作创建者的主要内容,如果未能解决你的问题,请参考以下文章

JS问题JQUERY问题如何让一段函数执行完毕后再执行另一段函数

js setTimeout如何调用自身所在的函数(有参数传递的)?

setTimeout 非法调用类型错误:非法调用

使用 Node 进行 Jest 测试 - 超时 - 在 jest.setTimeout 指定的 5000 毫秒超时内未调用异步回调

你如何将 setTimeout 包装在一个承诺中[重复]

超时 - 在 jest.setTimeout 指定的 5000 毫秒超时内未调用异步回调