Testing Redux next and api.dispatch with TypeScript and Jest

A middleware in Redux can have quite a lot of logic. In fact, this is my favorite place to place logic. The rationale is that it can be triggered by an action, still, have the time to request data from the backend server with an Ajax call and can dispatch other actions that can be computed by another middleware or by a reducer. It becomes crucial to unit test any area where logic can go wrong, thus testing if specific logic dispatch or invoke next.

Testing api.dispatch is a matter of leveraging Jest. If you are using React and Redux, it is the defacto testing framework. In fact, it is the one coming with the famous “create-react-app”. To test if an action got dispatched from the api.dispatch, you need to mock the dispatch and verify that it has been called. The function “toHavebeenCalledWith” can take another expect which can peek the content of an object passed. Because every action contains a type and payload, it is possible to verify if an action has been invoked.

middleware.myFunctionInMiddleware(next, api, payload);
expect(api.dispatch).toHaveBeenCalledWith(
    expect.objectContaining({
        type: MY_ACTION_CONSTANT_HERE
    })
);

The case of next is similar. I found that while it is possible to use a similar logic than with api.dispatch, that sometimes it is not enough. For example, if you have a function that calls several times “next.” In that case, it is possible to pass a custom “next” that will be smarter than a simple mock.

let nextMock = nextPayloadTypeSpy(MY_ACTION_CONSTANT_HERE);
middleware.myFunctionInMiddleware(nextMock.mock, api, payload);
expect(nextMock.getPayload()[0]).toBe(payload);
expect(nextMock.hasBeenCalled()).toBeTruthy();

The code above this paragraph is a glimpse of how to use the smart “next.” The code accumulates in an array all invocation and allows to asset its content along the test. In that case, the test was testing the first execution of the “next” associated to a specific action (defined at the declaration of the object).  The logic relies on a custom Jest’s function that adds in an array all actions of a specific time when invoked by the tested function.

export interface ActionsWithPayload<TypeAction, TypePayload> {
    type: TypeAction;
    payload: TypePayload;
}
export interface SpyActionsWithPayload {
    mock: jest.Mock&lt;{}>;
    hasBeenCalled: () => boolean;
    getPayload: () => any[];
}

export function nextPayloadTypeSpy(type?: string): SpyActionsWithPayload {
    let typeFromCaller: string[] = [];
    let payloadFromCaller: any[] = [];
    let nextMock = jest.fn().mockImplementation((func: ActionsWithPayload<any, string>) => {
        typeFromCaller.push(func.type);
        if (func.type === type) {
            payloadFromCaller.push(func.payload);
        }
    });
    return {
        mock: nextMock,
        hasBeenCalled: () => {
            return type === undefined ? false : typeFromCaller.includes(type);
        },
        getPayload: () => payloadFromCaller
    };
}

The code is tightly coupled with how you are handling your action. I strongly suggest using the Redux-TypeScript boilerplate “free”. It is really a relief to use in a term that you will create action within 30 seconds and to be type safe for the payload.

The code uses a “mock” property which is a hook to a mock implementation that does nothing else than being recorded in an array. The actual action is doing nothing. The two functions aside the mock property are there to assert the test. Future improvements are obvious. For example, the “hasBeenCalled” could also take an index to ensure that a particular “next” has been called.

To summarize, even if the middleware design is frightful, with types and some useful utility functions and patterns creating code and testing this one afterward is a breeze. I always enjoy having tests that are quick to build, and the discussed approach rationale with that mindset.

Mocking Every Functions of an Object with Jest and TypeScript

Most of the time, it is enough to simply mock a handful amount of member of an object while performing unit tests. However, if you are using the dependency injection pattern, it is faster to not send an actual object and manually cherry-pick which function to test. Since you are injected an external object, you definitely do not want to test that object and you do not want to manually create a stub object which can be time consuming.

class MyClass{
    constructor(public myOtherInjectedClass: IMyInjectedClassTypeHere){ ...}
}

