12

I have a contract's function which emit events on each call.

I would like to have an event emitted on each test which are passing, here are some tests :

it("should emit Error event when sending 5 ether", function(done){
  var insurance = CarInsurance.deployed();

  insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then(done).catch(done);
});

it("should emit Error event when sending 5 ether", function(done){
  var insurance = CarInsurance.deployed();

  insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then(function(txHash){
    assert.notEqual(txHash, null);
  }).then(done).catch(done);
});

it("should emit Error event when sending 5 ether", function(done){
  var insurance = CarInsurance.deployed();

  insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then(function(done){
    done();
  }).catch(done);
});

The results are :

1) should emit Error event when sending 5 ether

Events emitted during test:
---------------------------

Error(error: Must send 10 ether)

---------------------------
✓ should emit Error event when sending 5 ether (11120ms)
✓ should emit Error event when sending 5 ether (16077ms)


3 passing (51s)
1 failing

1) Contract: CarInsurance should emit Error event when sending 5 ether:
 Error: done() invoked with non-Error: 0x87ae32b8d9f8f09dbb5d7b36267370f19d2bda90d3cf7608629cd5ec17658e9b

You can see that the only one which is logged fail.

Any idea ?

Thank you

ltheron
  • 301
  • 1
  • 3
  • 12

6 Answers6

12

You are passing tx hash into done() function. I think the problem is in line:

insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then(done).catch(done);

Change it to:

insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then(function() { done(); }).catch(done);

To test for events:

it("should check events", function(done) {
  var watcher = contract.Reward();

  // we'll send rewards
  contract.sendReward(1, 10000, {from: accounts[0]}).then(function() {
    return watcher.get();
  }).then(function(events) {
    // now we'll check that the events are correct
    assert.equal(events.length, 1);
    assert.equal(events[0].args.beneficiary.valueOf(), 1);
    assert.equal(events[0].args.value.valueOf(), 10000);
  }).then(done).catch(done);
});
Aldekein
  • 3,538
  • 2
  • 29
  • 33
  • In fact, only the first test output the "Error" event which I want. When I change like you said, it output nothing, seems that it wait for done()... – ltheron Apr 15 '16 at 12:02
  • @user3262670 I do not see any check for events in test at all. + all test cases are named "should emit Error event when sending 5 ether" so you cannot tell which of them fail. – Aldekein Apr 15 '16 at 22:02
  • Can we check events in test ? I wanted to show three ways of doing the same test case. I just want to show events during tests, and the only way to do it is when the test fail... – ltheron Apr 16 '16 at 10:45
  • @user3262670 I've added an example of how to test events in Truffle. – Aldekein Apr 23 '16 at 04:42
  • 1
    Does truffle support testing events directly from solidity? – cayblood Jun 01 '17 at 20:19
6

Since Truffle v3 you get the logs in the callback result. So you could do something like:

insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')}).then((result) => { assert.equal(result.logs[0].event, "Error", "Expected Error event") })

See https://github.com/trufflesuite/truffle-contract#processing-transaction-results

satolizard
  • 199
  • 2
  • 3
5

There is a helper to do just this:

npm install --save truffle-test-utils

At the top of your test:

require('truffle-test-utils').init();

In your test:

let result = await insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')});
assert.web3Event(result, {
  event: 'Error',
  args: {
    error: 'Must send 10 ether'
  }
}, 'Error event when sending 5 ether');

Full disclosure: I'm the author of this package. I wrote it after looking for such solution on SO, but couldn't find it.

philippe_b
  • 38,730
  • 7
  • 57
  • 59
2

Instead of writing your own, you can also use Truffle's test utils expectEvent.js:

const { inLogs } = require('openzeppelin-solidity/test/helpers/expectEvent')
require('chai').use(require('chai-bignumber')(BigNumber)).should()
...
{ logs: this.logs } = await this.token.burn(amount, { from: owner })
...
const event = inLogs(this.logs, 'Burn')
event.args.burner.should.eq(owner)
event.args.value.should.be.bignumber.equal(amount)

An example can be found in Truffle's BurnableToken.behavior.js.

Richard Fu
  • 616
  • 10
  • 27
0

You can use the truffle-assertions package, which has an assertion to check that an event has been emitted. It also has the option to pass a filter function in order to check complex conditions to the event arguments.

npm install truffle-assertions

You can import it at the top of your test file:

const truffleAssert = require('truffle-assertions');

And use it inside your test:

let txResult = await insurance.send({from: accounts[0], value: web3.toWei(5, 'ether')});
truffleAssert.eventEmitted(txResult, 'Error', (ev) => {
    return ev.error === 'Must send 10 ether';
}

Disclaimer: I created this package to use in my own tests, and by adding the filter function, it is possible to check complex conditions to the event arguments, in a very straightforward way. I wrote an article explaining this in more detail on my blog.

Rosco Kalis
  • 567
  • 3
  • 13
0

I was able to track down some references to help with this, especially if you want to use async/await.

it('can create a unique star and get its name', async function () {
        const event = this.contract.starClaimed({});
        event.watch(async (err, result) => {
           if (err) console.log("Somethings wrong...");

           if (result.args.owner === accounts[0]) {
               let token = result.args._token;
               event.stopWatching;

               const star = await this.contract.tokenIdToStarInfo(token);

               assert.equal(star[0], 'awesome star!');
               assert.equal(star[1], 'yada yada yada');
               assert.equal(star[2], 'dec_test');
               assert.equal(star[3], 'mag_test');
               assert.equal(star[4], 'cent_test');
           }
        });

        await this.contract.createStar('awesome star!', 'yada yada yada', 'dec_test', 'mag_test', 'cent_test', {from: accounts[0]});
    });

Here's the reference I found: https://github.com/trufflesuite/truffle-contract/issues/117

James Grunewald
  • 43
  • 1
  • 1
  • 4