or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

argument-utilities.mdbalance-matchers.mdbignumber-support.mdevent-matchers.mdindex.mdpanic-codes.mdrevert-matchers.mdvalidation-matchers.md

event-matchers.mddocs/

0

# Event Emission Testing

1

2

Matchers for verifying that transactions emit specific events with expected arguments, supporting complex event validation scenarios.

3

4

## Capabilities

5

6

### Event Emission Matcher

7

8

Tests if a transaction emits a specific event from a contract, with support for argument validation through chaining.

9

10

```typescript { .api }

11

/**

12

* Tests if transaction emits a specific event

13

* @param contract - Contract instance that should emit the event

14

* @param eventName - Name of the event to check for

15

* @returns EmitAssertion that can be chained with withArgs()

16

*/

17

emit(contract: any, eventName: string): EmitAssertion;

18

```

19

20

**Basic Usage Examples:**

21

22

```typescript

23

import { expect } from "chai";

24

import { ethers } from "hardhat";

25

26

// Test that event is emitted

27

await expect(contract.transfer(recipient, 1000))

28

.to.emit(contract, "Transfer");

29

30

// Test that event is NOT emitted

31

await expect(contract.noEventFunction())

32

.to.not.emit(contract, "Transfer");

33

34

// Test multiple events from the same transaction

35

await expect(contract.complexOperation())

36

.to.emit(contract, "OperationStarted")

37

.and.to.emit(contract, "OperationCompleted");

38

```

39

40

### Event Argument Validation

41

42

Chain `.withArgs()` to validate specific event arguments, supporting flexible matching patterns.

43

44

```typescript { .api }

45

interface EmitAssertion extends AsyncAssertion {

46

/**

47

* Validates specific arguments emitted with the event

48

* @param args - Expected argument values or predicates

49

* @returns AsyncAssertion for further chaining

50

*/

51

withArgs(...args: any[]): AsyncAssertion;

52

}

53

```

54

55

**Argument Validation Examples:**

56

57

```typescript

58

// Test event with exact argument values

59

await expect(contract.transfer(recipient, 1000))

60

.to.emit(contract, "Transfer")

61

.withArgs(owner.address, recipient.address, 1000);

62

63

// Test event with partial argument matching using anyValue

64

import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";

65

66

await expect(contract.mint(recipient, 500))

67

.to.emit(contract, "Mint")

68

.withArgs(recipient.address, anyValue); // Any amount

69

70

// Test event with unsigned integer validation

71

import { anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";

72

73

await expect(contract.updateBalance(user, 750))

74

.to.emit(contract, "BalanceUpdated")

75

.withArgs(user.address, anyUint); // Any positive integer

76

77

// Test event with complex argument combinations

78

await expect(contract.complexTransfer(from, to, amount, data))

79

.to.emit(contract, "ComplexTransfer")

80

.withArgs(from.address, to.address, amount, anyValue);

81

```

82

83

### Multiple Event Validation

84

85

Test multiple events from the same transaction or validate event sequences.

86

87

```typescript

88

// Multiple events from same transaction

89

await expect(contract.transferWithFee(recipient, 1000))

90

.to.emit(contract, "Transfer")

91

.withArgs(owner.address, recipient.address, 900)

92

.and.to.emit(contract, "Transfer")

93

.withArgs(owner.address, feeCollector.address, 100);

94

95

// Event sequences with different contracts

96

await expect(factory.createToken("MyToken", "MTK"))

97

.to.emit(factory, "TokenCreated")

98

.withArgs(anyValue, "MyToken", "MTK")

99

.and.to.emit(tokenTemplate, "Initialized")

100

.withArgs("MyToken");

101

```

102

103

### Event Testing with Addressable Objects

104

105

The matcher automatically resolves Addressable objects (contracts, signers) to their addresses for comparison.

106

107

```typescript

108

// Works with Addressable objects - automatically resolved to addresses

109

await expect(contract.transfer(recipient, 1000))

110

.to.emit(contract, "Transfer")

111

.withArgs(owner, recipient, 1000); // owner and recipient are resolved to addresses

112

113

// Equivalent to explicit address usage

114

await expect(contract.transfer(recipient.address, 1000))

115

.to.emit(contract, "Transfer")

116

.withArgs(owner.address, recipient.address, 1000);

117

```

118

119

### Advanced Event Testing Patterns

120

121

```typescript

122

// Test event not emitted with specific arguments

123

await expect(contract.partialTransfer(recipient, 100))

124

.to.emit(contract, "Transfer")

125

.withArgs(owner.address, recipient.address, 100)

126

.and.to.not.emit(contract, "TransferFailed");

127

128

// Test event emission order (multiple events of same type)

129

await expect(contract.batchTransfer([user1, user2], [100, 200]))

130

.to.emit(contract, "Transfer")

131

.withArgs(owner.address, user1.address, 100)

132

.and.to.emit(contract, "Transfer")

133

.withArgs(owner.address, user2.address, 200);

134

135

// Complex validation with custom predicates

136

const validateComplexEvent = (address: string, value: bigint, metadata: string) => {

137

return address.length === 42 && value > 0n && metadata.startsWith("0x");

138

};

139

140

await expect(contract.complexOperation())

141

.to.emit(contract, "ComplexEvent")

142

.withArgs(anyValue, anyUint, validateComplexEvent);

143

```

144

145

## Error Handling

146

147

The emit matcher provides detailed error messages for debugging:

148

149

```typescript

150

// If event is not emitted, error shows:

151

// "Expected event 'Transfer' to be emitted"

152

153

// If arguments don't match, error shows expected vs actual:

154

// "Expected event 'Transfer' with args [owner, recipient, 1000] but got [owner, recipient, 500]"

155

156

// If wrong contract emits the event:

157

// "Expected event 'Transfer' to be emitted by contract at 0x123... but was emitted by 0x456..."

158

```

159

160

## Chaining Limitations

161

162

The `.emit()` matcher supports chaining with other `.emit()` matchers but not with other async matchers:

163

164

```typescript

165

// ✅ This works - chaining multiple emit matchers

166

await expect(contract.operation())

167

.to.emit(contract, "EventA")

168

.and.to.emit(contract, "EventB");

169

170

// ❌ This doesn't work - chaining with balance change

171

await expect(contract.transfer(recipient, 1000))

172

.to.emit(contract, "Transfer")

173

.and.to.changeTokenBalance(token, recipient, 1000);

174

175

// ✅ Use separate assertions instead

176

const tx = contract.transfer(recipient, 1000);

177

await expect(tx).to.emit(contract, "Transfer");

178

await expect(tx).to.changeTokenBalance(token, recipient, 1000);

179

```

180

181

## Types

182

183

```typescript { .api }

184

interface EmitAssertion extends AsyncAssertion {

185

withArgs(...args: any[]): AsyncAssertion;

186

}

187

188

interface AsyncAssertion extends Assertion, Promise<void> {}

189

```