Unit Testing for Gatsby using Jest, Typescript and React Testing Library
Tags: testing, react, tdd, gatsby
Published: 2020-01-07 00:14:15

My first experience working TDD using React Testing Library with Jest for a Gatsby website in Typescript.

Setting up Jest and React Testing Library for TDD with Gatsby is quite straight forward. It does get a bit tricky because I plan on using Typescript in my tests. 
First, I install `jest`,  `babel-jest` and `babel-preset-gatsby` to ensure that the babel preset(s) that are used match what are used internally for a Gatsby site.

```
npm install --save-dev jest babel-jest  babel-preset-gatsby identity-obj-proxy tslint-react @types/jest
```

## Configuring Jest to work with Gatsby
Because Gatsby handles its own Babel configuration, I will need to manually tell Jest to use `babel-jest`. The gatsby website recommends creating a `jest.config.js` file. The code below works for me and should work nicely for you.

*jest.config.js*

```
const path = require("path")

module.exports = {
  setupFilesAfterEnv: [
    path.resolve(__dirname, "./jest-configs/setup-test-env.js")
  ],
  transform: {
    // "^.+\\.(tsx?|jsx?)$": "ts-jest",
    "\\.svg": "<rootDir>/jest-configs/__mocks__/svgTransform.js" ,
    "^.+\\.(tsx?|jsx?)$": `<rootDir>/jest-configs/jest-preprocess.js`,
  },
  moduleNameMapper: {
    // "\\.svg": `./jest-configs/__mocks__/file-mocks.js`,
    "\\.svg": `<rootDir>/jest-configs/__mocks__/svgTransform.js`,
    "typeface-*": "identity-obj-proxy",
    ".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`,
    ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `<rootDir>/jest-configs/__mocks__/file-mocks.js`,
  },
  testPathIgnorePatterns: [`node_modules`, `.cache`, `public`],
  transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`, `\\.svg`],
  globals: {
    __PATH_PREFIX__: ``,
  },
  testRegex: "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx)$",
  moduleFileExtensions: [
    "ts",
    "tsx",
    "js"
  ],
  collectCoverage: false,
  coverageReporters: [
    "lcov",
    "text",
    "html"
  ]
}
```

*svgTransform.js*
```
module.exports = {
  process() {
    return 'module.exports = {};';
  },
  getCacheKey() {
    // The output is always the same.
    return 'svgTransform';
  },
};
```

The `transform:` option tells Jest that all ts, tsx, js or jsx files need to be transformed using a `jest-preprocess.js` file. I have created this file in a `jest-configs` folder at the root of my project.

*jest-configs/jest-preprocess.js*
```
const babelOptions = {
  presets: [
    '@babel/preset-react', 
    'babel-preset-gatsby', 
    "@babel/preset-typescript"
  ],
};

module.exports = require("babel-jest").createTransformer(babelOptions)
```

I also need to put some code in `setup-test-env.js` . 
The [Jest Configuration](https://jestjs.io/docs/en/configuration#setupfilesafterenv-array) docs explains the `setupFilesAfterEnv: ....` configuration option if you need to understand what it means along with other available configuration options.
> A list of paths to modules that run some code to configure or set up the testing framework before each test.


*jest-configs/setup-test-env.js*
```
import "@testing-library/jest-dom/extend-expect"
```

That should have Jest properly configured. Now, I'll install the testing library and jest-dom as dev-dependencies with npm.

```
npm install --save-dev @testing-library/react @testing-library/jest-dom
```

After this I could run `npx jest` ( Using npx because jest isn't installed globally ) and I got good.

![cli](https://i.ibb.co/sRhdLKd/Screenshot-2020-01-07-at-12-36-15-AM.png)




## Ok GREAT WORK. 
Fingers crossed, I am about to write my first test and run it.
One major reason to love TDD is to fail faster or break things faster. This means, write tests before your write code. Also test should initially fail, always. [Read this up](https://hackernoon.com/introduction-to-test-driven-development-tdd-61a13bc92d92) from Hackernoon.

I'll create a `__tests__` folder on my project root folder. I'll then create a file called `test.spec.tsx` and paste this code in it. I usually prefer my tests along side my components eg `src/components/-componentName-/-componentName.spec.ts-.
Right now, I am not sure which convention is better accepted.

*__tests__/test.spec.tsx*

~~~~

import React from "react"
import { render } from "@testing-library/react"

// You have to write data-testid
const Title = () => <h1 data-testid="hero-title">Gatsby is awesome!</h1>

test("Displays the correct title", () => {
  const { getByTestId } = render(<Title />)
  // Assertion
  expect(getByTestId("hero-title")).toHaveTextContent("Gatsby is awesome!")
  // --> Test will pass
})

~~~~


#### *Run Yarn or npm install if you get errors like...*

~~~~
Cannot find module 'react' from 'test.spec.tsx'
    > 1 | import React from "react"
~~~~

# HURRAY SUCCESSFUL UNIT TESTING WITH TYPESCRIPT AND GATSBY AND JEST AND REACT TESTING LIBRARY

![test-passes](https://i.ibb.co/tKSRxLK/Screenshot-2020-01-07-at-1-02-50-AM.png)


I feel really good with this. I am just starting out Typescript with React so this was a lot of fun for me. I'll put up another post about writing real code using TDD for a FAQ website I am building using Gatsby.

Thank you for reading this..