¿Cómo escuchar eventos de contrato en pruebas de JavaScript?

Estoy tratando de desencadenar eventos en mi contrato de solidez para generar información de depuración en mis pruebas de JavaScript. Sin embargo, los eventos parecen nunca quedar atrapados.

Ese es el código de contrato relevante:

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

Así es como trato de escuchar los eventos en mi archivo de prueba de JavaScript:

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

Mis pruebas funcionan bien y puedo enviar dinero al contrato y llamar a los métodos, pero nunca veo ninguna de las salidas de la consola definidas anteriormente.

Cualquier ayuda es apreciada.

Respuestas (5)

Descubrí que no todos los eventos se muestran en la ventana de salida de la trufa, aunque es posible que se hayan disparado correctamente con la ejecución de un contrato. Creo que esto sigue siendo un problema.

Después de pasar horas en esto hoy, se me ocurrió una solución para probar que se disparan eventos específicos.

Aquí está mi prueba de javascript de trufa de ejemplo:

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

Lo anterior filtra los eventos activados que coinciden con el objeto de filtro pasado a la función de utilidad assertEvent que tengo en utils.js en la misma carpeta. En la parte superior de mi prueba de javascript he declarado:

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

Un fragmento de mi clase utils.js es el siguiente:

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

Esto requiere otros paquetes npm que no se incluyen con truffle de manera predeterminada. Por defecto, truffle no incluye paquetes npm. Configuré npm e instalé los paquetes necesarios como este:

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

EDITAR: Usando testrpc

assertEventnecesita una ligera modificación: _.filter()devuelve una matriz vacía si no se encuentra nada. La matriz vacía se trata como verdadera en la ifdeclaración. Debería haberif (!_.isEmpty(log))
ObtuveTypeError: event.watch is not a function

En lugar de iniciar sesión , puede afirmar los eventos emitidos por un contrato inteligente:

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

En la parte superior de su prueba:

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

Al probar que ocurrió un evento:

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

Sé que esta solución no es exactamente la respuesta correcta, pero esta es la página SO que encontré cuando buscaba una forma de probar eventos. Así que creo que eso podría ayudar.

Divulgación completa: soy el autor de este paquete. Adivinaste bien: lo escribí porque no encontré la manera limpia de hacerlo.

Según mi observación.

Tenemos que esperar un momento para ver el resultado del evento visto por primera vez.

Solidez

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 mejor usar el cronómetro() antes de comenzar a ver sus eventos y no en el reloj o después de eso, podría detener accidentalmente el reloj del evento antes de que comience.

Pruebe el código anterior y comparta el resultado. omita la fecha límiteSet.stopWatching() por ahora.

¿Cómo haces tus pruebas? El fragmento de JavaScript anterior parece un código que uso en la interfaz... ¿La pregunta era sobre pruebas?

Cree que su filtro (es decir, {_from:web3.eth.coinbase}) no funciona. Pruébalo sin él. Algo como esto

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

Enumerando un ejemplo de cómo lo he usado.

Evento en Contrato

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

Código JavaScript

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>";
    });
Gracias por la respuesta rápida. Probé tu código y algunas variaciones sin éxito. Ahora acabo de leer que otra persona no pudo verificar ningún evento al usar trufa. Como también estoy usando trufa, supongo que este es el problema.
Bueno, estoy usando la red de prueba de Ethereum pvt y desarrollé el código usando la trufa.
Ah, entonces probablemente no funcione en mi caso porque estoy usando testrpc...

He usado la respuesta de mkaj, pero creo que necesita un par de correcciones:

  • aquí :

    si (registro) { resolver (registro); }

resolve(log) siempre se llama porque log es una matriz, la verificación correcta sería

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

(Cambiar el nombre del registro a filteredLogs también ayudaría a aclararlo)

  • No debe llamar a .watch() , .get() obtendrá el historial de registro de todos modos