Expect

expect is used to assert values in tests. It provides a rich set of matchers, supports chainable modifiers, soft assertions, polling, and snapshot testing.

expect

  • Type: <T>(actual: T, message?: string) => Assertion<T>

Creates an assertion object for the given value.

import { expect } from '@rstest/core';

expect(1 + 1).toBe(2);
expect('hello').toBeDefined();
expect([1, 2, 3]).toContain(2);

expect.not

Negates the assertion.

expect(1 + 1).not.toBe(3);
expect('foo').not.toBeUndefined();

expect.soft

  • Type: <T>(actual: T, message?: string) => Assertion<T>

Performs a soft assertion. The test will continue even if the assertion fails, and all failures will be reported at the end.

expect.soft(1 + 1).toBe(3); // will not stop the test
expect.soft(1 + 2).toBe(4);

expect.poll

  • Type: <T>(actual: () => T, options?: { interval?: number, timeout?: number, message?: string }) => Assertion<T>

Polls the value returned by the function until the assertion passes or timeout.

await expect.poll(() => getStatus()).toBe('ready');

expect.unreachable

  • Type: (message?: string) => never

Marks a code path as unreachable. Throws if called.

if (shouldNotHappen) {
  expect.unreachable('This should never happen');
}

expect.assertions

  • Type: (expected: number) => void

Asserts that a certain number of assertions are called during a test.

expect.assertions(2);
expect(1 + 1).toBe(2);
expect(2 + 2).toBe(4);

expect.hasAssertions

  • Type: () => void

Asserts that at least one assertion is called during a test.

expect.hasAssertions();
expect(1 + 1).toBe(2);

expect.addEqualityTesters

  • Type: (testers: Array<Tester>) => void

Adds custom equality testers for use in assertions.

expect.addEqualityTesters([
  (a, b) => {
    if (typeof a === 'number' && typeof b === 'number') {
      return Math.abs(a - b) < 0.01;
    }
  },
]);
expect(0.1 + 0.2).toEqual(0.3); // true with custom tester

expect.addSnapshotSerializer

  • Type: (serializer: SnapshotSerializer) => void

Adds a custom serializer for snapshot testing.

expect.addSnapshotSerializer({
  test: (val) => typeof val === 'string' && val.startsWith('secret:'),
  print: (val) => '***MASKED***',
});
expect('secret:123').toMatchSnapshot(); // snapshot will be masked

expect.getState / expect.setState

  • Type:
    • getState: () => MatcherState
    • setState: (state: Partial<MatcherState>) => void

Gets or sets the internal matcher state.

const state = expect.getState();
console.log(state.currentTestName);
expect.setState({ currentTestName: 'custom name' });
console.log(expect.getState().currentTestName); // will output 'custom name'

Matchers

Common matchers

Common matchers are used to assert basic value comparisons, type checks, and structure checks. They cover most day-to-day assertions for numbers, strings, objects, arrays, and more.

  • toBe(value). Checks strict equality using Object.is.
  • toEqual(value). Checks deep equality (recursively checks all fields).
  • toStrictEqual(value). Checks deep equality, including undefined properties and array sparseness.
  • toBeTruthy(). Checks if the value is truthy.
  • toBeFalsy(). Checks if the value is falsy.
  • toBeNull(). Checks if the value is null.
  • toBeUndefined(). Checks if the value is undefined.
  • toBeDefined(). Checks if the value is not undefined.
  • toBeNaN(). Checks if the value is NaN.
  • toBeGreaterThan(number). Checks if the value is greater than the given number.
  • toBeGreaterThanOrEqual(number). Checks if the value is greater than or equal to the given number.
  • toBeLessThan(number). Checks if the value is less than the given number.
  • toBeLessThanOrEqual(number). Checks if the value is less than or equal to the given number.
  • toBeCloseTo(number, numDigits?). Checks if a number is close to another number, optionally with a given precision.
  • toContain(item). Checks if an array or string contains the given item.
  • toContainEqual(item). Checks if an array contains an item (using deep equality).
  • toMatch(stringOrRegExp). Checks if a string matches a regex or substring.
  • toMatchObject(object). Checks if an object matches a subset of properties.
  • toHaveLength(length). Checks if an object has a .length property with the given value.
  • toHaveProperty(path, value?). Checks if an object has a property at the given path, optionally with a specific value.
  • toBeInstanceOf(class). Checks if the value is an instance of the given class.
  • toBeTypeOf(type). Checks if the value is of the given type (e.g. 'string').
  • toSatisfy(fn). Checks if the value satisfies the provided function.
  • toBeOneOf(array). Checks if the value is one of the values in the given array.
  • toThrowError(expected?). Checks if a function throws an error, optionally matching the error message or type.
// Equality
expect(1 + 1).toBe(2);
expect({ a: 1 }).toEqual({ a: 1 });
expect([1, undefined]).toStrictEqual([1, undefined]);
expect(2).toBeOneOf([1, 2, 3]);

// Type & Definition
expect(null).toBeNull();
expect(undefined).toBeUndefined();
expect('foo').toBeDefined();
expect('bar').toBeTypeOf('string');
expect(new Date()).toBeInstanceOf(Date);
expect(NaN).toBeNaN();
expect('hello').toBeTruthy();
expect('').toBeFalsy();

