OpenZeppelin / openzeppelin-test-helpers

Assertion library for Ethereum smart contract testing
https://docs.openzeppelin.com/test-helpers
MIT License
416 stars 132 forks source link

Support expectEvent testing for multiple emits of the same event in a transaction #135

Open abcoathup opened 3 years ago

abcoathup commented 3 years ago

Support expectEvent testing for multiple emits.

Currently expectEvent will pass for 1 or more emits of the event.

Raised by a community member in Telegram: https://forum.openzeppelin.com/t/test-for-multiple-emits-of-the-same-event-with-expectevent/4106

fabdarice commented 3 years ago

Also looking for support for this feature. Thanks

frangio commented 3 years ago

Would something like the following work, with a new options argument specifying the times the event should show up.

expectEvent(receipt, 'Foo', { arg1: 'bar' }, { times: 2 });

And this function would return the array of found events.

fab-spring commented 3 years ago

Not really, events could be emitted many times but with different values

frangio commented 3 years ago

In that case you can use subsequent calls to expectEvent.

expectEvent(receipt, 'Foo', { arg1: 'bar' });
expectEvent(receipt, 'Foo', { arg1: 'quux' });

Otherwise I'm not sure I'm understanding the request. Can someone provide an example of what they would like to write and how they would want it to behave?

SSharshunov commented 3 years ago

For example: my contract loops through the conditions, and each time generates the same event, but for example the result changes

SSharshunov commented 3 years ago
if (x == 1 || x == 2) {
    uint y = doCalc(some1, some0);
    emit yCalculated(x, y); // Triggering event
    if (x == 2) {
        uint y2 = doCalc(some0, some1);
        emit yCalculated(x, y2); // Triggering event
    }
}
frangio commented 3 years ago

@SSharshunov In this you would also want to check that the events are emitted in the correct order?

zikyfranky commented 2 years ago
if (x == 1 || x == 2) {
    uint y = doCalc(some1, some0);
    emit yCalculated(x, y); // Triggering event
    if (x == 2) {
        uint y2 = doCalc(some0, some1);
        emit yCalculated(x, y2); // Triggering event
    }
}

Just call the expectEvent and pass the right event name and the values of said events

If you are expecting 3 events of Transfer

expecteEvent(tx, 'Transfer', {from:0x.., to:0x.., value:value}
expecteEvent(tx, 'Transfer', {from:0x.., to:0x.., value:value}
expecteEvent(tx, 'Transfer', {from:0x.., to:0x.., value:value}

The value MUST be of type BigNumber or a String, else expectEvent would give you a misleading error expected {expected} but got {actual} cause it only throws the very first error in the error array, which isn't the actual error. expectEvent Source I had to go into the library function to find this.

RUIRUI-ashui commented 2 years ago

Does anyone know how to use it for multiple events in one function?