The idea is to use TypeScript mapped type to create a mirror of the type you inject but instead of having the raw function as a type to have the Jest’s mocking type. Changing the type will allow having a strongly typed object that has the same members but the function to be a mock. It gives the ability to use safely the Jest’s mocking features. 

The first step is to create a custom type mapping. The type has a generic type that is the object you are injecting. In the example, the “IMyInjectedClasTypeHere” is the one containing functions and variables. We want to change all the function to become a Jest’s mock type.

type Mockify<T> = { [P in keyof T]: T[P] extends Function ? jest.Mock<{}> : T[P] };

The “Mockify” type is looping all the members and when found one that is a function return a new Mock object. Otherwise, it returns the member in its initial format.

The next step is to create a function that transform an object into the Mockify one. So far, we only have a type translation, now we need to have the logic to transform.

function mapToMockify<T extends Object>(obj: T): Mockify<T> {
let newObject: Mockify<T> = {} as Mockify<T>;
const properties = Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
for (let i = 0; i &lt; properties.length; i++) {
newObject[properties[i]] = jest.fn();
}
return newObject;
}

From this point, you can invoke the function from your real instance and get a modified one ready to be injected and interrogated with all the Jest’s mocking features.

const toTest = new MyClass(mapToMockify(new MyInjectedClassTypeHere()));
expect(toTest.function1).toHaveBeenCalled();

To recap, in this article we saw that with the combination of TypeScript’s mapped type and basic JavaScript we created an easy way to create a replica of a class that has all its functions transformed to Mock. 

TypeScript: Testing Private Members

I wrote about three years ago on how to test private member as well as last year and the year before. One article was more specific to C# and the two others more abstract and on TypeScript, but still relevant today. In this article, I’ll explain how I am testing private members without using any hack with Jest.

The goal of having private and public members is to mark a clear separation about what is restricted as internal use of the object that defines the member from what can be consumed from outside the scope of the object. The idea makes sense. The usage of the keyword “private” does not necessary. Using “private” does not work because you will not be able to test internal logic, neither mock them in your testing — it is blocked at the scope of the object.

class MyClass1 {
    private variable1: string = "init";
    public function2(p1: number, p2: number): void {
        // Code here...
        if (this.function1(p1)) {
            // More code here ...
        }
        // Code here... 
    }
    private function1(p1: number): boolean { }
}

There are some workarounds. One popular approach is to avoid testing these functions directly. The problem is that you have code that is not tested. An alternative is to test these private functions through public function. The problem is that you are using a function to proxy all the logic which make all test less “unit test” and fragile because these tests become dependant on another piece of code. If the logic of the private function remains the same, but the public function change, the code that is testing the private function will fail. It sways the simplicity into a nightmare. If the private function returns a boolean value, but the public function returns a void type, testing the return of the private function requires to understand the behavior of the public function that use it to extrapolate a behavior that corresponds to the return value. The proxy function, the public function, might be only a single one or many. When there is only a single function, the choice is limited and can push you in a corner without escape. When many functions, the selection of which one can also be problematic. In the end, the goal is to unit test, not to have many hurdles before even testing.

Another option is to cast to any and access the function. The problem is that any refactoring on the name will make the function to be “undefined.” It leads to issues of typing when the ground change that is the role of having a typed language in the first place.

describe("MyClass1", () => {
    describe("test the private function #1", () => {
        it("public proxy function", () => {
            const x = new MyClass1();
            expect(x.function2(1, 2)).toBe("????");
        });
        it("cast with any", () => {
            const x = new MyClass1() as any;
            expect(x.function1(1)).toBeTruthy();
        });
    });
});

So, if we have all these solutions with weaknesses, what is the best solution? The best solution that I have been used for a while now is this one: do not use private. Instead, you should use interface. The idea is that the concrete object will never be used directly, hence can have its members public. The usage across the whole application is done with an interface that exposes the members that the consumers can interact. Here is the same code as above but with the pattern of using an interface instead of private.

interface IMyClass1 {
    function2(p1: number, p2: number): void;
}