// Number Comparison
expect(5).toBeGreaterThan(3);
expect(5).toBeGreaterThanOrEqual(5);
expect(3).toBeLessThan(5);
expect(3).toBeLessThanOrEqual(3);
expect(0.1 + 0.2).toBeCloseTo(0.3, 5);

// Array / Object / String
expect([1, 2, 3]).toContain(2);
expect([{ a: 1 }]).toContainEqual({ a: 1 });
expect('hello world').toMatch(/world/);
expect({ a: 1, b: 2 }).toMatchObject({ a: 1 });
expect('abc').toHaveLength(3);
expect({ foo: { bar: 1 } }).toHaveProperty('foo.bar', 1);

// Function / Exception
expect(() => {
  throw new Error('fail');
}).toThrowError('fail');
expect(3).toSatisfy((x) => x % 3 === 0 || x % 3 === 1);

Mock matchers

Mock matchers are used to assert how mock functions (created by rstest.fn or rstest.spyOn) are called, what they return, and their call order. They are essential for verifying function interactions in unit tests.

  • toHaveBeenCalled(). Checks if a mock function was called at least once.
  • toHaveBeenCalledTimes(times). Checks if a mock function was called a specific number of times.
  • toHaveBeenCalledWith(...args). Checks if a mock function was called with specific arguments.
  • toHaveBeenCalledBefore(mock). Checks if a mock was called before another mock.
  • toHaveBeenCalledAfter(mock). Checks if a mock was called after another mock.
  • toHaveBeenCalledExactlyOnceWith(...args). Checks if a mock was called exactly once with specific arguments.
  • toHaveBeenLastCalledWith(...args). Checks if a mock was last called with specific arguments.
  • toHaveBeenNthCalledWith(n, ...args). Checks if a mock was called with specific arguments on the nth call.
  • toHaveReturned(). Checks if a mock function returned at least once.
  • toHaveReturnedTimes(times). Checks if a mock function returned a specific number of times.
  • toHaveReturnedWith(value). Checks if a mock function returned a specific value.
  • toHaveLastReturnedWith(value). Checks if a mock function last returned a specific value.
  • toHaveNthReturnedWith(n, value). Checks if a mock function returned a specific value on the nth call.
  • toHaveResolved(). Checks if a promise resolved at least once.
  • toHaveResolvedTimes(times). Checks if a promise resolved a specific number of times.
  • toHaveResolvedWith(value). Checks if a promise resolved with a specific value.
  • toHaveLastResolvedWith(value). Checks if a promise last resolved with a specific value.
  • toHaveNthResolvedWith(n, value). Checks if a promise resolved with a specific value on the nth call.
const mockFn = rstest.fn((x) => x + 1);
mockFn(1);

expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith(1);

Snapshot matchers

Snapshot matchers are used to compare values, errors, or files against previously recorded snapshots, making it easy to track changes in output over time.

  • toMatchSnapshot(). Compares the value to a saved snapshot.
  • toMatchInlineSnapshot(). Compares the value to an inline snapshot in the test file.
  • toThrowErrorMatchingSnapshot(). Checks if a thrown error matches a saved snapshot.
  • toThrowErrorMatchingInlineSnapshot(). Checks if a thrown error matches an inline snapshot in the test file.
  • toMatchFileSnapshot(filepath). Compares the value to a snapshot saved in a specific file.
expect('hello world').toMatchSnapshot();

expect(() => {
  throw new Error('fail');
}).toThrowErrorMatchingSnapshot();

Promise matchers

  • resolves. Asserts on the resolved value of a Promise.
  • rejects. Asserts on the rejected value of a Promise.
await expect(Promise.resolve('ok')).resolves.toBe('ok');
await expect(Promise.reject(new Error('fail'))).rejects.toThrow('fail');

Asymmetric matchers

Asymmetric matchers are helpers that allow for flexible matching of values, such as partial matches, type matches, or pattern matches. They are useful for writing more expressive and less brittle tests.

  • expect.anything(). Matches any value except null or undefined.
  • expect.any(constructor). Matches any value of the given type.
  • expect.closeTo(number, precision?). Matches a number close to the expected value.
  • expect.arrayContaining(array). Matches an array containing the expected elements.
  • expect.objectContaining(object). Matches an object containing the expected properties.
  • expect.stringContaining(string). Matches a string containing the expected substring.
  • expect.stringMatching(stringOrRegExp). Matches a string matching the expected pattern.
expect({ a: 1 }).toEqual({ a: expect.anything() });

expect(1).toEqual(expect.any(Number));

expect(0.1 + 0.2).toEqual(expect.closeTo(0.3, 5));

expect([1, 2, 3]).toEqual(expect.arrayContaining([2, 1]));

expect({ a: 1, b: 2 }).toEqual(expect.objectContaining({ a: 1 }));

expect('hello world').toEqual(expect.stringContaining('world'));

expect('hello world').toEqual(expect.stringMatching(/^hello/));

Custom matchers

You can extend expect with custom matchers:

expect.extend({
  toBeDivisibleBy(received, argument) {
    const pass = received % argument === 0;
    if (pass) {
      return {
        message: () =>
          `expected ${received} not to be divisible by ${argument}`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be divisible by ${argument}`,
        pass: false,
      };
    }
  },
});

expect(10).toBeDivisibleBy(2);