27

I'm trying to trigger events in my solidity contract to output some debug information in my javascript tests. However the events seem to get never caught.

That's the relevant contract code:

pragma solidity ^0.4.4;

contract CrowdFunding {

    uint public deadline;
    event DeadlineSet(uint deadline, uint timeNow);

    function withdrawal() returns(bool) {
        DeadlineSet(deadline, now);
        return true;
    }
}

Here's how I try to listen for the events in my JavaScript test file:

 var deadlineSet;
 deadlineSet = contractInstance.DeadlineSet({_from:web3.eth.coinbase});
 deadlineSet.watch(function(err, result) {
    if(err) {
        console.log(err);
        return;
    }
    console.log("Deadline " + result.args.deadline);
    console.log("Time Now " + result.args.timeNow);
    deadlineSet.stopWatching();
});

My tests are working fine and I can send money to the contract and call methods, but I never see any of the console outputs defined above.

Any help is appreciated.

5 Answers 5

17

I've discovered that not all events are displayed in the truffle output window, although they might have fired correctly with the execution of a contract. I believe this to still be an issue

After spending hours on this today I have come up with a solution to test that specific events are fired.

Here's my example truffle javascript test:

it("should do something that fires SaleMade", function() {
    return myContract
        .stockShelf("beer", "wine", {from: sellerAccount})
        .then(() => myContract.sell("water", "bread", {from: sellerAccount}))
        .then(() => utils.assertEvent(myContract, { event: "SaleMade", logIndex: 1, args: { name: "bread" }}));
}

The above filters the fired events that match the filter object passed to the assertEvent utility function I have in utils.js in the same folder. At the top of my javascript test I have declared:

var utils = require("./utils.js");

A snippet of my utils.js class is as follows:

var _ = require("lodash");
var Promise = require("bluebird");

module.exports = {
    assertEvent: function(contract, filter) {
        return new Promise((resolve, reject) => {
            var event = contract[filter.event]();
            event.watch();
            event.get((error, logs) => {
                var log = _.filter(logs, filter);
                if (log) {
                    resolve(log);
                } else {
                    throw Error("Failed to find filtered event for " + filter.event);
                }
            });
            event.stopWatching();
        });
    }
}

This requires other npm packages that aren't included with truffle by default. By default truffle doesn't include npm packages. I setup npm and installed the required packages like this:

npm init
npm install bluebird --save
npm install lodash --save

EDIT: Using testrpc

2
  • 2
    assertEvent needs a slight modification: _.filter() returns an empty array if nothing is found. Empty array is treated as true in if statement. There should be if (!_.isEmpty(log))
    – Kipriz
    Commented Nov 24, 2017 at 13:01
  • 2
    I got TypeError: event.watch is not a function
    – Gagan
    Commented Feb 5, 2019 at 9:46
16

Instead of logging, you can assert the events emitted by a smart contract:

npm install --save-dev truffle-test-utils

At the top of your test:

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

When testing that an event occurred:

// Regular call thanks to Truffle
let result = await testedSmartContract.testedFunction();

// Check event
assert.web3Event(result, {
    event: 'TestedEvent',
      args: {
        param_1: 'Some value',
        param_2: 0x123456 // No need for toNumber hassle
    }
  }, 'The event is emitted'
);

I know this solution is not exactly the right answer, but this is the SO page I found when looking for a way to test events. So I think that might help.

Full disclosure: I'm the author of this package. You guessed it right: I wrote it because I didn't find the clean way of doing it.

9

According to my observation.

We need to wait for a while to see the watched event result for first time watch .

Solidity

contract CrowdFunding {
    event DeadlineSet(
        address indexed _from,
        uint deadline,
        uint timeNow
    );

    uint deadline;

    function withdrawal() returns(bool) {
        DeadlineSet(msg.sender,deadline,now);
        return true;
    }
}

Javascript

var abi = /* abi as generated by the compiler */;
var CrowdFunding = web3.eth.contract(abi);
var crowdfunding = CrowdFunding .at("*address*");

var event = CrowdFunding.DeadlineSet({_from:web3.eth.coinbase},{fromBlock: 0, toBlock: 'latest'});

event.watch(function(error, result){
    if (!error)
        alert("wait for a while, check for block Synchronization or block creation");
        console.log(result);
});

It is better to use stopwatch() before you start watch for your events and not in the watch or after that, it might accidently stop the event watch before it starts.

Try above code and share the result. skip deadlineSet.stopWatching() for now.

1
  • How do you run your tests? The JavaScript snippet above looks like a code I use on the frontend... The question was about testing? Commented Apr 5, 2018 at 11:37
1

Believe your filter (i.e. {_from:web3.eth.coinbase}) is not working. Give a try without it. Something like this

var deadlineSet= contractInstance.DeadlineSet({fromBlock: 0, toBlock: 'latest'});

Listing an example how I have used it.

Event in Contract

event RegisterCandidate(uint256 indexed
eventTimeStamp, address indexed _from, bytes32 indexed _candidateName);

Javascript Code

var event = contractInstance.RegisterCandidate( {_candidateName: "Abc"}, {fromBlock: 0, toBlock: 'latest'});

    event.watch(function(error, response)
    {
       //once the event has been detected, take actions as desired
        var data = 'from: ' + response.args._from+"<br>candidateName: "+web3.toUtf8(response.args._candidateName) +"<br>";
    });
3
  • Thx for the quick response. I tried your code and some variations without success. Now I just read that someone else was not able to check any events when using truffle. Since I'm using truffle as well, I assume this is the problem.
    – Mindful
    Commented Apr 21, 2017 at 4:33
  • Well I am using Ethereum pvt test network and developed the code using truffle itself.
    – Susmit
    Commented Apr 21, 2017 at 4:40
  • 1
    Ah, then it probably doens't work in my case because I'm using testrpc...
    – Mindful
    Commented Apr 21, 2017 at 5:49
1

I've used the answer from mkaj, but I think it needs a couple of fixes :

  • here :

    if (log) { resolve(log); }

resolve(log) is always called because log is an array, the correct check would be

  if (log.length > 0) {
     resolve(log);
    }

(renaming log to filteredLogs would also help clarify it)

  • You don't to call .watch() , .get() will fetch the log history anyway

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.