Jest Matcher Utilities
jest-matcher-utils provides a collection of helper functions used internally by Jest and exposed for developers creating custom matchers. These utilities facilitate consistent formatting and error reporting within Jest's `expect` assertions. The package is part of the larger Jest monorepo, which is currently stable at version 30.3.0, with major releases occurring every few years (Jest 30 was released after three years, with a stated aim for more frequent future majors). It's actively maintained, with frequent patch and minor updates addressing bug fixes, performance improvements, and new features across the Jest ecosystem. Its primary differentiation lies in providing the exact formatting and utility logic that Jest itself uses, ensuring seamless integration and a consistent user experience when extending Jest's assertion capabilities. This includes functions for printing values, generating matcher hints, and handling object comparisons, crucial for building custom assertion logic that feels native to Jest.
Common errors
-
TypeError: (0, _jestMatcherUtils.matcherHint) is not a function
cause This typically occurs when mixing CommonJS `require()` syntax with ESM-first packages, or when incorrect destructuring is applied in a CommonJS context to an ESM export. It can also happen if `jest-matcher-utils` is loaded in an unexpected way.fixEnsure you are using `import { matcherHint } from 'jest-matcher-utils';` for ESM environments (e.g., in `package.json` with `"type": "module"` or when using bundlers). If strictly using CommonJS, verify the module's compatibility or adjust import syntax if it's a dual-package. -
MatcherResult must be an object with a `pass` boolean property.
cause Your custom matcher function is not returning an object with a `pass` property (which must be a boolean) and typically a `message` property (which must be a function). This is a fundamental requirement for all Jest custom matchers.fixReview your custom matcher implementation. Ensure it returns an object like `{ pass: boolean; message: () => string; }`. For example: `return { pass: true, message: () => '...' };`
Warnings
- breaking Jest 30 introduced substantial changes across the entire Jest ecosystem. While `jest-matcher-utils` specifically might not have had direct breaking API changes, upgrading Jest to v30.0.0 or later requires reviewing the general Jest migration guide, which may indirectly impact custom matchers or test setups.
- gotcha In Jest v30.0.2, the `deepCyclicCopyObject` utility (used internally and potentially in advanced custom matchers) was made safer by setting descriptors to a null-prototype object. If you had custom logic relying on specific behaviors of deep copying or encountered issues with deeply nested objects in earlier 30.x versions, this fix might subtly change behavior or resolve previous edge cases.
Install
-
npm install jest-matcher-utils -
yarn add jest-matcher-utils -
pnpm add jest-matcher-utils
Imports
- matcherHint
const { matcherHint } = require('jest-matcher-utils')import { matcherHint } from 'jest-matcher-utils' - printReceived
import { printReceived } from 'jest-matcher-utils/dist/printReceived'import { printReceived } from 'jest-matcher-utils' - EXPECTED_COLOR
import { EXPECTED_COLOR } from 'jest-matcher-utils'
Quickstart
import { matcherHint, printReceived, printExpected, EXPECTED_COLOR, RECEIVED_COLOR } from 'jest-matcher-utils';
import { expect } from '@jest/globals'; // Or global 'expect' if configured
declare global {
namespace jest {
interface Matchers<R> {
toBeDivisibleBy(divisor: number): R;
}
}
}
expect.extend({
toBeDivisibleBy(received: number, argument: number) {
const pass = received % argument === 0;
const message = () =>
matcherHint('.toBeDivisibleBy', 'received', 'argument') +
'\n\n' +
`Expected: ${EXPECTED_COLOR(argument)}\n` +
`Received: ${pass ? printReceived(received) : RECEIVED_COLOR(received)}`;
if (pass) {
return {
message,
pass: true,
};
} else {
return {
message,
pass: false,
};
}
},
});
describe('toBeDivisibleBy', () => {
test('should pass if the number is divisible', () => {
expect(4).toBeDivisibleBy(2);
});
test('should fail if the number is not divisible', () => {
expect(() => expect(5).toBeDivisibleBy(2)).toThrowErrorMatchingSnapshot();
});
});