Truffle – Testing Events via JavaScript Effectively

eventsjavascripttestingtruffletruffle-assertions

I am testing my contract via the chai and truffle-assertions libraries from a JavaScript file and am testing if events return the correct values. I have an event called Message. In my function, the event is called twice consecutively but with a different id and message. The problem I have is that it gives me an error whenever I try to test for both events even though I checked it on remix and everything seems to work. Just testing for the events (truffleAssert.eventEmitted(result, 'Message');) works fine.

I can't give the events two different names as it will create a mess for the later development of my contracts and I'll end up with an enormous amount of events.

How can I get the tests to work? Is there a workaround this error?

Similar to the below (can't share my actual code though):

event Message(address id, bytes16 message);

function messages() public {
emit Message(0x1fe..., 'Almost there);
emit Message(0x0, 'Congratulations'); 
}

And my test file looks pretty much like this:

const Contract = artifacts.require('./Contract.sol')
const assert = require("chai").assert;
const truffleAssert = require('truffle-assertions');

contract('Contract', function(accounts) {
  let contractInst;
  let owner = accounts[0];
  let user1 = accounts[1];
  let user2 = accounts[2];

  before('getting instance before all Test Cases', async function(){
    contractInst = await Contract.new({from: owner});

  })

it("should check that the correct events are returned", async () => {
  let result = await contractInst.messages();

    truffleAssert.eventEmitted(result, 'Message', (ev) => {
      assert.equal(ev.id, user1, 'Correct id was returned');
      assert.equal(web3.toUtf8(ev.message), "Almost there", 'Correct message was returned.');
      return true;
    }, 'Contract should return the correct message.');

    truffleAssert.eventEmitted(result, 'Message', (ev) => {
      assert.equal(ev.id, user2, 'Correct id was returned');
      assert.equal(web3.toUtf8(ev.message), "Congratulations", 'Correct message was returned.');
      return true;
    }, 'Contract should return the correct message.');

})

})

The latest error message I am getting is that I am expecting the event to return the 0x1fe… address but instead it returns the 0x0 address so it looks like it's only looking at the return of the latest event. At the same time, even if I input the 0x0 address for both events it still returns an error message.

Thanks!

Best Answer

While Aquila's answer can work as a workaround, the way truffleAssert.eventEmitted() works is by applying a filter function on the event's arguments. The drawback of this is that you can't "assert" each argument individually, but this will allow you to run both assertions in this fashion.

I saw from your other question that you're using Truffle v5 with Solidity v0.5.0, so I updated your tests to use Web3 v1.0.

I used the following solidity code to test:

event Message(address id, bytes16 message);

function messages() public {
    emit Message(address(0), "Almost there");
    emit Message(address(msg.sender), "Congratulations");
}

And changed the Javascript tests to:

it("should check that the correct events are returned", async () => {
    let result = await casino.messages();

    truffleAssert.eventEmitted(result, 'Message', (ev) => {
      return ev.id === '0x0000000000000000000000000000000000000000' && web3.utils.hexToUtf8(ev.message) === 'Almost there';
    }, 'Contract should return the correct message.');

    truffleAssert.eventEmitted(result, 'Message', (ev) => {
      return ev.id === accounts[0] && web3.utils.hexToUtf8(ev.message) === 'Congratulations';
    }, 'Contract should return the correct message.');
  })

Both of these tests pass with Truffle v5, Solidity v0.5.0, truffle-assertions v0.7.1.

Related Topic