class MyClass1 implements IMyClass1 {
    private variable1: string = "init";
    public function2(p1: number, p2: number): void {
        // Code here...
        if (this.function1(p1)) {
            /// More code here ...
        }
        // Code here... 
    }
    public function1(p1: number): boolean { }
}

describe("MyClass1", () => {
    let x: MyClass1;
    beforeEach(() => {
        x = new MyClass1();
    });
    describe("function1 with an integer", () => {
        it("returns true", () => {
            expect(x.function1(1)).toBeTruthy();
        });
    });
});

It works perfectly in term of testability. The unit test code has access to all members because everything is public. It is easy to invoke all members directly but also to mock these and still keep and the type from TypeScript. In the application, we use the interface everywhere. The only place where we use the concrete class is during the initialization. Every declaration uses the interface — no exception.

Furthermore, a class is easily mockable with framework because you can access every public function and assign them a mock/spy/stub that allows to control specific branches of the code as well as managing the scope of the test to be as much as a single unit. The key of an efficient test is to have every block of code tested as a unit and then moving from bottom to top with more and more integration tests.

describe("MyClass1", () => {
    let x: MyClass1;
    beforeEach(() => {
        x = new MyClass1();
        x.function1 = jest.fn();
    });
    describe("function2", () => {
        it("calls function1", () => {
            x.function2(1,2);
            expect(x.function1).toHaveBeenCalledTimes(1);
        });
    });
});

Last but not the least, functions that are directly sitting in a module are very hard to unit test. It is not possible to mock or spy their dependencies. The lack of access sway my design to always encapsulate every function into a class.

In summary, encapsulation does not require to rely solely on public, private and protected keywords. The usage of an interface is powerful by adding the protection to what can be accessed while allowing developers to have a sane and simple way to test correctly without using a detour to obtain the desired piece of code.

Unit Tests and Coverage Report in Jenkins using Jest from Create-React-App

Since I left Microsoft Visual Studio Online (VSTS) has an employee I have been using Jenkins which is the continuous integration (ci) platform Netflix uses. I configured two Jenkins jobs for the project I am leading. One is handling every pull request done against master and the second one is executed during the merge of any pull request into master. For many months, I didn’t have the unit tests running on the platform. The reason is that I am, yet, used to how Jenkins works and even after several months feel VSTS more intuitive. Regardless, recently I took the time and setup to have my TypeScript code using Create-React-App to run my unit tests in these two Jenkins tasks. I am using Create-React-App, which come with the best testing framework I have experimented so far which is Jest. My goal was to have all the unit tests ran as well as to see the coverage.

Here are the steps required to have Jenkins handle your test. First thing is to install a dev dependency to “jest-junit”. The reason is that we need to convert the format of Jest into Junit.

npm install --save-dev jest-junit

The next step is to download a Python script in your repository. I have mine in “tools”. The reason is also about converting. Jest coverage file is not in the right format. The Python script converts the locv into Cobertura format. You can download once the script at this address.

wget https://raw.github.com/eriwen/lcov-to-cobertura-xml/master/lcov_cobertura/lcov_cobertura.py

Few configurations are required in the package.json. The first one is to create a test command that Jenkins execute instead of the default test command. The command calls the react-scripts. I am using TypeScript, hence I have to use the react-scripts-ts command. The next parameter is the “test” command which we still want to execute. The change starts with the test results processor. This is where you specify the jest-junit to execute once the tests are done. I set my coverage to be positioned into the “coverage” folder which is the folder I have ignored in the .gitignore and where I have normally my local coverage file outputted. Here are the three commands I have. The first one runs the test, the second run and coverage for the ci (this is the new stuff) and the last one is when I want to run locally the coverage.

"test": "react-scripts-ts test --env=jsdom",
"test:ci": "react-scripts-ts test --env=jsdom --testResultsProcessor ./node_modules/jest-junit --coverage --coverageDirectory=coverage",
"coverage": "react-scripts-ts test --env=jsdom --coverage",

