0018.3 jest testing framework for Node.js


Cheatsheet

Installation

npm install --save-dev jest

For TypeScript:

npm install --save-dev ts-jest @types/jest
npx ts-jest config:init

Basic Commands


Test Structure

describe('Group of tests', () => {
  beforeAll(() => {
    // Runs once before all tests
  });

  beforeEach(() => {
    // Runs before each test
  });

  afterEach(() => {
    // Runs after each test
  });

  afterAll(() => {
    // Runs once after all tests
  });

  test('should do something', () => {
    expect(true).toBe(true);
  });
});

Matchers

Common Matchers

expect(value).toBe(value);               // Strict equality
expect(value).toEqual(value);           // Deep equality
expect(value).toEqual(expect.any(constructor)) // Matches anything that was created with the given constructor
expect(value).toBeNull();               // null
expect(value).toBeDefined();            // Not undefined
expect(value).toBeUndefined();          // undefined
expect(value).toBeTruthy();             // true-like
expect(value).toBeFalsy();              // false-like

Numbers

expect(value).toBeGreaterThan(number);
expect(value).toBeGreaterThanOrEqual(number);
expect(value).toBeLessThan(number);
expect(value).toBeLessThanOrEqual(number);
expect(value).toBeCloseTo(number, precision);

Strings

expect(string).toMatch(/regex/);

Arrays/Iterables

expect(array).toContain(item);
expect(array).toHaveLength(number);

Objects

expect(object).toHaveProperty(keyPath, value);
expect(object).toHaveProperty('kitchen.area', 20);

Exceptions

expect(() => {
  throw new Error('error');
}).toThrow('error');

async function to throw

it('should test async errors', async () =>  {        
    await expect(failingAsyncTest())
    .rejects
    .toThrow('I should fail');
});

Mock Functions

Basic Mock

const mockFn = jest.fn();
mockFn();
expect(mockFn).toHaveBeenCalled();
expoect(mockFn).toHaveBeenCalledWith(...args);
expect(mockFn).toHaveBeenCalledTimes(1);

Mock Implementation

const mockFn = jest.fn().mockReturnValue(42);
expect(mockFn()).toBe(42);

const mockFn2 = jest.fn().mockImplementation((x) => x + 1);
expect(mockFn2(1)).toBe(2);

Mock Implementation

// Uses a custom implementation that adds 1
const mockFn3 = jest.fn()
  .mockImplementation((x) => x + 1);

expect(mockFn3(1)).toBe(2);
expect(mockFn3(5)).toBe(6);
// Custom implementation only on the first call, then undefined
const mockFn4 = jest.fn()
  .mockImplementationOnce((x) => x * 2);

expect(mockFn4(3)).toBe(6);
expect(mockFn4(3)).toBeUndefined(); 

Spy on Existing Function

const obj = {
  method: (x) => x + 1,
};
const spy = jest.spyOn(obj, 'method');
obj.method(2);
expect(spy).toHaveBeenCalledWith(2);

Mock Return Values

// Always returns 42
const mockFn = jest.fn().mockReturnValue(42);

expect(mockFn()).toBe(42);
expect(mockFn()).toBe(42); // Still 42
// Returns 10 on the first call, then undefined afterward
const mockFn2 = jest.fn()
  .mockReturnValueOnce(10);

expect(mockFn2()).toBe(10);
expect(mockFn2()).toBeUndefined();

Mocking Asynchronous/Promises

// mockResolvedValue: always resolves to the given value
const fetchData = jest.fn().mockResolvedValue({ data: 'Mocked data' });

test('it resolves with mocked data', async () => {
  const result = await fetchData();
  expect(result).toEqual({ data: 'Mocked data' });
});
// mockResolvedValueOnce: resolves with different values on each call
const fetchData2 = jest.fn()
  .mockResolvedValueOnce({ data: 'Mocked data #1' })
  .mockResolvedValueOnce({ data: 'Mocked data #2' })
  .mockResolvedValue({ data: 'Default mocked data' });

