Snippets
Typescript
Jest

Jest Snippets

Mocking

  • Mocking method-by-method
let state = {
    set: jest.fn(),
    get: jest.fn()
} as unknown as Map<string, string>;
  • Spying on a method to verify behaviour
const state = new Map<string, string>();
const setSpy = jest.spyOn(state, 'set');

Matching

  • Partial and nested object matching using objectContaining vs toMatchObject
 
 
  // objectContaining, with nested object, containing full props/values
  // PASSES
  expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
    position: {
      x: expect.any(Number),
      y: expect.any(Number)
    }
  }));
 
  // objectContaining, with nested object, containing partial props/values
  // FAILS
  expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
    position: {
      x: expect.any(Number)
    }
  }));
 
 
  // objectContaining, with nested object, also declared with objectContaining, containing partial props/values
  // PASSES
  expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
    position: expect.objectContaining({
      x: expect.any(Number)
    })
  }));
 
  // toMatchObject, with nested object, containing full props/values
  // PASSES
  expect({ position: { x: 0, y: 0 } }).toMatchObject({
    position: {
      x: expect.any(Number),
      y: expect.any(Number)
    }
  });
 
  // toMatchObject, with nested object, containing partial props/values
  // PASSES
  expect({ position: { x: 0, y: 0 } }).toMatchObject({
    position: {
      x: expect.any(Number)
    }
  });

Jest Config

  • jest.config.js
module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
    testMatch: ['**/*.test.ts'],
    moduleFileExtensions: ['ts', 'js'],
    transform: {
      '^.+\\.ts?$': 'ts-jest',
    },
    collectCoverage: true,
    coverageDirectory: 'coverage',
    coverageReporters: ['text', 'lcov'],
    verbose: true,
};

Custom Matchers


  • Create matcher custom-matcher.ts
// Function to check is UUID is valid
 
  const isUUIDv4 = (str: string): boolean => {
    const parts = str.split('-');
    
    // Check if the UUID has the correct parts and lengths
    if (
      parts.length !== 5 || 
      parts[0].length !== 8 || 
      parts[1].length !== 4 || 
      parts[2].length !== 4 || 
      parts[3].length !== 4 || 
      parts[4].length !== 12
    ) {
      return false;
    }
  
    // Validate each part for correct hex characters
    const isValidHex = (part: string) => /^[0-9a-f]+$/i.test(part);
    if (!isValidHex(parts[0]) || !isValidHex(parts[1]) || !isValidHex(parts[2]) || !isValidHex(parts[3]) || !isValidHex(parts[4])) {
      return false;
    }
  
    // Check that the version bit (4) is correct in the third section
    if (parts[2][0] !== '4') {
      return false;
    }
  
    // Check that the variant bits are correct (8, 9, a, b) in the fourth section
    if (!/^[89ab]$/i.test(parts[3][0])) {
      return false;
    }
  
    return true;
};
 
// Matchers
export const customMatchers = {
  toBeUUIDv4(received: string) {
    const pass = isUUIDv4(received);
    if (pass) {
      return {
        message: () => `expected ${received} not to be a valid UUID`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be a valid UUID`,
        pass: false,
      };
    }
  },
  • Extend matchers
expect.extend(customMatchers);
  • Attach to expect in jest.custom-matchers.d.ts for Typescript
import 'jest';
 
declare global {
  namespace jest {
    interface Matchers<R> {
      toBeUUIDv4(): R;
    }
    interface InverseAsymmetricMatchers {
      toBeUUIDv4(): any
    }
    interface Expect {
      toBeUUIDv4(): any
    }
  }
}