Тестирование с RunSaga с дублей и задержкой - PullRequest
3 голосов
/ 15 мая 2019

Если у меня есть сага с этой формой:

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)
}

Теперь сага не дотягивает до завершения и не останавливается - она ​​достигает take, но действие никогда не наступает в канале.

Можно ли проверить это с помощью этой формы? Я подозреваю, что могу заставить его работать, call используя delay s, а не yield напрямую, но я хотел бы знать, как заставить это работать без этого (если это возможно).

1 Ответ

4 голосов
/ 15 мая 2019

Использование yield call(() => myPromiseyDelay(500)) не спасет вас здесь. Во время отправки все равно будет нечего заметить «потерянное» действие.

Когда вы публикуете свой WAIT_FOR_ACTION, сага находится в уступившем состоянии на yield delay. Здесь нет очереди для действий, поэтому к тому времени, когда вы доберетесь до yield take(WAIT_FOR_ACTION), действие WAIT_FOR_ACTION уже отправлено, незамеченным любой из представленных вами саговых логик (не было активных take для захвата). действие).

Подумайте о настройке actionChannel для захвата этих нелицензионных действий. Они будут поставлены в очередь в канале, готовые к употреблению, после завершения delay.

Итак, что-то вроде:

function * sagaWorker() {
  const channel = yield actionChannel(WAIT_FOR_ACTION)
  yield put(START_ACTION)
  yield delay(100)
  yield take(channel)
  yield put(END_ACTION)
}

Итак, все это вместе, как не псевдокод:

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.0.2/dist/redux-saga.umd.min.js"></script>
...