0
# Hardhat Chai Matchers
1
2
Hardhat 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.
3
4
## Package Information
5
6
- **Package Name**: @nomicfoundation/hardhat-chai-matchers
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install --save-dev @nomicfoundation/hardhat-chai-matchers`
10
11
## Core Imports
12
13
```typescript
14
// Import the plugin in your Hardhat configuration
15
require("@nomicfoundation/hardhat-chai-matchers");
16
17
// Import utilities for argument matching
18
import { anyValue, anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
19
20
// Import panic codes for revert testing
21
import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";
22
```
23
24
## Basic Usage
25
26
```typescript
27
import { expect } from "chai";
28
import { ethers } from "hardhat";
29
30
// After importing the plugin, new matchers are available on Chai expectations
31
describe("Token Contract", function () {
32
it("should transfer tokens", async function () {
33
const [owner, recipient] = await ethers.getSigners();
34
const Token = await ethers.getContractFactory("Token");
35
const token = await Token.deploy(1000000);
36
37
// Test successful transfer and event emission
38
await expect(token.transfer(recipient.address, 1000))
39
.to.emit(token, "Transfer")
40
.withArgs(owner.address, recipient.address, 1000);
41
42
// Test balance changes
43
await expect(token.transfer(recipient.address, 500))
44
.to.changeTokenBalance(token, recipient, 500);
45
});
46
47
it("should handle reverts", async function () {
48
// Test transaction reverts with specific reasons
49
await expect(token.transfer(ethers.ZeroAddress, 1000))
50
.to.be.revertedWith("Cannot transfer to zero address");
51
52
// Test custom error reverts
53
await expect(token.transferFrom(owner.address, recipient.address, 1000))
54
.to.be.revertedWithCustomError(token, "InsufficientAllowance");
55
});
56
});
57
```
58
59
## Architecture
60
61
Hardhat Chai Matchers is built around extending Chai's assertion interface with Ethereum-specific matchers:
62
63
- **Chai Extensions**: All matchers extend the global Chai.Assertion interface via TypeScript declaration merging
64
- **Async Matchers**: Most matchers return AsyncAssertion promises for testing transaction results
65
- **Chainable Interface**: Some matchers like `.emit()` and `.revertedWithCustomError()` support chaining with `.withArgs()`
66
- **Integration Layer**: Seamless integration with Hardhat, ethers.js, and Chai testing framework
67
68
## Capabilities
69
70
### Transaction Revert Testing
71
72
Comprehensive matchers for testing different types of transaction failures including generic reverts, reason strings, custom errors, and panic conditions.
73
74
```typescript { .api }
75
interface Assertion {
76
reverted: AsyncAssertion;
77
revertedWith(reason: string | RegExp): AsyncAssertion;
78
revertedWithoutReason(): AsyncAssertion;
79
revertedWithPanic(code?: any): AsyncAssertion;
80
revertedWithCustomError(contract: { interface: any }, customErrorName: string): CustomErrorAssertion;
81
}
82
```
83
84
[Transaction Revert Testing](./revert-matchers.md)
85
86
### Event Emission Testing
87
88
Matchers for verifying that transactions emit specific events with expected arguments, supporting complex event validation scenarios.
89
90
```typescript { .api }
91
interface Assertion {
92
emit(contract: any, eventName: string): EmitAssertion;
93
}
94
95
interface EmitAssertion extends AsyncAssertion {
96
withArgs(...args: any[]): AsyncAssertion;
97
}
98
```
99
100
[Event Emission Testing](./event-matchers.md)
101
102
### Balance Change Testing
103
104
Matchers for testing ETH and ERC-20 token balance changes during transaction execution, supporting both single and multiple account scenarios.
105
106
```typescript { .api }
107
interface Assertion {
108
changeEtherBalance(account: any, balance: any, options?: any): AsyncAssertion;
109
changeEtherBalances(accounts: any[], balances: any[] | ((changes: bigint[]) => boolean), options?: any): AsyncAssertion;
110
changeTokenBalance(token: any, account: any, balance: any): AsyncAssertion;
111
changeTokenBalances(token: any, accounts: any[], balances: any[] | ((changes: bigint[]) => boolean)): AsyncAssertion;
112
}
113
```
114
115
[Balance Change Testing](./balance-matchers.md)
116
117
### Data Validation
118
119
Matchers for validating Ethereum-specific data formats including addresses, private keys, and hex strings.
120
121
```typescript { .api }
122
interface Assertion {
123
hexEqual(other: string): void;
124
properPrivateKey: void;
125
properAddress: void;
126
properHex(length: number): void;
127
}
128
```
129
130
[Data Validation](./validation-matchers.md)
131
132
### Argument Matching Utilities
133
134
Helper functions for flexible argument matching in event and error testing scenarios.
135
136
```typescript { .api }
137
function anyValue(): boolean;
138
function anyUint(i: any): boolean;
139
```
140
141
[Argument Matching Utilities](./argument-utilities.md)
142
143
### BigNumber Support
144
145
Enhanced comparison operators that support ethers BigInt and other BigNumber types alongside regular JavaScript numbers.
146
147
```typescript { .api }
148
interface NumericComparison {
149
within(start: any, finish: any, message?: string): Assertion;
150
}
151
152
// Enhanced operators: equal, above, below, least, most, closeTo
153
// All support BigInt/BigNumber comparisons automatically
154
```
155
156
[BigNumber Support](./bignumber-support.md)
157
158
### Panic Codes
159
160
Constants and utilities for testing Solidity panic conditions and arithmetic errors.
161
162
```typescript { .api }
163
const PANIC_CODES: {
164
ASSERTION_ERROR: 0x1;
165
ARITHMETIC_OVERFLOW: 0x11;
166
DIVISION_BY_ZERO: 0x12;
167
ENUM_CONVERSION_OUT_OF_BOUNDS: 0x21;
168
INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY: 0x22;
169
POP_ON_EMPTY_ARRAY: 0x31;
170
ARRAY_ACCESS_OUT_OF_BOUNDS: 0x32;
171
TOO_MUCH_MEMORY_ALLOCATED: 0x41;
172
ZERO_INITIALIZED_VARIABLE: 0x51;
173
};
174
```
175
176
[Panic Codes](./panic-codes.md)
177
178
## Types
179
180
```typescript { .api }
181
interface AsyncAssertion extends Assertion, Promise<void> {}
182
183
interface EmitAssertion extends AsyncAssertion {
184
withArgs(...args: any[]): AsyncAssertion;
185
}
186
187
interface CustomErrorAssertion extends AsyncAssertion {
188
withArgs(...args: any[]): AsyncAssertion;
189
}
190
```