Wie kann ich in JavaScript-Tests auf Vertragsereignisse lauschen?

Ich versuche, Ereignisse in meinem Soliditätsvertrag auszulösen, um einige Debug-Informationen in meinen Javascript-Tests auszugeben. Die Ereignisse scheinen jedoch nie erfasst zu werden.

Das ist der relevante Vertragscode:

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;
    }
}

So versuche ich, auf die Ereignisse in meiner JavaScript-Testdatei zu lauschen:

 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();
});

Meine Tests funktionieren einwandfrei und ich kann Geld an den Vertrag senden und Methoden aufrufen, aber ich sehe nie eine der oben definierten Konsolenausgaben.

Jede Hilfe ist willkommen.

Antworten (5)

Ich habe festgestellt, dass nicht alle Ereignisse im Truffle-Ausgabefenster angezeigt werden, obwohl sie bei der Ausführung eines Kontrakts möglicherweise korrekt ausgelöst wurden. Ich glaube, das ist immer noch ein Problem

Nachdem ich heute Stunden damit verbracht habe, habe ich eine Lösung gefunden, um zu testen, ob bestimmte Ereignisse ausgelöst werden.

Hier ist mein Beispiel-Trüffel-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" }}));
}

Das Obige filtert die ausgelösten Ereignisse, die mit dem Filterobjekt übereinstimmen, das an die AssertEvent-Dienstprogrammfunktion übergeben wird, die ich in utils.js im selben Ordner habe. An der Spitze meines Javascript-Tests habe ich erklärt:

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

Ein Ausschnitt meiner utils.js-Klasse sieht wie folgt aus:

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();
        });
    }
}

Dies erfordert andere npm-Pakete, die nicht standardmäßig in Truffle enthalten sind. Standardmäßig enthält Truffle keine npm-Pakete. Ich habe npm eingerichtet und die erforderlichen Pakete wie folgt installiert:

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

BEARBEITEN: Mit testrpc

assertEventBenötigt eine leichte Änderung: _.filter()Gibt ein leeres Array zurück, wenn nichts gefunden wird. ifEin leeres Array wird in der Anweisung als wahr behandelt . Es sollte seinif (!_.isEmpty(log))
ich habeTypeError: event.watch is not a function

Anstatt zu loggen , können Sie die von einem Smart Contract ausgegebenen Ereignisse geltend machen:

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

An der Spitze Ihres Tests:

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

Beim Testen, ob ein Ereignis aufgetreten ist:

// 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'
);

Ich weiß, dass diese Lösung nicht genau die richtige Antwort ist, aber dies ist die SO-Seite, die ich gefunden habe, als ich nach einer Möglichkeit gesucht habe, Ereignisse zu testen. Also ich denke das könnte helfen.

Vollständige Offenlegung: Ich bin der Autor dieses Pakets. Sie haben es richtig erraten: Ich habe es geschrieben, weil ich keinen sauberen Weg gefunden habe, es zu tun.

Nach meiner Beobachtung.

Wir müssen eine Weile warten, um das Ergebnis des beobachteten Ereignisses beim ersten Mal zu sehen.

Solidität

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);
});

Es ist besser, stopwatch() zu verwenden, bevor Sie mit der Überwachung Ihrer Ereignisse beginnen, und nicht in der Überwachung, oder danach könnte die Ereignisüberwachung versehentlich gestoppt werden, bevor sie beginnt.

Probieren Sie den obigen Code aus und teilen Sie das Ergebnis. Überspringen Sie vorerst den TerminDeadlineSet.stopWatching().

Wie führen Sie Ihre Tests durch? Das obige JavaScript-Snippet sieht aus wie ein Code, den ich im Frontend verwende ... Die Frage betraf das Testen?

Glauben Sie, dass Ihr Filter (dh {_from:web3.eth.coinbase}) nicht funktioniert. Versuch mal ohne. Etwas wie das

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

Ein Beispiel auflisten, wie ich es verwendet habe.

Ereignis im Vertrag

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>";
    });
Thx für die schnelle Antwort. Ich habe Ihren Code und einige Variationen ohne Erfolg ausprobiert. Jetzt habe ich gerade gelesen, dass jemand anderes bei der Verwendung von Trüffel keine Ereignisse überprüfen konnte. Da ich auch Trüffel verwende, gehe ich davon aus, dass dies das Problem ist.
Nun, ich verwende das Ethereum pvt-Testnetzwerk und habe den Code mit Trüffel selbst entwickelt.
Ah, dann funktioniert es in meinem Fall wahrscheinlich nicht, weil ich testrpc verwende ...

Ich habe die Antwort von mkaj verwendet, aber ich denke, es braucht ein paar Korrekturen:

  • hier :

    if (log) {auflösen (log); }

resolve(log) wird immer aufgerufen, weil log ein Array ist, die richtige Prüfung wäre

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

(Das Umbenennen des Protokolls in „filteredLogs“ würde ebenfalls zur Klärung beitragen.)

  • Sie müssen .watch() nicht aufrufen, .get() ruft sowieso den Protokollverlauf ab