Ethereum-specific Chai assertion matchers for smart contract testing in Hardhat development environment.
npx @tessl/cli install tessl/npm-nomicfoundation--hardhat-chai-matchers@2.1.0Hardhat Chai Matchers extends the Chai assertion library with Ethereum-specific capabilities for smart contract testing. It provides specialized matchers for testing transaction reverts, event emissions, balance changes, and Ethereum-specific data validation, making smart contract tests more readable and comprehensive.
npm install --save-dev @nomicfoundation/hardhat-chai-matchers// Import the plugin in your Hardhat configuration
require("@nomicfoundation/hardhat-chai-matchers");
// Import utilities for argument matching
import { anyValue, anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
// Import panic codes for revert testing
import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";import { expect } from "chai";
import { ethers } from "hardhat";
// After importing the plugin, new matchers are available on Chai expectations
describe("Token Contract", function () {
it("should transfer tokens", async function () {
const [owner, recipient] = await ethers.getSigners();
const Token = await ethers.getContractFactory("Token");
const token = await Token.deploy(1000000);
// Test successful transfer and event emission
await expect(token.transfer(recipient.address, 1000))
.to.emit(token, "Transfer")
.withArgs(owner.address, recipient.address, 1000);
// Test balance changes
await expect(token.transfer(recipient.address, 500))
.to.changeTokenBalance(token, recipient, 500);
});
it("should handle reverts", async function () {
// Test transaction reverts with specific reasons
await expect(token.transfer(ethers.ZeroAddress, 1000))
.to.be.revertedWith("Cannot transfer to zero address");
// Test custom error reverts
await expect(token.transferFrom(owner.address, recipient.address, 1000))
.to.be.revertedWithCustomError(token, "InsufficientAllowance");
});
});Hardhat Chai Matchers is built around extending Chai's assertion interface with Ethereum-specific matchers:
.emit() and .revertedWithCustomError() support chaining with .withArgs()Comprehensive matchers for testing different types of transaction failures including generic reverts, reason strings, custom errors, and panic conditions.
interface Assertion {
reverted: AsyncAssertion;
revertedWith(reason: string | RegExp): AsyncAssertion;
revertedWithoutReason(): AsyncAssertion;
revertedWithPanic(code?: any): AsyncAssertion;
revertedWithCustomError(contract: { interface: any }, customErrorName: string): CustomErrorAssertion;
}Matchers for verifying that transactions emit specific events with expected arguments, supporting complex event validation scenarios.
interface Assertion {
emit(contract: any, eventName: string): EmitAssertion;
}
interface EmitAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}Matchers for testing ETH and ERC-20 token balance changes during transaction execution, supporting both single and multiple account scenarios.
interface Assertion {
changeEtherBalance(account: any, balance: any, options?: any): AsyncAssertion;
changeEtherBalances(accounts: any[], balances: any[] | ((changes: bigint[]) => boolean), options?: any): AsyncAssertion;
changeTokenBalance(token: any, account: any, balance: any): AsyncAssertion;
changeTokenBalances(token: any, accounts: any[], balances: any[] | ((changes: bigint[]) => boolean)): AsyncAssertion;
}Matchers for validating Ethereum-specific data formats including addresses, private keys, and hex strings.
interface Assertion {
hexEqual(other: string): void;
properPrivateKey: void;
properAddress: void;
properHex(length: number): void;
}Helper functions for flexible argument matching in event and error testing scenarios.
function anyValue(): boolean;
function anyUint(i: any): boolean;Enhanced comparison operators that support ethers BigInt and other BigNumber types alongside regular JavaScript numbers.
interface NumericComparison {
within(start: any, finish: any, message?: string): Assertion;
}
// Enhanced operators: equal, above, below, least, most, closeTo
// All support BigInt/BigNumber comparisons automaticallyConstants and utilities for testing Solidity panic conditions and arithmetic errors.
const PANIC_CODES: {
ASSERTION_ERROR: 0x1;
ARITHMETIC_OVERFLOW: 0x11;
DIVISION_BY_ZERO: 0x12;
ENUM_CONVERSION_OUT_OF_BOUNDS: 0x21;
INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY: 0x22;
POP_ON_EMPTY_ARRAY: 0x31;
ARRAY_ACCESS_OUT_OF_BOUNDS: 0x32;
TOO_MUCH_MEMORY_ALLOCATED: 0x41;
ZERO_INITIALIZED_VARIABLE: 0x51;
};interface AsyncAssertion extends Assertion, Promise<void> {}
interface EmitAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}
interface CustomErrorAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}