Skip to content

Commit b9af4f0

Browse files
jakvbsrzadp
andauthoredJul 8, 2022
🌶 Support structs in events for withArgs matcher (#751)
* Remove Chai AssertionError for emit withArgs(nestedStruct) * Rename parametr * Rename variables * Change pragma solidity version * Fix test name * Add changeset * Remove typo * Fix alphanumeric keys * Linting * Update .changeset/silver-masks-compete.md Co-authored-by: Przemyslaw Rzad <roopert7@gmail.com>
1 parent 9d3a171 commit b9af4f0

File tree

4 files changed

+130
-3
lines changed

4 files changed

+130
-3
lines changed
 
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ethereum-waffle/chai": patch
3+
---
4+
5+
Support structs in events for withArgs matcher

‎waffle-chai/src/matchers/withArgs.ts

+27
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ export function supportWithArgs(Assertion: Chai.AssertionStatic) {
4545
[expectedArgs[index], utils.keccak256(expectedArgBytes)]
4646
);
4747
} else {
48+
if (isStruct(actualArgs[index])) {
49+
new Assertion(
50+
convertStructToPlainObject(actualArgs[index])
51+
).to.deep.equal(expectedArgs[index]);
52+
return;
53+
}
4854
new Assertion(actualArgs[index]).equal(expectedArgs[index]);
4955
}
5056
}
@@ -68,6 +74,27 @@ export function supportWithArgs(Assertion: Chai.AssertionStatic) {
6874
);
6975
};
7076

