Skip to content

Function & Error Matchers

toThrow asserts that calling a function throws. Pass the function itself - not its result - so the matcher can invoke it and catch the error.

toThrow

Checks that a function throws when called, optionally matching the thrown error.

ts
xExpect(fn).toThrow(expected?);

Supports asymmetric matchers

expected accepts asymmetric matchers such as xExpect.objectContaining().

expected is optional and selects how the thrown error is matched:

expectedMatches when
(omitted)The function throws anything
ConstructorThe error is an instance of that class
StringThe substring appears in the error message
RegExpThe pattern tests true against the error message
ObjectThe thrown value matches the object

Pass a function, not a value

toThrow needs to call the code itself. Wrap the call in an arrow function - xExpect(() => parse(x)).toThrow(). Writing xExpect(parse(x)) throws before the matcher runs.

Any error

ts
xExpect(() => { throw new Error('oops'); }).toThrow();
xExpect(() => 'ok').not.toThrow();

By error type

ts
xExpect(() => { throw new TypeError('invalid type'); }).toThrow(TypeError);
xExpect(() => { throw new Error('oops'); }).not.toThrow(SyntaxError);

class ValidationError extends Error {}
xExpect(() => { throw new ValidationError('invalid data'); }).toThrow(ValidationError);

By message

ts
xExpect(() => { throw new Error('invalid password'); }).toThrow('password');
xExpect(() => { throw new Error('File not found'); }).toThrow('not found');

By pattern

ts
xExpect(() => { throw new Error('Code: 404, Not Found'); }).toThrow(/Code: \d+/);

By shape

ts
// Plain thrown object
xExpect(() => {
    throw { code: 'AUTH_FAILED', message: 'Invalid credentials' };
}).toThrow({ code: 'AUTH_FAILED', message: 'Invalid credentials' });

// Error matched partially with an asymmetric matcher
xExpect(() => {
    throw new Error('Permission denied');
}).toThrow(xExpect.objectContaining({
    name: 'Error',
    message: 'Permission denied',
    stack: xExpect.any(String)
}));

With Promises

Combine toThrow with the .rejects modifier to assert on a rejected Promise.

ts
await xExpect(Promise.reject(new Error('Failed'))).rejects.toThrow('Failed');
await xExpect(Promise.reject(new TypeError('Type error'))).rejects.toThrow(TypeError);

Common patterns

ts
test('validateEmail throws for invalid emails', () => {
    xExpect(() => validateEmail('')).toThrow('Email cannot be empty');
    xExpect(() => validateEmail('invalid')).toThrow('Invalid email format');
    xExpect(() => validateEmail('user@example.com')).not.toThrow();
});

test('database operations throw specific errors', () => {
    class DatabaseError extends Error {
        constructor(message: string, public code: string) {
            super(message);
            this.name = 'DatabaseError';
        }
    }

    const connect = (): never => {
        throw new DatabaseError('Connection failed', 'DB_CONN_ERROR');
    };

    xExpect(connect).toThrow(DatabaseError);
    xExpect(connect).toThrow('Connection failed');
    xExpect(connect).toThrow(xExpect.objectContaining({ code: 'DB_CONN_ERROR' }));
});

See also

Released under the Mozilla Public License 2.0