test('returns different values for sequential calls', async () => {
  let result = await fetchData2();
  expect(result).toEqual({ data: 'Mocked data #1' });

  result = await fetchData2();
  expect(result).toEqual({ data: 'Mocked data #2' });

  result = await fetchData2();
  expect(result).toEqual({ data: 'Default mocked data' });
});
// mockRejectedValue: always rejects with an error
const fetchData3 = jest.fn().mockRejectedValue(new Error('Async error'));

test('rejects with an error', async () => {
  await expect(fetchData3()).rejects.toThrow('Async error');
});
// mockRejectedValueOnce: rejects on first call, resolves on subsequent calls
const fetchData4 = jest.fn()
  .mockRejectedValueOnce(new Error('Async error #1'))
  .mockResolvedValue({ data: 'Recovery data' });

test('rejects on first call, resolves on second', async () => {
  await expect(fetchData4()).rejects.toThrow('Async error #1');
  await expect(fetchData4()).resolves.toEqual({ data: 'Recovery data' });
});

Combining Multiple Behaviors

// Chain multiple resolved/rejected calls
const someAsyncFunction = jest.fn()
  .mockResolvedValueOnce('First call')
  .mockRejectedValueOnce(new Error('Second call failed'))
  .mockResolvedValue('All subsequent calls');

Usage in Test Suites

import { fetchUserData } from './dataService'; // The function you're mocking

jest.mock('./dataService', () => ({
  fetchUserData: jest.fn()
}));

describe('test asynchronous data fetch', () => {
  it('successfully fetches data', async () => {
    fetchUserData.mockResolvedValue({ name: 'Alice', age: 25 });
    
    const result = await fetchUserData();
    expect(result).toEqual({ name: 'Alice', age: 25 });
    expect(fetchUserData).toHaveBeenCalledTimes(1);
  });

  it('handles errors gracefully', async () => {
    fetchUserData.mockRejectedValue(new Error('Network issue'));
    
    try {
      await fetchUserData();
      throw new Error('This test should have failed but did not');
    } catch (error) {
      expect(error).toBeInstanceOf(Error);
      expect(error.message).toBe('Network issue');
    }
  });
});

Async Testing

Testing Promises

test('promise resolves', async () => {
  await expect(Promise.resolve('value')).resolves.toBe('value');
});

Testing Async/Await

test('async/await', async () => {
  const data = await fetchData();
  expect(data).toBe('value');
});

Testing Callbacks

test('callback test', (done) => {
  function callback(data) {
    expect(data).toBe('value');
    done();
  }
  asyncOperation(callback);
});

Snapshots

Creating Snapshots

test('matches snapshot', () => {
  const tree = render(<Component />);
  expect(tree).toMatchSnapshot();
});

Updating Snapshots

npx jest --updateSnapshot

Mock Modules

Mock Entire Module

jest.mock('module-name');

Mock Specific Function

jest.mock('module-name', () => ({
  functionName: jest.fn(),
}));

Clear/Reset Mocks

jest.clearAllMocks();
jest.resetAllMocks();
jest.restoreAllMocks();

Configuring Jest

jest.config.js

module.exports = {
  testEnvironment: 'node', // or 'jsdom'
  transform: {
    '^.+\\.jsx?

#### TypeScript Configuration

Update `jest.config.js`:

```javascript
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};

Coverage

Collect Coverage

npx jest --coverage

Exclude Files in Config

module.exports = {
  collectCoverage: true,
  collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
};

Debugging

Run Jest with Node debugger:

node --inspect-brk ./node_modules/.bin/jest --runInBand

: 'babel-jest',
},
moduleNameMapper: {
'\.(css|less)

TypeScript Configuration

Update jest.config.js:

{{CODE_BLOCK_36}}


Coverage

Collect Coverage

{{CODE_BLOCK_37}}

Exclude Files in Config

{{CODE_BLOCK_38}}


Debugging

Run Jest with Node debugger:

{{CODE_BLOCK_39}}


: '/mocks/styleMock.js',
},
};

#### TypeScript Configuration

Update `jest.config.js`:

{{CODE_BLOCK_36}}

---

### **Coverage**

#### Collect Coverage

{{CODE_BLOCK_37}}

#### Exclude Files in Config

{{CODE_BLOCK_38}}

---

### **Debugging**

Run Jest with Node debugger:

{{CODE_BLOCK_39}}

---