77+
const isStruct = (arr: any[]) => {
78+
if (!Array.isArray(arr)) return false;
79+
const keys = Object.keys(arr);
80+
const hasAlphaNumericKeys = keys.some((key) => key.match(/^[a-zA-Z0-9]*[a-zA-Z]+[a-zA-Z0-9]*$/));
81+
const hasNumericKeys = keys.some((key) => key.match(/^\d+$/));
82+
return hasAlphaNumericKeys && hasNumericKeys;
83+
};
84+
85+
const convertStructToPlainObject = (struct: any[]): any => {
86+
const keys = Object.keys(struct).filter((key: any) => isNaN(key));
87+
return keys.reduce(
88+
(acc: any, key: any) => ({
89+
...acc,
90+
[key]: isStruct(struct[key])
91+
? convertStructToPlainObject(struct[key])
92+
: struct[key]
93+
}),
94+
{}
95+
);
96+
};
97+
7198
Assertion.addMethod('withArgs', function (this: any, ...expectedArgs: any[]) {
7299
if (!('txMatcher' in this) || !('callPromise' in this)) {
73100
throw new Error('withArgs() must be used after emit() or revertedWith()');

‎waffle-chai/test/contracts/Events.ts

+47-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
export const EVENTS_SOURCE = `
2-
pragma solidity ^0.6.0;
2+
pragma solidity ^0.8.0;
33
44
contract Events {
55
event One(uint value, string msg, bytes32 encoded);
66
event Two(uint indexed value, string msg);
77
event Index(string indexed msgHashed, string msg, bytes bmsg, bytes indexed bmsgHash, bytes32 indexed encoded);
88
event Arrays(uint256[3] value, bytes32[2] encoded);
9+
event Struct(Task task);
10+
event NestedStruct(Nested nested);
11+
12+
struct Task {
13+
bytes32 hash;
14+
uint value;
15+
bytes32[2] encoded;
16+
}
17+
18+
struct Nested {
19+
bytes32 hash;
20+
uint value;
21+
Task task;
22+
}
923
1024
function emitOne() public {
1125
emit One(1, "One", 0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123);
@@ -58,6 +72,32 @@ pragma solidity ^0.6.0;
5872
function doNotEmit() pure public {
5973
}
6074
75+
function emitStruct() public {
76+
emit Struct(Task(
77+
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
78+
1,
79+
[
80+
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123),
81+
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162124)
82+
]
83+
));
84+
}
85+
86+
function emitNestedStruct() public {
87+
emit NestedStruct(Nested(
88+
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
89+
1,
90+
Task(
91+
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
92+
1,
93+
[
94+
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123),
95+
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162124)
96+
]
97+
)
98+
));
99+
}
100+
61101
}
62102
`;
63103

@@ -66,6 +106,8 @@ export const EVENTS_ABI = [
66106
'event Two(uint indexed value, string msg)',
67107
'event Index(string indexed msgHashed, string msg, bytes bmsg, bytes indexed bmsgHash, bytes32 indexed encoded)',
68108
'event Arrays(uint256[3] value, bytes32[2] encoded)',
109+
'event Struct((bytes32 hash, uint value, bytes32[2] encoded) task)',
110+
'event NestedStruct((bytes32 hash, uint value, (bytes32 hash, uint value, bytes32[2] encoded) task) nested)',
69111
'function emitOne() public',
70112
'function emitOneMultipleTimes() public',
71113
'function emitTwo() public',
@@ -74,8 +116,10 @@ export const EVENTS_ABI = [
74116
'function emitArrays() public',
75117
'function doNotEmit() pure public',
76118
'function emitNested() public',
77-
'function _emitInternal() internal'
119+
'function _emitInternal() internal',
120+
'function emitStruct() public',
121+
'function emitNestedStruct() public'
78122
];
79123

80124
// eslint-disable-next-line max-len
81-
export const EVENTS_BYTECODE = '608060405234801561001057600080fd5b50610862806100206000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b2f998381161005b578063b2f99838146100b5578063baa4c5ef146100bf578063d5eacee0146100c9578063db6cdf68146100d357610088565b806334c101151461008d5780633f0e64ba1461009757806377f3094b146100a1578063a35a3a0d146100ab575b600080fd5b6100956100dd565b005b61009f610149565b005b6100a96101e6565b005b6100b36103e1565b005b6100bd6104e7565b005b6100c761069b565b005b6100d16106a5565b005b6100db61078d565b005b60027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df6040518080602001828103825260038152602001807f54776f000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390a2565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a1565b7ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b6040518060400160405280600581526020017f54687265650000000000000000000000000000000000000000000000000000008152506040518082805190602001908083835b60208310610272578051825260208201915060208101905060208303925061024f565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060405180807f5468726565000000000000000000000000000000000000000000000000000000815250600501905060405180910390207f2c0160d31a12563decf7b38f40fd0fab153ae9c20f87643b7fb747e3f0e4c93f6040518060400160405280600581526020017f5468726565000000000000000000000000000000000000000000000000000000815250604051808060200180602001838103835260058152602001807f5468726565000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b838110156103a4578082015181840152602081019050610389565b50505050905090810190601f1680156103d15780820380516001836020036101000a031916815260200191505b50935050505060405180910390a4565b7f35cf379c46b4950eedc35bc96d30e9fe7480e2422431c50ea5c4b211ee6b1b8d60405180606001604052806001815260200160028152602001600381525060405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152506040518083600360200280838360005b838110156104a4578082015181840152602081019050610489565b5050505090500182600260200280838360005b838110156104d25780820151818401526020810190506104b7565b505050509050019250505060405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60018060405180838152602001806020018360001b8152602001828103825260128152602001807f446966666572656e744b696e644f664f6e650000000000000000000000000000815250602001935050505060405180910390a1565b6106a361078f565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60018060405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a160027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df6040518080602001828103825260038152602001807f54776f000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390a2565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a156fea26469706673582212208a01fcb12fd6c96d5813c2d16a13edf495b5261a585830072215df30f387ceeb64736f6c63430006000033';
125+
export const EVENTS_BYTECODE = '608060405234801561001057600080fd5b50610e3a806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063b2f9983811610066578063b2f99838146100d5578063baa4c5ef146100df578063d5eacee0146100e9578063db6cdf68146100f3578063ec168af5146100fd5761009e565b806334c10115146100a35780633f0e64ba146100ad57806377f3094b146100b75780639c75eefb146100c1578063a35a3a0d146100cb575b600080fd5b6100ab610107565b005b6100b5610140565b005b6100bf61019b565b005b6100c961028b565b005b6100d3610359565b005b6100dd610409565b005b6100e76104f7565b005b6100f1610501565b005b6100fb610574565b005b610105610576565b005b60027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df60405161013690610739565b60405180910390a2565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123604051610191929190610846565b60405180910390a1565b7ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b6040518060400160405280600581526020017f546872656500000000000000000000000000000000000000000000000000000081525060405161020191906108fc565b60405180910390206040516102159061096a565b60405180910390207f2c0160d31a12563decf7b38f40fd0fab153ae9c20f87643b7fb747e3f0e4c93f6040518060400160405280600581526020017f546872656500000000000000000000000000000000000000000000000000000081525060405161028191906109fd565b60405180910390a4565b7f88af697807fb5575334776b551b779d8a0b7114db2b5077d73bb6f608caa313c60405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b81525081525060405161034f9190610b2e565b60405180910390a1565b7f35cf379c46b4950eedc35bc96d30e9fe7480e2422431c50ea5c4b211ee6b1b8d60405180606001604052806001815260200160028152602001600381525060405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152506040516103ff929190610c47565b60405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405161045a929190610846565b60405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf71621236040516104b3929190610846565b60405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c6001806040516104ed929190610ced565b60405180910390a1565b6104ff610681565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c600180604051610533929190610d29565b60405180910390a160027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df60405161056a90610739565b60405180910390a2565b565b7f24ddd153a6146efa8103ad88564854b506eca37f3c52bdb18fdf3416dfa19d1360405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152508152508152506040516106779190610de9565b60405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf71621236040516106d2929190610846565b60405180910390a1565b600082825260208201905092915050565b7f54776f0000000000000000000000000000000000000000000000000000000000600082015250565b60006107236003836106dc565b915061072e826106ed565b602082019050919050565b6000602082019050818103600083015261075281610716565b9050919050565b6000819050919050565b6000819050919050565b6000819050919050565b600061079261078d61078884610759565b61076d565b610763565b9050919050565b6107a281610777565b82525050565b7f4f6e650000000000000000000000000000000000000000000000000000000000600082015250565b60006107de6003836106dc565b91506107e9826107a8565b602082019050919050565b6000819050919050565b6000819050919050565b60008160001b9050919050565b600061083061082b610826846107f4565b610808565b6107fe565b9050919050565b61084081610815565b82525050565b600060608201905061085b6000830185610799565b818103602083015261086c816107d1565b905061087b6040830184610837565b9392505050565b600081519050919050565b600081905092915050565b60005b838110156108b657808201518184015260208101905061089b565b838111156108c5576000848401525b50505050565b60006108d682610882565b6108e0818561088d565b93506108f0818560208601610898565b80840191505092915050565b600061090882846108cb565b915081905092915050565b600081905092915050565b7f5468726565000000000000000000000000000000000000000000000000000000600082015250565b6000610954600583610913565b915061095f8261091e565b600582019050919050565b600061097582610947565b9150819050919050565b600061098c6005836106dc565b91506109978261091e565b602082019050919050565b600082825260208201905092915050565b6000601f19601f8301169050919050565b60006109cf82610882565b6109d981856109a2565b93506109e9818560208601610898565b6109f2816109b3565b840191505092915050565b60006040820190508181036000830152610a168161097f565b90508181036020830152610a2a81846109c4565b905092915050565b610a3b816107fe565b82525050565b610a4a81610763565b82525050565b600060029050919050565b600081905092915050565b6000819050919050565b6000610a7c8383610a32565b60208301905092915050565b6000602082019050919050565b610a9e81610a50565b610aa88184610a5b565b9250610ab382610a66565b8060005b83811015610ae4578151610acb8782610a70565b9650610ad683610a88565b925050600181019050610ab7565b505050505050565b608082016000820151610b026000850182610a32565b506020820151610b156020850182610a41565b506040820151610b286040850182610a95565b50505050565b6000608082019050610b436000830184610aec565b92915050565b600060039050919050565b600081905092915050565b6000819050919050565b6000610b758383610a41565b60208301905092915050565b6000602082019050919050565b610b9781610b49565b610ba18184610b54565b9250610bac82610b5f565b8060005b83811015610bdd578151610bc48782610b69565b9650610bcf83610b81565b925050600181019050610bb0565b505050505050565b600081905092915050565b610bf981610a50565b610c038184610be5565b9250610c0e82610a66565b8060005b83811015610c3f578151610c268782610a70565b9650610c3183610a88565b925050600181019050610c12565b505050505050565b600060a082019050610c5c6000830185610b8e565b610c696060830184610bf0565b9392505050565b7f446966666572656e744b696e644f664f6e650000000000000000000000000000600082015250565b6000610ca66012836106dc565b9150610cb182610c70565b602082019050919050565b6000610cd7610cd2610ccd84610759565b610808565b6107fe565b9050919050565b610ce781610cbc565b82525050565b6000606082019050610d026000830185610799565b8181036020830152610d1381610c99565b9050610d226040830184610cde565b9392505050565b6000606082019050610d3e6000830185610799565b8181036020830152610d4f816107d1565b9050610d5e6040830184610cde565b9392505050565b608082016000820151610d7b6000850182610a32565b506020820151610d8e6020850182610a41565b506040820151610da16040850182610a95565b50505050565b60c082016000820151610dbd6000850182610a32565b506020820151610dd06020850182610a41565b506040820151610de36040850182610d65565b50505050565b600060c082019050610dfe6000830184610da7565b9291505056fea2646970667358221220f8b514d0f235d497ef41cb23be8705ea2d1e301573a1be093b353512357b88c764736f6c634300080f0033';

‎waffle-chai/test/matchers/eventsTest.ts

+51
Original file line numberDiff line numberDiff line change
@@ -467,5 +467,56 @@ export const eventsTest = (provider: TestProvider) => {
467467
.to.emit(events, 'One')
468468
.and.not.to.emit(differentEvents, 'One');
469469
});
470+
471+
it('Emit struct: success', async () => {
472+
const struct = {
473+
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
474+
value: BigNumber.from(1),
475+
encoded: [
476+
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
477+
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162124'
478+
]
479+
};
480+
await expect(events.emitStruct())
481+
.to.emit(events, 'Struct')
482+
.withArgs(struct);
483+
});
484+
485+
it('Emit struct: fail', async () => {
486+
await expect(
487+
expect(events.emitStruct()).to.emit(events, 'One')
488+
).to.be.eventually.rejectedWith(
489+
AssertionError,
490+
'Expected event "One" to be emitted, but it wasn\'t'
491+
);
492+
});
493+
494+
it('Emit nested struct: success', async () => {
495+
const struct = {
496+
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
497+
value: BigNumber.from(1),
498+
encoded: [
499+
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
500+
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162124'
501+
]
502+
};
503+
const nestedStruct = {
504+
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
505+
value: BigNumber.from(1),
506+
task: struct
507+
};
508+
await expect(events.emitNestedStruct())
509+
.to.emit(events, 'NestedStruct')
510+
.withArgs(nestedStruct);
511+
});
512+
513+
it('Emit nested struct: fail', async () => {
514+
await expect(
515+
expect(events.emitNestedStruct()).to.emit(events, 'One')
516+
).to.be.eventually.rejectedWith(
517+
AssertionError,
518+
'Expected event "One" to be emitted, but it wasn\'t'
519+
);
520+
});
470521
});
471522
};

0 commit comments

Comments
 (0)
Please sign in to comment.