Vitest Cheatsheet

Assertions (expect)

Use this Vitest reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

expect() Basics

import { expect } from 'vitest'

expect(value)           // creates an assertion chain
expect(value).not.toBe(x)  // negate any matcher

Equality Matchers

MatcherChecks
.toBe(val)Object.is() strict equality (primitives, same reference)
.toEqual(val)Deep equality (objects, arrays — recursively)
.toStrictEqual(val)Deep equality + checks undefined properties + class instances
.toBeUndefined()=== undefined
.toBeDefined()!== undefined
.toBeNull()=== null
.toBeNaN()isNaN()
.toBeTruthy()truthy
.toBeFalsy()falsy
expect({ a: 1 }).toEqual({ a: 1 })       // passes
expect({ a: 1 }).toStrictEqual({ a: 1 }) // passes
expect(new Dog()).toStrictEqual({ name: 'Rex' }) // FAILS — different class

Number Matchers

MatcherChecks
.toBeGreaterThan(n)> n
.toBeGreaterThanOrEqual(n)>= n
.toBeLessThan(n)< n
.toBeLessThanOrEqual(n)<= n
.toBeCloseTo(n, digits?)Floating-point approximation (default 2 decimal digits)
.toBeFinite()Not Infinity or NaN
.toBePositive()> 0
.toBeNegative()< 0
.toBeInteger()No decimal part
expect(0.1 + 0.2).toBeCloseTo(0.3, 5)
expect(Math.PI).toBeCloseTo(3.14159, 5)

String Matchers

MatcherChecks
.toContain(str)Substring present
.toMatch(str|regex)Regex or substring match
.toHaveLength(n).length === n
expect('hello world').toContain('world')
expect('foo123').toMatch(/\d+/)
expect('foobar').toMatch(/^foo/)

.toStartWith / .toEndWith are not built-in — they come from the jest-extended package via expect.extend.

Array and Iterable Matchers

MatcherChecks
.toContain(item)Array contains item (strict equality)
.toContainEqual(item)Array contains item (deep equality)
.toHaveLength(n).length === n
.toEqual(expect.arrayContaining([...]))Array has at least these items
expect([1, 2, 3]).toContain(2)
expect([{ id: 1 }]).toContainEqual({ id: 1 })
expect([1, 2, 3]).toEqual(expect.arrayContaining([1, 3]))

Object Matchers

MatcherChecks
.toMatchObject(obj)Object contains at least the given subset
.toHaveProperty(keyPath, val?)Property exists (optional value check)
expect({ a: 1, b: 2 }).toMatchObject({ a: 1 })
expect({ user: { id: 1 } }).toHaveProperty('user.id', 1)
expect({ arr: [1, 2] }).toHaveProperty('arr[0]', 1)

Error / Exception Matchers

MatcherChecks
.toThrow()Function throws anything
.toThrow(str)Thrown message contains string
.toThrow(regex)Thrown message matches regex
.toThrow(ErrorClass)Thrown instance of class
.toThrowError(...)Alias for .toThrow
.rejects.toThrow(...)Async function rejects
expect(() => { throw new Error('oops') }).toThrow('oops')
expect(() => fn()).toThrow(TypeError)

await expect(asyncFn()).rejects.toThrow('network error')
await expect(asyncFn()).rejects.toBeInstanceOf(Error)

Wrap the call in an arrow function: expect(() => fn()) not expect(fn()).

Promise Matchers

await expect(Promise.resolve(42)).resolves.toBe(42)
await expect(Promise.reject(new Error('x'))).rejects.toThrow('x')

Function / Spy Matchers

MatcherChecks
.toHaveBeenCalled()Called at least once
.toHaveBeenCalledTimes(n)Called exactly n times
.toHaveBeenCalledWith(...args)Last call had these args
.toHaveBeenLastCalledWith(...args)Alias for above
.toHaveBeenNthCalledWith(n, ...args)nth call had these args
.toHaveReturnedWith(val)Returned this value
.toHaveReturnedTimes(n)Returned (not thrown) n times
.toHaveLastReturnedWith(val)Last return value
const fn = vi.fn().mockReturnValue(42)
fn('a', 'b')

expect(fn).toHaveBeenCalledWith('a', 'b')
expect(fn).toHaveBeenCalledTimes(1)
expect(fn).toHaveReturnedWith(42)

Asymmetric Matchers (expect.*)

Asymmetric MatcherMeaning
expect.any(Constructor)Any instance of type
expect.anything()Anything except null/undefined
expect.arrayContaining([...])Superset of given array
expect.objectContaining({...})Superset of given object
expect.stringContaining(str)String containing substring
expect.stringMatching(regex)String matching regex
expect.not.arrayContaining([...])Negated version
expect({ id: expect.any(Number), name: 'Alice' }).toMatchObject({
  id: expect.any(Number),
  name: expect.stringContaining('Ali'),
})

expect(fn).toHaveBeenCalledWith(
  expect.objectContaining({ userId: expect.any(String) })
)

Custom Matchers

import { expect } from 'vitest'

expect.extend({
  toBeWithinRange(received: number, min: number, max: number) {
    const pass = received >= min && received <= max
    return {
      pass,
      message: () =>
        `expected ${received} to${pass ? ' not' : ''} be within [${min}, ${max}]`,
    }
  },
})

// Usage:
expect(50).toBeWithinRange(1, 100)

Add TypeScript types by augmenting interface Assertion in a .d.ts file.

expect.assertions / expect.hasAssertions

it('must run the callback assertion', async () => {
  expect.assertions(1) // exactly 1 assertion must run
  await new Promise<void>((resolve) => {
    asyncFn((result) => {
      expect(result).toBe('ok')
      resolve()
    })
  })
})

it('at least one assertion runs', async () => {
  expect.hasAssertions()
  await expect(asyncFn()).resolves.toBeDefined()
})

Soft Assertions

it('reports all failures', () => {
  expect.soft(1).toBe(2)    // fails but continues
  expect.soft(3).toBe(3)    // passes
  expect.soft('a').toBe('b') // fails but continues
  // all soft failures thrown at end of test
})