# Building a Github Repo Template Part 3: Jest Testing Setup with TypeScript

In this ongoing series, I am putting together a Github Repository Template for my "Go To" front-end tech stack of Next.js, React, TypeScript etc. In [the 2nd part of the series](https://hashnode.blainegarrett.com/building-a-github-repo-template-part-2-eslint-with-typescript-ckcnxtgm000aekls112id1qv7), I set up ESLint to work with TypeScript. In this post, I will get Jest Testing to work with TypeScript (and ESLint).

Just want the Code? [View the full changeset covered in this post](https://github.com/blainegarrett/react-next-material-typescript-template/compare/0.0.2...0.0.3) or check out the [0.0.3 release of the repository](https://github.com/blainegarrett/react-next-material-typescript-template/releases/tag/0.0.3).


## Prerequisites
If you are following along, [please complete part 2 of the series](https://hashnode.blainegarrett.com/building-a-github-repo-template-part-2-eslint-with-typescript-ckcnxtgm000aekls112id1qv7). I am immediately picking up where that post left off. 

## Writing a Simple Function To Test
Thus far, I've only dealt with Next.js page components, which have to live within the */pages* directory in the project root. I'll introduce a */src* folder to the project root and create a *utils* folder that will contain *add.ts* that will export a simple function to test. Using the nested folders will help us ensure that glob patterns are working later with Jest test matching (something worth confirming from experience).

```
// src/utils/add.ts

// Simple file to help illustrate jest testing
const add = (a: number, b: number): number => a + b;
export default add;
```
## Writing our Test 
Even though I have not yet installed Jest, I can still write the test. In a way, I am using Test Driven Design thinking to ensure the test setup works. In the *src/utils/* create a file *add.test.ts*

```
// src/utils/add.test.ts

import add from './add';

describe('adding two numbers should', () => {
  test('return expected when both args are non 0', () => {
    expect(add(1, 2)).toEqual(5);
  });
  test('return 0 when both args are 0', () => {
    expect(add(0, 0)).toEqual(5);
  });
  test('return expected when both args trigger floating point error', () => {
    expect(add(0.1, 0.2)).toEqual(5);
  });
});

```
*Note:* These tests are expected to fail when run as the expected value is 5. This is Test Driven Design thinking. Once they actually fail, I know they are being run and fixing them is trivial. I'll write a series about unit testing later. 
 
If you are following along, and have ESLint set up properly from the previous post, you should see some errors in your IDE highlighted as per below. As per the previous post, I am using VSCode.

![Screen Shot 2020-07-16 at 9.53.10 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1594911206466/b6qUklRnI.png)

This is due to TypeScript not knowing the types for *describe*, *test*, and *expect*. I need to install Jest and Jest Type Definitions to clean that up.

## Installing Jest and Types
To install Jest and the associated Types, simply run the following in the terminal
```
npm install --save-dev jest @types/jest
```
Once installed, the ESLint errors go away in the IDE
![Screen Shot 2020-07-16 at 9.54.36 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1594911289203/Zy6NiIFFr.png)

## Running Tests with Jest 
I have some code, I have a test for that code, and I installed Jest. However, I can't actually run the tests yet. Let's set that up next.

Update the default test script in *package.json* from
```
    "test": "echo \"Error: no test specified\" && exit 1"
```
to 
```
    "test": "jest --collectCoverage true",
```
I can now run the tests by typing the following in the command line
```
npm run test
```
This complains with an error: 
![Screen Shot 2020-07-16 at 11.04.26 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1594915495398/qrxLq4enb.png)
The reason for the error is that Jest doesn't know how to deal with TypeScript yet. Even though I have installed the Types, Jest needs some additional dependencies and configuration.

## Configuring Jest for TypeScript
I need to tell Jest how to deal with TypeScript. 

Run the following in the terminal to install TypeScript support for Jest
```
npm install --save-dev ts-jest
```

Once installed, add the following top level directive to the *package.json*
```
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".test.ts(x?)$",
    "transform": {
      "^.+\\.ts$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.{ts,tsx}"
    ],
    "moduleNameMapper": {
      "~/(.*)$": "<rootDir>/$1"
    },
    "coverageDirectory": "../coverage",
    "testEnvironment": "jsdom",
    "resetMocks": true
  }
```
**Note:** This config could live in a separate *jestconfig.json* file. However, jest supports putting config in the *package.json* so why clutter up the project directory?

Jest is now ready to run the tests written in TypeScript:
```
npm run test
```

![Screen Shot 2020-07-16 at 10.57.13 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1594915054534/qa9QmCOtd.png)

The tests failed, but they ran! I'll update the tests to pass by changing the expected value to what logically makes sense. Note that nasty floating point test...
```
import add from './add';

describe('adding two numbers should', () => {
  test('return expected when both args are non 0', () => {
    expect(add(1, 2)).toEqual(3);
  });
  test('return 0 when both args are 0', () => {
    expect(add(0, 0)).toEqual(0);
  });
  test('return expected when both args trigger floating point error', () => {
    expect(add(0.1, 0.2)).toEqual(0.30000000000000004);
  });
});

```

Running the tests again:

![Screen Shot 2020-07-16 at 11.00.10 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1594915222521/0trYvaN9w.png)
Celebrate!

## Separating Unit and Integration Tests 
I am a big fan of Test Driven Design. I'm also a big fan of separating unit tests from other slower types of tests. Personally, if running unit tests is slow, I believe people (myself included) skip TDD and/or skip writing tests all together. For that reason, I tend to prefer unit tests to be very simple and ran independently of other tests. Python's nose test runner used to have a simple class tag approach to this, but we can leverage Jest's filename matching to accomplish the same thing.

I will introduce two additional scripts to the *package.json*:

```
    "unit": "jest --testRegex '(?<!integration\\.)test\\.ts(x?)$'",
    "integration": "jest --testRegex 'integration\\.test\\.ts(x?)$'",
```
With these in place, I have 3 test commands:

1. `npm run unit` will run all unit test (those not ending in `integration.test.ts(x?)`)
2. `npm run unit` will run all the slower integration tests.
3. `npm run test` will run all tests AND generate a coverage report (which isn't necessary normally during normal dev)

I've previously written about this topic on my personal blog. If you would like more explanation, [give it a read](https://www.blainegarrett.com/2019/08/20/jest-setup-with-next).


## Closing Thoughts
At this point, the Github Template repository contains a Next.js application written in TypeScript that obeys airbnb formatting rules without any errors, and has Jest testing set up. [View the full changeset covered in this post](https://github.com/blainegarrett/react-next-material-typescript-template/compare/0.0.2...0.0.3) or check out the [0.0.3 release of the repository](https://github.com/blainegarrett/react-next-material-typescript-template/releases/tag/0.0.3).

This is a great starting point for most projects, but I'm going to do a bit more in [part 4 of the series](https://hashnode.blainegarrett.com/building-a-github-repo-template-part-4-typescript-path-aliases-ckcpaj01c00688vs1dxqc3kkl) by adding module aliases.

## Discussion Topic
Have you been using Tap instead of Jest? Do you like it? Post in the comments.


Image Credit: Photo by [Ylanite Koppens](https://www.pexels.com/photo/blackberries-in-macro-photography-2008135/) from Pexels

