0.2.3 • Published 5 years ago

chai-truffle v0.2.3

Weekly downloads
4
License
MIT
Repository
github
Last release
5 years ago

Chai Assertions for Truffle

https://www.npmjs.com/package/chai-truffle https://codecov.io/gh/calvinlauco/chai-truffle https://travis-ci.org/calvinlauco/chai-truffle https://github.com/calvinlauco/chai-truffle

Chai Truffle extends Chai to provide assertion for Truffle Transaction. Complete TypeScript typings are provided with this library.

With Chai Truffle, you can assert event emission on contract call easily. This library tries to make assertion as fluent as English sentence.

const response = await bankInstance.deposit(oneEtherInWei);

expect(response)
    .to.emitEvent("Deposit")
    .withEventArgs((args) => {
        expect(args.from).to.eq(defaultAccount);
        expect(args.amount.toString(10)).to.eq(oneEtherInWei);

        return true;
    });

Chai Truffle can also help assert EVM execution result.

return expect(response).to.evmRevert();

Remarks: When trying to used with EVM execution assertion, return must be used because it is an asynchronous assertion.

Quick Navigation

Installation

npm install chai-truffle

How to use

Chai Truffle is compatible with both CommonJS module system and TypeScript.

CommonJS

const chai = require("chai");
const ChaiTruffle = require("chai-truffle");
chai.use(ChaiTruffle);

TypeScript

import chai from "chai";
import chaiTruffle = require("chai-truffle");
chai.use(chaiTruffle);

Remarks: import = require() syntax must be used to import Chai Truffle

APIs

The library is shipped with Event APIs and EVM execution result APIs.

Event APIs

.transactionResponse

Assert if a value is Transaction Response liked object

const response = await bankInstance.withdraw(oneEtherInWei);

expect(response).to.be.transactionResponse;

.emitEvent(eventName)

Asserts if any event has been emitted from the transaction. If eventName is provided, it will assert if an event with the eventName has been emitted.

const response = await bankInstance.withdraw(oneEtherInWei);

expect(response).to.emitEvent("Withdrawal");

.emitEventAt(eventName, position, message)

Assert if the event with eventName has been emitted at the specified log position.

const response = await bankInstance.batchWithdraw(oneEtherInWei);

expect(response).to.emitEventAt("Withdrawal", 2);

Remarks: Event log position begins from 0.

.withEventArgs(argumentAssertFunction)

Use in conjunction with .emitEvent() and emitEventAt() to assert if the emitted event has parameters satisfying the argumentAssertFunction.

const response = await bankInstance.withdraw(oneEtherInWei);

expect(response).to.emitEvent("Withdrawal").withEventArgs((args) => {
    expect(args.to).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);
});

.emitEventWithArgs(eventName, argumentAssertFunction, message)

Assert if a event with eventName and matching parameter has been emitted. The argumentAssertFunction is used to match the event arguments. It is a shorthand of the emitEvent().withEventArgs() but they have subtle difference in behaviour in some scenarios.

expect(response).to.emitEventWithArgs("Deposit", (args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);
});

.emitEventWithArgsAt(eventName, argumentAssertFunction, position, message)

Similar to .emitEventWithArgs(), it asserts if a event with eventName and matching parameter has been emitted at a specified log position. The argumentAssertFunction is used to match the event arguments.

// Checking for a Deposit event in the 3rd event log of a transaction
expect(response).to.emitEventWithArgs("Deposit", (args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);
}, 2);

Remarks: Event log position begins at 0

.eventLength(length, message)

Assert if transaction has emitted length of events.

const response = bankContract.batchWithdraw(oneEtherInWei);

expect(response).to.have.eventLength(2);

.eventLengthOf(length, message)

Alias of .eventLength

Argument Assert Function

Argument assert function takes the form

(args: Truffle.TransactionLogArgs) => boolean

args is an array-liked object containing both parameter name and parameter index as key. If you have a solidity contract of event:

event Deposit(
    address indexed from,
    uint amount
);

The corresponding args object will be:

