Guide to writing your first Jest test

Guide to writing your first Jest test

Posted 2023-10-15

This is part of my notes section of the site.It is where I post quick notes/cheatsheets/etc.
For more in-depth articles which are (hopefully) more interesting check out my blog


How to write your tests in Jest

Using describe() to organise your test files

Wrap your tests in a describe() block like this.

You can nest them to help organise your test files:

BlogPost.test.tsx
✅ copied
describe('Your Component', () => { describe('Like count', () => { // your tests about the 'like count' feature... }) describe('Comment box', () => { // your tests about the 'comment' feature... }) })

(but don't overdo it with too much nesting of describe blocks).

(Most of the examples in this blog post will not add describe blocks. They are not required anyway, but help tidy up large test files)

Write your tests within it() or test() functions:

Write your tests in it() or test() functions (they are equivalent)

BlogPost.test.tsx
✅ copied
describe('Your Component', () => { describe('Like count', () => { test('increments the like count', () => { // write your assertions here }) // or use 'it()': it('should increment the like count', () => { // write your assertions here }) }) })

Run code before or after each test with beforeAll()/afterAll()

If you need to set up some mocks or shared data, use beforeAll, beforeEach within the describe() block.

  • beforeAll will run once, before all the tests in that block/scope run
  • beforeEach will run before every it() or test() function
  • (and afterAll/afterEach work in a similar way)

You can put them inside a describe block to run before all/before each.

BlogPost.test.tsx
✅ copied
describe('Your Component', () => { // runs once - before any test functions: beforeAll(() => console.log("About to run all tests...")) // runs before each test beforeEach(() => console.log("Running a test...")) describe('Like count', () => { beforeAll(() => { // runs once - for tests within this block console.log("before all for this describe block"); }) test('increments the like count', () => { // write your assertions here }) }) })
  • If you need to run code after each test (e.g. to reset mocks), then use afterEach() and afterAll().

Writing your test assertions

Write assertions with expect(something).toBe(somethingElse) (or similar functions).

Use expect.any() when you don't care about the exact data.

Assertions.test.ts
✅ copied
test('some examples', () => { const someData = { name: "codedrivendevelopment.com", age: 99, } expect(someData.name).toBe('codedrivendevelopment.com'); expect(someData).toStrictEqual({name: expect.any(String), age: 99}) })

Mocking in Jest

Mock with jest.spyOn(module, 'functionToMock').mockReturnValue(someValue).

You can also use jest.mock() but spying is easier and works in most cases.

Spying.test.tsx
✅ copied
import SomeModule from '../somethingToSpyOn' const spy = jest.spyOn(SomeModule, 'calculatePriceFn') .mockReturnValue(25); test('it doubles the price', () => { const price = service.doublePrice() expect(price).toBe(50) expect(spy).toHaveBeenCalledTimes(1) })

Spying will only work if you have an export with an exposed function or method.

You will need to use jest.mock() to mock a full import.

jest.mock('some-package') // << mock entire module with dummy values. This isn't often too useful

You can pass in an argument to set up the mock import, and within that you can import the real implementation here. Here is an example:

✅ copied
jest.mock('../foo-bar-baz', () => { const originalModule = jest.requireActual('../foo-bar-baz'); //Mock the default export and named export 'foo' return { __esModule: true, ...originalModule, default: jest.fn(() => 'mocked baz'), foo: 'mocked foo', }; });

Resetting spy/mock state

Because spy functions or jest.fn() maintain state so you can check how many times it was called (or what arguments it was called with), you often will want to reset this state.

beforeAll(() => {
 /* clear all mocks will set # of calls back to 0 */
 jest.clearAllMocks() // << the most common one
})

If you want to restore a spy back to its real implmentation (before you set up a spy on that function) then either run:

jest.restoreAllMocks()

const someSpy = jest.spyOn(SomeModule, 'someFn')
someSpy.mockRestore()

Snapshots

Use snapshots to easily compare large chunks of data (like strings... or HTML).

Note: do not overuse these.

Run with jest --watch to automatically fill these in with their result, and it will fail on future runs if the contents change.

Snapshots.test.ts
✅ copied
test('snapshot example', () => { // after your run it for first time (when there are no arguments) // then it will serialise the results as a string and update your // test file with it (inline): expect(someResult).toMatchInlineSnapshot() // similar to inline snapshots, but it will place the serialised string // in a separate file expect(someResult).toMatchSnapshot() })

Mocking dates and timeouts

Mock dates with jest.useFakeTimers()

jest.useFakeTimers(); test('advances timers', () => { jest.advanceTimersByTime(1000); // Test something that happens after a timer });

General tips

  • Run jest in watch mode to automatically re-run after files are saved/changed, with jest --watch
  • Run a specific test file by entering the file name after the jest command like jest yourComponent.test.ts (or just jest yourComponent).

Subscribe to my
Full Stack Typescript Developer
newsletter

If you enjoyed my content and want more Full Stack Typescript content, then enter your email below.

I send a few links every couple of weeks, that I personally found useful from around the web.

Focusing on Testing, Typescript, NextJS, and also
engineering soft skills posts.