Finally, you need few jest-unit configurations. This can be in your package.json. I have some coverage folder that I want to exclude which you can do in the jest configuration under collectCoverageFrom. I had these before doing the task we are doing of configuring Jenkins. Then, the coverage reported must be lcov and text. Finally, the new configurations are under “jest-junit”. The most important configuration is the “output” which is again in the coverage folder. You can change the destination and file as you wish. However, remember the location because you will need to use the same in a few instants inside Jenkins.

  "jest": {
    "collectCoverageFrom": [
      "**/*.{ts,tsx}",
      "!**/node_modules/**",
      "!**/build/**",
      "!**/definitionfiles/**",
      "!**/WebWrokers/**",
      "!**/*.mock.ts",
      "!src/setupTests.ts"
    ],
    "coverageReporters": [
      "lcov",
      "text"
    ]
  },
  "jest-junit": {
    "suiteName": "jest tests",
    "output": "coverage/junit.xml",
    "classNameTemplate": "{classname} - {title}",
    "titleTemplate": "{classname} - {title}",
    "ancestorSeparator": " > ",
    "usePathForSuiteName": "true"
  },

In Jenkins, you need to add 2 build steps and 2 post-build steps. The first build step is to run the unit test with the script we just added in the package.json. The type of build step is “Execute Shell”.

npm run test:ci

The second step is also an “Execute Shell”. This one calls the python code that we placed in the “tools” folder. It is important to change the path of your lov.info and coverage.xml. Both are in my “/coverage/” folder. The “base-dir” is the directory of the source of your code.

python tools/lcov_cobertura.py coverage/lcov.info --base-dir src/ --output coverage/coverage.xml

The next two steps are “Post-Build”. This time, two different types. The first one is “Publish JUnit test result report”. It has a single parameter which is the XML file. Mine is set to “coverage/junit.xml”. The second task is a “Publish Cobertura Coverage Report”. It also takes a single parameter which is the coverage.xml file. Mine is set to “coverage/coverage.xml”.

At that point, if you push the modification from the package.json and the Python script you will see Jenkins running the unit tests and doing the conversion. It is possible to adjust the threshold of how many tests your allow to fail to not break the build as well as setting the percentage of coverage you expect. You will get a report on the build history that allows you to sort and drill into the coverage report.

Creating Test with Jest and TypeScript wiht describe, beforeEach and it

Jest provides an easy structure to organize unit tests. It consists of blocks a function imbricated. Each function is a division of a test but not a test itself. The test is inside the function “it”. Here is an example:

describe("Test Class A", () => {
    describe("method 1", () => {
        describe("when parameter a < 0", () => {
            it("throwns an exception", () => {
            });
        });
        describe("when parameter a == 0", () => {
            it("returns 0", () => {
            });
        });
        describe("when parameter a > 0", () => {
            it("returns xyz", () => {
            });
        });
    });
});

The structure is a little bit convoluted but enforces a logical way to divide test and to create very small functions which are easier to maintain. The idea is to strive to have one assertion by test (by “it” function).

Another particularity of the describe function is that since it is a function it creates a closure where variables can live. This allows sharing variables between children functions. A distinction is that it’s alright to declare variables to be shared at the beginning of the describe block, but not to assign. The reason is to respect the order of execution, initialization must be set in the special function “beforeEach” or “beforeAll” which are executed before the subsequent block (describe or it). Here is the same code with an object used in each test.

describe("Test Class A", () => {
    let myObj: ObjectType1;
    describe("method 1", () => {
        beforeEach(() => {
            moObj = new ObjectType1();
        });
        describe("when parameter a < 0", () => {
            it("throwns an exception", () => {
            });
        });
        describe("when parameter a == 0", () => {
            it("returns 0", () => {
            });
        });
        describe("when parameter a > 0", () => {
            it("returns xyz", () => {
            });
        });
    });
});