{
    from: "{From Address}",
    [0]: "{From Address}",
    amount: "{Amount}",
    [1]: "{Amount}",
};

You can define your parameter assert function be like

(args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);

    return true;
}

Remarks: Boolean must be returned at the end of the parameter assert function or otherwise assertion will consider the parameters to be unmatched.

All event parameters assertions (.withEventArgs(), .emitEventWithArgs(), .emitEventWithArgsAt()) support Chai assertion inside the parameter assert function. They will capture the assertion errors inside and displayed as test result:

const defaultAccount = "0xf17f52151EbEF6C7334FAD080c5704D77216b732";
expect(response).to.emitEvent("Deposit").withEventArgs((args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);
});

///
$ AssertionError: expected transaction to emit event 'Withdrawal' with matching argument(s), but argument(s) assert function got: 'expected '0x627306090abaB3A6e1400e9345bC60c78a8BEf57' to equal '0xf17f52151EbEF6C7334FAD080c5704D77216b732''
      + expected - actual

      -0x627306090abaB3A6e1400e9345bC60c78a8BEf57
      +0xf17f52151EbEF6C7334FAD080c5704D77216b732

EVM Execution Result APIs

The EVM execution result assertion APIs help to check if a transaction has passed EVM execution. If not, what error has occurred.

Note that return must be used because EVM execution error are thrown from the Promise, the assertion is asynchronous.

return(contractInstance.revertImmediately()).to.evmFail();

.evmSuccess(message)

Assert if the transaction call has passed the EVM execution successfully.

return expect(BankInstance.withdraw(oneEtherInWei)).to.evmSuccess();

.evmFail(reason)

Assert if the transaction call has failed the EVM execution. If reason is provided, it will assert if the thrown error message contains the reason keyword.

return expect(BankInstance.withdraw(outOfBalanceWei)).to.evmFail();
return expect(BankInstance.withdraw(oneEtherInWei)).to.evmFail("Insufficient balance");

.evmRevert(message)

Assert if the transaction call has failed the EVM execution because of revert.

return expect(ContractInstance.revertImmediately()).to.evmFail();

.evmOutOfGas(message)

Assert if the transaction call has failed the EVM execution because of run out of gas.

return expect(ContractInstance.drainGas()).to.evmOutOfGas();

.evmInvalidOpcode(message)

Assert if the transaction call has failed the EVM execution because of invalid opcode.

return expect(ContractInstance.assertFail()).to.emvInvalidOpcode();

Difference between .emitEvent().withArgs() and .emitEventWithArgs()

At first glance these two assertions may seems to be the same when asserting a particular event with arguments has been emitted.

expect(response).to.emitEvent("Deposit").withEventArgs((args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);

    return true;
})
// is the same as
expect(response).to.emitEventWithArgs("Deposit", (args) => {
    expect(args.from).to.eq(defaultAccount);
    expect(args.amount).to.eq(oneEtherInWei);

    return true;
})

Their difference is when you are asserting a particular event with parameter is NOT emitted.

.emitEvent().not.withEventArgs() is useful when you want to assert a event with event name is emitted but not with the arguments you specified. For example you are certain that a Deposit event is emitted, but you want to make sure it is not emitted with wrong arguments.

The below example will pass only when Deposit event is emitted but with non-matching arguments.

const response = bankInstance.deposit({
    value: oneEtherInWei,
});

expect(response).to.emitEvent("Deposit").not.withEventArgs((args) => {
    expect(args.amount).eq.eq(twoEtherInWei);

    return true;
});

If you use .not.emitEventWithArgs(), the assertion will pass event if Deposit event is not emitted.

For more details, please refer to Wiki for Detailed assertion truth table

Example

There is a simple Bank contract with test cases example to illustrate how to integrate Chai Truffle with Truffle contract. For setup and details, please refer to README under example/ directory.

Contribution

Contribution and feedbacks are welcome. Feel free to leave issues or fork and submit your PR.

License

This library is published under MIT license

0.2.3

5 years ago

0.2.2

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.0

5 years ago