Test Generator Runner

testGeneratorRunner package provides a set of tools to create both unit and integration tests for routines. It is widely used internally for testing purposes.

integrationTestRunner

import { integrationTestGeneratorRunner } from 'csp-coffee/testGeneratorRunner';

Integration test runner will record all calls inside our routines and provide a way to assert whether the particular call happened during the test run.

It also provides a way to advance a routine's internal generator to control it execution and test against its different states.

import { integrationTestGeneratorRunner } 
from 'csp-coffee/testGeneratorRunner';

function* innerGenerator1() {
    yield delay(1000);
}

function* innerGenerator2() {
    yield delay(1200);
}

function* outerGenerator() {
    yield all(call(innerGenerator1), call(innerGenerator2));
}
const { runTillEnd, createInstructionAsserter } =
    integrationTestGeneratorRunner(outerGenerator());

await runTillEnd();
const assert = createInstructionAsserter();

expect(assert.call(innerGenerator1)).toBeTruthy();
expect(assert.call(innerGenerator2)).toBeTruthy();

This is an example of how we would make sure that our all operator actually calls those two inner generators. We have used runTillEnd method to advance our generator runner to the end. We used createInstructionAsserter which provides us an object with a single method - call. This method will accept a generator function and return true if this generator was called in our outerGenerator. Note that this asserter will only record those calls which are made with call operator.

unitTestGeneratorRunner

import { unitTestGeneratorRunner } 
from 'csp-coffee/testGeneratorRunner';

Accepts an iterator as well much like a function above but will return an object that exposes a single .next method with the same signature. unitTestGeneratorRunner will iterate through a supplied iterator a little bit differently, see a paragraph below for a detailed explanation.

How these test runners step through an iterator

When calling a .next method or any of its aliases like .runNTimes or .runTillEnd, test generator runner will peform iterator.next on a supplied iterator. When processing this call, if any generators, promises, cancellablePromises or operators are encountered, they will be executed during a current step from start to end in integrationTestGeneratorRunner. unitTestGeneratorRunner will not execute nested generators, routines and operators right away and each next successive call will iterate through that nested generator, operator or routine until its done or throws an error. When it is done, the next .next will continue iterating through a parent iterator. unitTestGeneratorRunner allows you to precisely iterate through each and every step of the generator that is being tested and all of its children recursively.

API

integrationTestGeneratorRunner<G extends Generator<unknown, any, unknown>>(iterator: G): IntegrationGeneratorTestRunner

Will accept an iterator and produce an IntegrationGeneratorTestRunner object.

IntegrationGeneratorTestRunner

next: (arg?: any) => Promise<StepResult>

Will cal a .next method on an internal iterator with a provided argument and return a result with done and value properties.

runNTimes(times: number): Promise<StepResult>

Simply a shorthand for calling .next N times.

runTillEnd(): Promise<StepResult>

A shorthand to run iterator till its done.

StepResult

value: any

Is a value yielded from a supplied iterator as a result of .next call

done: boolean

Indicates whether a supplied iterator is done being iterated through

Last updated