It might sound very easy and logical, but you may be in a situation that you think that something is wrong — that beforeEach are executed after you test! If this occurs, double check that you do not have an exception thrown in the beforeEach that short-circuit the remaining of the beforeEach code. Double check as well if there is a code assigned directly to a describe block that might be executed out of order.

Strongly Typed Mock with TypeScript and Jest

TypeScript strongly typed nature help reducing the number of tests but unit tests will always be needed to test logic. Jest comes for free when using the React ecosystem and the project “create-react-app” which is also available with TypeScript as the transpiler. In this article, we will see a way to mock an interface that got injected into a class in a strongly typed fashion.

Before getting too far into the detail of the implementation, here is a basic interface that a class use in the application and a class that uses that interface by injection to another class. The goal will be to unit test the class that receives the injected interface. We want to abstract the implementation of the concrete injected class and rely on mocking the interface with Jest.

interface IClassToInject {
    run(): boolean;
}
class ClassToInject implements IClassToInject {
    public run(): boolean {
        return Math.random() >= 0.5;
    }
}
class ClassToTest {
    constructor(private injectedClass: IClassToInject) { }
}

const myClass = new ClassToTest(new ClassToInject());

The idea will be to use jest.Mock which is generic. The problem that we want to have Jest using the same object but not the real type. The idea is to have Jest using the same structure but with the type swapped to use Jest’s stub. TypeScript type mapping can be handy in a situation where we want to preserve the structure but change the type. The type, that I called “Mockify” allows doing exactly this transformation for you. Instead of injecting the interface directly, we inject the Mockify interface. Creating a Mockify version force the definition of each property which you can set to jest.fn(). There is a little of boilerplate that could be automated but overall, the idea is to have the strongly typed nature available. If the interface adds a new member, delete, or rename, the transpiler will raise an error in your test! The notification brings extra validation very soon in the development flow.

The next step is to create a variable that will hold the mocked interface where you can set returned value depending on what is tested in each test. Finally, we set the mock object to the class by injecting the mock by the constructor.

type Mockify<T> = {
    [P in keyof T]: jest.Mock<{}>;
};
let mockInterfaceToInject: Mockify<IClassToInject> = {
    run: jest.fn()
};

mockInterfaceToInject.run.mockReturnValue(false);
const classToTest = new ClassToTest(mockInterfaceToInject);

In this article, we saw that it’s possible to keep an existing interface and to map its structure with new returned values that are from Jest’s mocking framework. It allows keeping in sync with the model and flexible by adding testing capability like giving returned value or count how many time a property is called.

How to unit test a file in Jest that use webworker?

This might be tricky. Why is it a problem? It is because it’s a web concept and Jest doesn’t use the browser and in fact, we do not want to use this feature, we want to use a module that may reference a web worker. If you are using create-react-app or the TypeScript equivalence you know that to use a web worker you must do something different to import this one. Your code may look like this:

import * as workerPath from "file-loader?name=[name].js!../../WebWorkers/yourWebWorker";

With a file-loader definition file that may look like this:

declare module "file-loader?name=[name].js!*" {
    const value: string;
    export = value;
}

However, doing so will have an issue with Jest that won’t understand the file-loader and will crash. To get around, Jest allows configuring a “moduleNameMapper” property to mock the call. Unfortunately, if you are using create-react-app, you won’t have access to this property since only a merely portions of what available is supported. You’ll have to be more imaginative and use what you can find. Jest is open source and it allows to get inside. One thing you can see in the source code is that it sets the ENV variable to test. So a working solution is to look if we are in test and to return something else than the web worker.

async function getWorkerPath() {
    let workerPathAsync = "";
    if (process.env.NODE_ENV !== "test") {
        workerPathAsync = require("file-loader?name=[name].js!../../WebWorkers/logWebWorker");
    }
    return workerPathAsync;
}
const workerPath = getWorkerPath();

The “require” syntax work, the “await import” async version doesn’t work yet for me even if I was using TypesScript 2.5.3. It was compiling but during Jest execution, the syntax was not supported. Regardless, the “require” solution let you load it for your development and production environment.