As much as want to take credit for this post this was mostly written by . It was real good and helped me a lot and I wanted it to be shared with the world. John Pipkin Click here for his full article So testing generators it’s best to think of them as loops that execute when you tell them to. Step 1 it(‘should return 6’, () => {// we’ve set up the generator, but we haven’t called next yet so we’re not at a yieldconst 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 yieldlet number = 0 number = yield call(addNumber, number, 1)number = yield call(addNumber, number, 2) //3number = yield call(addNumber, number, 3) //6yield.put(something(number))} In this step we haven’t told the generator to do anything yet, so we don’t have anything to test. Step 2 it(‘should return 6’, () => {const gen = count() // This next is called, we’re seeing what the yield will beexpect(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) //3number = yield call(addNumber, number, 3) //6yield.put(something(number))} Here we’ve executed . We’ve told the generator to go the yield statement and wait. So now we’re paused at the , but we haven’t actually ran the code. gen.next() -> When we get here we’re just getting what the yield WILL do. gen.next().value Step 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 lineexpect(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) //6yield.put(something(number))} Here we’ve called again. The generator sees that command and executes the yield that it was paused at and continues the next `yield` statement. It will pause here . tells the yield statement it was at to execute, we can pass what we want returned from that into the callWe were paused at , we wanted that to return so we pass that in when we actually execute that line. gen.next() -> gen.next() yield call(addNumber, number, 1) 1 Step 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 nextexpect(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) //6yield.put(something(number))} This one is just like the previous step, just to illustrate what I’m talking about. The yield to should return so we pass that in to the call to because we’ve told the generator to execute that line and we want it to return . call(addNumber, number, 2) 3 gen.next(3) 3 Step 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 worksexpect(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) //3number = yield call(addNumber, number, 3) //6-> yield.put(something(number))} We’ve called again so now we’re waiting at the yield to put. In this example you can see I intentionally returned the wrong value `8` in . This is to illustrate that next takes in the return value of the previous execution. Essentailly mock data in this case. Now we see that the yield we’re paused at is the . Since in this case is (because that’s what we told to return, that’s what we’re looking for. gen.next() gen.next() put(number) number 8 call(addNumber, number, 3) Step 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 yieldsexpect(gen.next().done).toBeTruthy()}) function *count() {let number = 0 number = yield call(addNumber, number, 1)number = yield call(addNumber, number, 2) //3number = yield call(addNumber, number, 3) //6yield.put(something(number))->} Finally, we call again. Since there are no more yields to wait for we can see the saga is done. gen.next()