A comprehensive matcher library for Jest testing framework providing assertion utilities for test expectations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Matchers for testing error conditions and exception handling. These matchers are essential for verifying that functions throw appropriate errors and for testing error handling logic.
Tests that a function throws an error when called. Can optionally verify the error message, error type, or error pattern.
/**
* Checks if function throws an error, optionally matching type, message, or pattern
* @param expected - Optional: Error constructor, error message string, or RegExp pattern
*/
ExpectationObject.toThrow(expected?: string | Error | RegExp): void;Usage Examples:
// Test that a function throws any error
expect(() => {
throw new Error('Something went wrong');
}).toThrow();
// Test that a function throws with specific message
expect(() => {
throw new Error('Invalid input');
}).toThrow('Invalid input');
// Test with partial message matching
expect(() => {
throw new Error('Database connection failed: timeout');
}).toThrow('Database connection failed');
// Test with regex pattern
expect(() => {
throw new Error('User not found: ID 123');
}).toThrow(/User not found: ID \d+/);
// Test with Error constructor
expect(() => {
throw new TypeError('Expected string');
}).toThrow(TypeError);
// Test with specific Error instance
expect(() => {
throw new RangeError('Value out of range');
}).toThrow(new RangeError('Value out of range'));Alias for toThrow - functions identically.
/**
* Alias for toThrow - checks if function throws error
* @param expected - Optional: Error constructor, error message string, or RegExp pattern
*/
ExpectationObject.toThrowError(expected?: string | Error | RegExp): void;Usage Examples:
// All examples from toThrow work identically with toThrowError
expect(() => {
throw new Error('Something went wrong');
}).toThrowError();
expect(() => {
throw new Error('Invalid input');
}).toThrowError('Invalid input');
expect(() => {
throw new TypeError('Expected string');
}).toThrowError(TypeError);class ValidationError extends Error {
constructor(field, message) {
super(`Validation failed for ${field}: ${message}`);
this.name = 'ValidationError';
this.field = field;
}
}
class NetworkError extends Error {
constructor(statusCode, message) {
super(message);
this.name = 'NetworkError';
this.statusCode = statusCode;
}
}
function validateUser(userData) {
if (!userData.email) {
throw new ValidationError('email', 'Email is required');
}
if (!userData.email.includes('@')) {
throw new ValidationError('email', 'Invalid email format');
}
}
// Test specific error types
expect(() => validateUser({})).toThrow(ValidationError);
// Test error messages
expect(() => validateUser({})).toThrow('Validation failed for email: Email is required');
// Test with regex for flexible matching
expect(() => validateUser({email: 'invalid'})).toThrow(/Validation failed for email:/);
// Test that valid data doesn't throw
expect(() => validateUser({email: 'user@example.com'})).not.toThrow();// Testing async functions that throw
async function fetchUserData(userId) {
if (!userId) {
throw new Error('User ID is required');
}
if (userId < 0) {
throw new RangeError('User ID must be positive');
}
// fetch implementation...
}
// Use await expect for async functions
await expect(async () => {
await fetchUserData();
}).rejects.toThrow('User ID is required');
await expect(async () => {
await fetchUserData(-1);
}).rejects.toThrow(RangeError);
// Alternative syntax
expect(fetchUserData()).rejects.toThrow('User ID is required');
expect(fetchUserData(-1)).rejects.toThrow(RangeError);function processData(data) {
return new Promise((resolve, reject) => {
if (!data) {
reject(new Error('No data provided'));
} else if (data.invalid) {
reject(new ValidationError('data', 'Invalid data structure'));
} else {
resolve(data);
}
});
}
// Test promise rejections
await expect(processData()).rejects.toThrow('No data provided');
await expect(processData({invalid: true})).rejects.toThrow(ValidationError);
// Test successful resolution
await expect(processData({valid: true})).resolves.toEqual({valid: true});class ApiClient {
async request(endpoint, options = {}) {
if (!endpoint) {
throw new Error('Endpoint is required');
}
if (options.timeout && options.timeout < 0) {
throw new RangeError('Timeout must be positive');
}
// Simulate network error
if (endpoint.includes('unavailable')) {
throw new NetworkError(503, 'Service unavailable');
}
return {data: 'success'};
}
}
const client = new ApiClient();
// Test various error conditions
await expect(() => client.request()).rejects.toThrow('Endpoint is required');
await expect(() =>
client.request('/api/data', {timeout: -1})
).rejects.toThrow(RangeError);
await expect(() =>
client.request('/api/unavailable')
).rejects.toThrow(NetworkError);
await expect(() =>
client.request('/api/unavailable')
).rejects.toThrow('Service unavailable');
// Test successful case
await expect(client.request('/api/data')).resolves.toEqual({data: 'success'});function safeParseJSON(jsonString) {
try {
return JSON.parse(jsonString);
} catch (error) {
throw new Error(`Invalid JSON: ${error.message}`);
}
}
function unsafeParseJSON(jsonString) {
return JSON.parse(jsonString); // Let SyntaxError bubble up
}
// Test wrapped error handling
expect(() => safeParseJSON('{')).toThrow('Invalid JSON:');
expect(() => safeParseJSON('{')).toThrow(/Invalid JSON:/);
// Test raw error bubbling
expect(() => unsafeParseJSON('{')).toThrow(SyntaxError);
expect(() => unsafeParseJSON('{')).toThrow('Unexpected end of JSON input');
// Test successful parsing
expect(() => safeParseJSON('{"valid": true}')).not.toThrow();
expect(safeParseJSON('{"valid": true}')).toEqual({valid: true});function divide(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Both arguments must be numbers');
}
if (b === 0) {
throw new Error('Division by zero');
}
if (!Number.isFinite(a) || !Number.isFinite(b)) {
throw new RangeError('Arguments must be finite numbers');
}
return a / b;
}
// Test type errors
expect(() => divide('5', 2)).toThrow(TypeError);
expect(() => divide(5, '2')).toThrow('Both arguments must be numbers');
// Test division by zero
expect(() => divide(10, 0)).toThrow('Division by zero');
// Test infinite numbers
expect(() => divide(Infinity, 5)).toThrow(RangeError);
expect(() => divide(5, NaN)).toThrow('Arguments must be finite numbers');
// Test successful operation
expect(() => divide(10, 2)).not.toThrow();
expect(divide(10, 2)).toBe(5);const ERROR_MESSAGES = {
en: {
REQUIRED_FIELD: 'This field is required',
INVALID_EMAIL: 'Please enter a valid email address'
},
es: {
REQUIRED_FIELD: 'Este campo es obligatorio',
INVALID_EMAIL: 'Por favor ingrese una dirección de correo válida'
}
};
function validateWithLocale(value, locale = 'en') {
if (!value) {
throw new Error(ERROR_MESSAGES[locale].REQUIRED_FIELD);
}
}
// Test different locales
expect(() => validateWithLocale('', 'en')).toThrow('This field is required');
expect(() => validateWithLocale('', 'es')).toThrow('Este campo es obligatorio');
// Test with regex for flexible matching
expect(() => validateWithLocale('', 'en')).toThrow(/required/i);
expect(() => validateWithLocale('', 'es')).toThrow(/obligatorio/i);Exception matchers support negation to test that functions do NOT throw:
function safeOperation(value) {
if (value > 0) {
return value * 2;
}
return 0;
}
expect(() => safeOperation(5)).not.toThrow();
expect(() => safeOperation(0)).not.toThrow();
expect(() => safeOperation(-1)).not.toThrow();
// Test that async functions don't reject
await expect(Promise.resolve('success')).resolves.not.toThrow();Exception matchers work seamlessly with promise-based testing:
// Test promise rejections
await expect(Promise.reject(new Error('Failed'))).rejects.toThrow('Failed');
await expect(Promise.reject(new TypeError('Type error'))).rejects.toThrow(TypeError);
// Test promise resolutions (should not throw)
await expect(Promise.resolve('success')).resolves.not.toThrow();