0
# Transaction Revert Testing
1
2
Comprehensive matchers for testing different types of transaction failures including generic reverts, reason strings, custom errors, and panic conditions.
3
4
## Capabilities
5
6
### Generic Revert Testing
7
8
Tests if a transaction reverted for any reason without checking the specific cause.
9
10
```typescript { .api }
11
/**
12
* Tests if a transaction reverted for any reason
13
* @returns AsyncAssertion promise that resolves if transaction reverted
14
*/
15
reverted: AsyncAssertion;
16
```
17
18
**Usage Example:**
19
20
```typescript
21
import { expect } from "chai";
22
23
// Test that transaction reverts for any reason
24
await expect(contract.failingFunction()).to.be.reverted;
25
26
// Test that transaction does NOT revert
27
await expect(contract.successfulFunction()).to.not.be.reverted;
28
```
29
30
### Revert with Reason String
31
32
Tests if a transaction reverted with a specific reason string, supporting both exact string matches and regular expressions.
33
34
```typescript { .api }
35
/**
36
* Tests if transaction reverted with specific reason string
37
* @param reason - Expected revert reason as string or RegExp
38
* @returns AsyncAssertion promise that resolves if reason matches
39
*/
40
revertedWith(reason: string | RegExp): AsyncAssertion;
41
```
42
43
**Usage Examples:**
44
45
```typescript
46
// Test exact reason string
47
await expect(contract.transfer(ethers.ZeroAddress, 100))
48
.to.be.revertedWith("Cannot transfer to zero address");
49
50
// Test with regular expression
51
await expect(contract.withdraw(1000))
52
.to.be.revertedWith(/insufficient.*balance/i);
53
54
// Test negation
55
await expect(contract.validTransfer())
56
.to.not.be.revertedWith("Insufficient balance");
57
```
58
59
### Revert without Reason
60
61
Tests if a transaction reverted without providing any reason string.
62
63
```typescript { .api }
64
/**
65
* Tests if transaction reverted without a reason string
66
* @returns AsyncAssertion promise that resolves if reverted without reason
67
*/
68
revertedWithoutReason(): AsyncAssertion;
69
```
70
71
**Usage Example:**
72
73
```typescript
74
// Test transaction reverts with no reason
75
await expect(contract.lowLevelCall()).to.be.revertedWithoutReason();
76
77
// Test transaction provides a reason (negation)
78
await expect(contract.revertWithMessage())
79
.to.not.be.revertedWithoutReason();
80
```
81
82
### Revert with Panic Code
83
84
Tests if a transaction reverted due to a Solidity panic condition, optionally checking for specific panic codes.
85
86
```typescript { .api }
87
/**
88
* Tests if transaction reverted with a panic code
89
* @param code - Optional specific panic code to match
90
* @returns AsyncAssertion promise that resolves if panic code matches
91
*/
92
revertedWithPanic(code?: any): AsyncAssertion;
93
```
94
95
**Usage Examples:**
96
97
```typescript
98
import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";
99
100
// Test any panic condition
101
await expect(contract.divideByZero()).to.be.revertedWithPanic();
102
103
// Test specific panic code
104
await expect(contract.divideByZero())
105
.to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);
106
107
// Test arithmetic overflow
108
await expect(contract.overflow())
109
.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);
110
111
// Test array access out of bounds
112
await expect(contract.accessInvalidIndex())
113
.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
114
```
115
116
### Revert with Custom Error
117
118
Tests if a transaction reverted with a specific custom error defined in the contract, with support for argument validation.
119
120
```typescript { .api }
121
/**
122
* Tests if transaction reverted with a specific custom error
123
* @param contract - Contract object with interface containing the error definition
124
* @param customErrorName - Name of the custom error
125
* @returns CustomErrorAssertion that can be chained with withArgs()
126
*/
127
revertedWithCustomError(
128
contract: { interface: any },
129
customErrorName: string
130
): CustomErrorAssertion;
131
```
132
133
**Usage Examples:**
134
135
```typescript
136
// Test custom error without arguments
137
await expect(contract.withdraw(1000))
138
.to.be.revertedWithCustomError(contract, "InsufficientBalance");
139
140
// Test custom error with specific arguments
141
await expect(contract.transfer(recipient, 1000))
142
.to.be.revertedWithCustomError(contract, "TransferFailed")
143
.withArgs(recipient, 1000);
144
145
// Test custom error with any value matching
146
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
147
148
await expect(contract.complexOperation())
149
.to.be.revertedWithCustomError(contract, "OperationFailed")
150
.withArgs(anyValue, 404);
151
```
152
153
## Important Limitations
154
155
**Chaining Restrictions**: The revert matchers do not support chaining with other async matchers. Use separate assertions:
156
157
```typescript
158
// ❌ This won't work
159
await expect(contract.transfer(recipient, 1000))
160
.to.be.revertedWith("Insufficient balance")
161
.and.to.changeEtherBalance(owner, -1000);
162
163
// ✅ Use separate assertions instead
164
const tx = contract.transfer(recipient, 1000);
165
await expect(tx).to.be.revertedWith("Insufficient balance");
166
await expect(tx).to.changeEtherBalance(owner, -1000);
167
```
168
169
## Types
170
171
```typescript { .api }
172
interface CustomErrorAssertion extends AsyncAssertion {
173
withArgs(...args: any[]): AsyncAssertion;
174
}
175
176
interface AsyncAssertion extends Assertion, Promise<void> {}
177
```