使用带有 take 和 delay 的 runSaga 进行测试
Testing with runSaga with take and delay
如果我有这种形式的 saga:
function * sagaWorker() {
yield put(START_ACTION)
yield take(WAIT_FOR_ACTION)
yield delay(100)
yield put(END_ACTION)
}
我可以像这样使用 runSaga
成功测试它:
step('saga passes the tests', async () => {
const channel = stdChannel()
const dispatched = []
const options = {
dispatch: action => dispatched.push(action),
getState: () => {},
channel
}
const task = runSaga(options, sagaWorker)
channel.put(WAIT_FOR_ACTION)
await task.toPromise()
expect(dispatched).to.deep.eql([START_ACTION, END_ACTION])
})
但是,如果我将延迟移到镜头前:
function * sagaWorker() {
yield put(START_ACTION)
yield delay(100)
yield take(WAIT_FOR_ACTION)
yield put(END_ACTION)
}
现在 saga 未 运行 完成并超时 - 它到达 take
但操作从未到达频道。
是否可以使用此表格进行测试?我怀疑我可以通过 call
ing delay
s 而不是直接 yield
ing 来使其工作,但我想知道如何在不这样做的情况下使其工作(如果可能的话) ).
使用 yield call(() => myPromiseyDelay(500))
不会在此处保存您。在派发时仍然不会注意到“丢失”操作。
当您 post 您的 WAIT_FOR_ACTION
传奇在 yield delay
上处于屈服状态。这里没有动作队列,所以当你到达 yield take(WAIT_FOR_ACTION)
时,WAIT_FOR_ACTION
动作早已被调度,你上面介绍的任何传奇逻辑都没有注意到(没有活动的 take
抓住行动)。
考虑设置一个 actionChannel
来捕获这些 unlistened-for 操作。 delay
完成后,他们将在频道 ready-to-consume 中排队。
所以,类似于:
function * sagaWorker() {
const channel = yield actionChannel(WAIT_FOR_ACTION)
yield put(START_ACTION)
yield delay(100)
yield take(channel)
yield put(END_ACTION)
}
所以把这些放在一起就是 non-pseudocode:
const {
runSaga,
stdChannel,
effects: {
take,
put,
actionChannel,
delay
}
} = window.ReduxSaga
const WAIT_FOR_ACTION = "WAIT_FOR_ACTION";
const START_ACTION = "START_ACTION";
const END_ACTION = "END_ACTION";
(async() => {
const channel = stdChannel();
const dispatched = [];
const options = {
dispatch: action => dispatched.push(action),
getState: () => {},
channel
};
const task = runSaga(options, sagaWorker);
channel.put({
type: WAIT_FOR_ACTION
});
await task.toPromise();
console.log(dispatched);
})();
function* sagaWorker() {
const channel = yield actionChannel(WAIT_FOR_ACTION);
yield put({
type: START_ACTION
});
yield delay(100);
yield take(channel);
yield put({
type: END_ACTION
});
}
<script src="https://cdn.jsdelivr.net/npm/redux-saga@1.1.3/dist/redux-saga.umd.min.js"></script>
如果我有这种形式的 saga:
function * sagaWorker() {
yield put(START_ACTION)
yield take(WAIT_FOR_ACTION)
yield delay(100)
yield put(END_ACTION)
}
我可以像这样使用 runSaga
成功测试它:
step('saga passes the tests', async () => {
const channel = stdChannel()
const dispatched = []
const options = {
dispatch: action => dispatched.push(action),
getState: () => {},
channel
}
const task = runSaga(options, sagaWorker)
channel.put(WAIT_FOR_ACTION)
await task.toPromise()
expect(dispatched).to.deep.eql([START_ACTION, END_ACTION])
})
但是,如果我将延迟移到镜头前:
function * sagaWorker() {
yield put(START_ACTION)
yield delay(100)
yield take(WAIT_FOR_ACTION)
yield put(END_ACTION)
}
现在 saga 未 运行 完成并超时 - 它到达 take
但操作从未到达频道。
是否可以使用此表格进行测试?我怀疑我可以通过 call
ing delay
s 而不是直接 yield
ing 来使其工作,但我想知道如何在不这样做的情况下使其工作(如果可能的话) ).
使用 yield call(() => myPromiseyDelay(500))
不会在此处保存您。在派发时仍然不会注意到“丢失”操作。
当您 post 您的 WAIT_FOR_ACTION
传奇在 yield delay
上处于屈服状态。这里没有动作队列,所以当你到达 yield take(WAIT_FOR_ACTION)
时,WAIT_FOR_ACTION
动作早已被调度,你上面介绍的任何传奇逻辑都没有注意到(没有活动的 take
抓住行动)。
考虑设置一个 actionChannel
来捕获这些 unlistened-for 操作。 delay
完成后,他们将在频道 ready-to-consume 中排队。
所以,类似于:
function * sagaWorker() {
const channel = yield actionChannel(WAIT_FOR_ACTION)
yield put(START_ACTION)
yield delay(100)
yield take(channel)
yield put(END_ACTION)
}
所以把这些放在一起就是 non-pseudocode:
const {
runSaga,
stdChannel,
effects: {
take,
put,
actionChannel,
delay
}
} = window.ReduxSaga
const WAIT_FOR_ACTION = "WAIT_FOR_ACTION";
const START_ACTION = "START_ACTION";
const END_ACTION = "END_ACTION";
(async() => {
const channel = stdChannel();
const dispatched = [];
const options = {
dispatch: action => dispatched.push(action),
getState: () => {},
channel
};
const task = runSaga(options, sagaWorker);
channel.put({
type: WAIT_FOR_ACTION
});
await task.toPromise();
console.log(dispatched);
})();
function* sagaWorker() {
const channel = yield actionChannel(WAIT_FOR_ACTION);
yield put({
type: START_ACTION
});
yield delay(100);
yield take(channel);
yield put({
type: END_ACTION
});
}
<script src="https://cdn.jsdelivr.net/npm/redux-saga@1.1.3/dist/redux-saga.umd.min.js"></script>