Насколько я понимаю, этот пост в основном написан Джоном Пипкиным. Это было действительно хорошо и очень помогло мне, и я хотел, чтобы об этом поделился со всем миром.

Щелкните здесь, чтобы увидеть полную статью

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

Шаг 1

it(‘should return 6’, () => {
 // we’ve set up the generator, but we haven’t called next yet so we’re not at a yield
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 -> // We haven’t told the generator to exicute anything yet so we’re not at a yield
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

На этом этапе мы еще ничего не сказали генератору, поэтому нам нечего тестировать.

Шаг 2

it(‘should return 6’, () => {
 const gen = count()
// This next is called, we’re seeing what the yield will be
 expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number,2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
// Generator is paused here, waiting. The yield call(addNumber, number, 1) hasn’t executed
 -> number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

Здесь мы выполнили gen.next(). Мы сказали генератору перейти к оператору yield и подождать. Итак, теперь мы остановились на ->, но на самом деле еще не запустили код.

Когда мы получаем gen.next().value здесь, мы просто получаем то, что БУДЕТ делать доходность.

Шаг 3

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
// called next here, this evaluated the previous line. We pass in the return value from the last line
 expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 // We evaluated the previous line, now were waiting at the this yield
 -> number = yield call(addNumber, number, 2) 
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
}

Здесь мы снова позвонили gen.next(). Генератор видит эту команду и выполняет yield, на котором он был приостановлен, и продолжает следующий оператор yield. Здесь будет пауза ->. gen.next() сообщает оператору yield, в котором он должен был выполняться, мы можем передать то, что мы хотим вернуть, в вызов
Мы были приостановлены на yield call(addNumber, number, 1), мы хотели, чтобы он возвращал 1, поэтому мы передаем это, когда мы действительно выполняем эту строку .

Шаг 4

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number,1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
// Called next again, we evaluated the call to (number, 2) and specifiy its return value in this next
 expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(6).value).toEqual(put(something(6)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 -> number = yield call(addNumber, number,3) //6
 yield.put(something(number))
}

Этот шаг похож на предыдущий, просто чтобы проиллюстрировать, о чем я говорю. Выход для call(addNumber, number, 2) должен возвращать 3, поэтому мы передаем это в вызов gen.next(3), потому что мы сказали генератору выполнить эту строку, и мы хотим, чтобы он возвращал 3.

Шаг 5

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
// Called next again, we evaluated the call to (number, 3) and specifiy its return value in this next.
 // I’ve intentionally returned the wrong value from the call to (addNumber, number, 3) to illustrate how the return in next works
 expect(gen.next(8).value).toEqual(put(something(8)))
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 -> yield.put(something(number))
}

Мы снова позвонили в gen.next(), так что теперь ждем доходности до опциона. В этом примере вы можете видеть, что я намеренно вернул неправильное значение «8» в gen.next(). Это показано, чтобы проиллюстрировать, что next принимает значение, возвращаемое предыдущим выполнением. В данном случае данные только имитируют. Теперь мы видим, что доходность, на которой мы остановились, составляет put(number). Поскольку number в данном случае 8 (потому что это то, что мы сказали call(addNumber, number, 3) вернуться, это то, что мы ищем.

ШАГ 6

it(‘should return 6’, () => {
 const gen = count()
expect(gen.next().value).toEqual(call(addNumber, number, 1))
expect(gen.next(1).value).toEqual(call(addNumber, number, 2))
expect(gen.next(3).value).toEqual(call(addNumber, number, 3))
expect(gen.next(8).value).toEqual(put(something(8)))
// Finally call next again to see there are no more yields
 expect(gen.next().done).toBeTruthy()
})
function *count() {
 let number = 0
number = yield call(addNumber, number, 1)
 number = yield call(addNumber, number, 2) //3
 number = yield call(addNumber, number, 3) //6
 yield.put(something(number))
 ->
}

Наконец, мы снова вызываем gen.next(). Поскольку урожаев больше нет, мы можем увидеть, что сага закончена.