我创建了一个recordSaga函数,它的目标是记录在传奇期间已分派(dispatch)了哪些 Action 。

export const recordSaga = async (saga, initialAction, state) => {
  const dispatched = [];

  const done = await runSaga(
    {
      dispatch: action => dispatched.push(action),
      getState: () => state,
    },
    saga,
    initialAction,
  ).done;

  return {
    dispatched,
    done,
  };
};


所以说我的传奇就是这个

export function* mySaga() {
  const needToSave = yield select(needToSaveDocument);
  if (needToSave) {
    yield put(saveDocument());
    yield take(SAVE_DOCUMENT_SUCCESS);
  }
  yield put(doSomethingElse())
}

我想编写两个测试,我希望是以下测试

describe('mySaga', async () => {
  it('test 1: no need to save', async () => {
    const state = { needToSave: false }
    const { dispatched } = await recordSaga(mySaga, {}, state);
    expect(dispatched).toEqual([
      doSomethingElse()
    ])
  })
  it('test 2: need to save', async () => {
    const state = { needToSave: true }
    const { dispatched } = await recordSaga(mySaga, {}, state);
    expect(dispatched).toEqual([
      saveDocument(),
      doSomethingElse()
    ])
  })
})

但是,对于测试2,两者之间有一个take,当然jest(或其女友jasmine)对我大吼:Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
我知道这是因为runSaga正在等待take(SAVE_DOCUMENT_SUCCESS),但是我该如何模拟呢?

最佳答案

答案stdChannel().put({type, payload})
为什么 ?

使用stdChannel,您可以在第一次运行后分派(dispatch)。

如何 ?

  • import stdChannel;
  • 添加到runSaga中的第一个参数;
  • 调用stdChannel().put(SAVE_DOCUMENT_SUCCESS);

  • 例子

    什么对我有用

    我离开了第一个测试,因为它是预期的最终结果,但是解决方案来自最后一个2。

    
      import { runSaga, stdchannel } from 'redux-saga'
      let dispatchedActions = [];
      let channel;
      let fakeStore;
    
      beforeEach(() => {
        channel = stdChannel(); // you have to declare the channel to have access to it later
        fakeStore = {
          channel, // add it to the store in runSaga
          getState: () => "initial",
          dispatch: (action) => dispatchedActions.push(action),
        };
      });
    
      afterEach(() => {
        global.fetch.mockClear();
      });
    
     it("executes getData correctly", async () => {
        await runSaga(fakeStore, getData, getAsyncData("test")).toPromise();
        expect(global.fetch.mock.calls.length).toEqual(1);
        expect(dispatchedActions[0]).toEqual(setData(set_value));
      });
    
      it("triggers takeLatest and call getData(), but unfortunately doesn't resolve promise", async () => {
        await runSaga(fakeStore, rootSaga)// .toPromise() cannot be used here, as will throw Timeout error
        channel.put(getAsyncData("test")); // if remove this line, the next 2 expects() will fail
        expect(global.fetch.mock.calls.length).toEqual(1);
        // expect(dispatchedActions[1]).toEqual(setData(set_value)); // will fail here, but pass on the next it()
      });
    
      it("takes the promised data from test above", () => {
        expect(dispatchedActions[1]).toEqual(setData(set_value));
      });
    

    this answer (about true code, not tests) helped me

    10-06 11:55