Getting Started With Unit Testing In JS/TS And React

Wednesday, October 25, 2023 -  4 min read

Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently tested. The goal is to verify that each unit of code meets its design and behaves as expected. In simpler terms unit testing is isolating the smallest sets of code and testing them to verify that they behave as expected.

What do you need to get started?

  • a testing framework like Vitest or Jest (personally I prefer Vitest).
  • a project to test. I provided a repo to get started with here ( start with main and compare your branch at every step with the "steps" branch) but you can start with any project

Why Vitest, not Jest?

  • It's significantly faster than Jest.
  • Out-of-box ESM, TypeScript, and JSX support powered by esbuild.
  • In watch mode, it's smart and only reruns the related changes, just like HMR for tests!
  • If you know Jest you already know Vitest, it provides a Jest-compatible API that allows you to use it as a drop-in replacement in most projects. you only have to change a few things, and you're good to go. check the migration guide here

Installing Vitest in your project

yarn add -D vitest vite jsdom

shell

to test react components and/or hooks run

yarn add -D @vitejs/plugin-react react-test-renderer @testing-library/react @testing-library/jest-dom

shell

if you have typescript paths (absolute imports) configured in your project run

yarn add -D vite-tsconfig-paths

shell

Configuring Vitest

Make a file in the root of the project called vitest.config.ts with the following code

// to only use absolute imports defined in TS import { defineConfig } from 'vitest/config'; import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ plugins: [tsconfigPaths()] }); // to test react use the following import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ plugins: [tsconfigPaths(), react()], test: { environment: 'jsdom', setupFiles: ['./tests/setupTests.ts'], }, });

ts

@vitejs/plugin-react enables HMR to react in development. vite-tsconfig-paths makes vite use the paths defined in your tsconfig. environment: 'jsdom' by default the environment is node which means that any code meant for the browser can't run in the test, so we use jsdom which provides a browser-like environment to run the test in it.

Make file called tests/setupTests.ts with the following code (in case of React testing)

import '@testing-library/jest-dom/vitest'; import { afterEach } from 'vitest'; import { cleanup } from '@testing-library/react'; afterEach(() => { cleanup(); });

ts

The @testing-library/jest-dom/vitest library provides a set of custom jest/vitest matchers that you can use to extend jest/vitest. These will make your tests more declarative, clear to read, and maintain. Check the docs here to see the added matchers

the after each cleanup configures Vitest and @testing-library/react to clean up after running every test so that each test can run on a clean slate

Add the following script to your package.json

"test": "vitest run",

json

Writing our first test

let's start with something simple create a file called tests/add.ts with the following code

export const add = (a:number, b:number) => a + b;

ts

to test a unit is to check whether it matches something
eg: you expect 1 + 2 = 3. this is human language
in TS/JS you write expect(1+2).toEqual(3)
there are a lot of matchers for different types
eg: expect(function).toHaveBeenCalled()
eg: expect(object).toHaveProperty(property)
eg: expect(array).toContain(element)
eg: expect(boolean).not.toBe(false)

to create a test file you must use the extension .spec.(ts/tsx/js/jsx) or .test.(ts/tsx/js/jsx) A spec comes from "specification" where you specify how code should behave, the extension doesn't change anything in how we write the tests it's just a preference. so create a file in the same folder you created the add file called add.test.ts with the following code

import {add} from './add'; import { expect, test } from 'vitest' test("add()" , () => { expect(add(1,2)).toBe(3); })

ts

then fire up the terminal and run yarn test your terminal should look like this

congratulations! you just ran your first test successfully.