Sweet tool for
smart contracts testing

The most advanced framework for testing smart contracts

Philosophy

  • bitten waffle

    Simpler

    Minimalistic, fewer dependencies.

  • waffle with chocolate

    Sweeter

    Nicer syntax, easy to learn, and easy to extend.

  • waffle in motion

    Faster

    Faster contract compilation and tests execution.

Features

  • Compiles Solidity & Vyper

  • Write tests with ENS

  • Works with Hardhat

Example code

Below is an example contract, that delivers from standard ERC20 token:

					
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// Example class - a mock class using delivering from ERC20
contract BasicToken is ERC20 {
    constructor(uint256 initialBalance) ERC20("Basic", "BSC") public {
        _mint(msg.sender, initialBalance);
    }
}
					
				

Belows is example test written for the contract above written with Waffle.

					
import {expect, use} from 'chai';
import {Contract} from 'ethers';
import {deployContract, MockProvider, solidity} from 'ethereum-waffle';
import BasicToken from '../build/BasicToken.json';
use(solidity);
describe('BasicToken', () => {
  const [wallet, walletTo] = new MockProvider().getWallets();
  let token: Contract;
  beforeEach(async () => {
    token = await deployContract(wallet, BasicToken, [1000]);
  });
  it('Assigns initial balance', async () => {
    expect(await token.balanceOf(wallet.address)).to.equal(1000);
  });
  it('Transfer adds amount to destination account', async () => {
    await token.transfer(walletTo.address, 7);
    expect(await token.balanceOf(walletTo.address)).to.equal(7);
  });
  it('Transfer emits event', async () => {
    await expect(token.transfer(walletTo.address, 7))
      .to.emit(token, 'Transfer')
      .withArgs(wallet.address, walletTo.address, 7);
  });
  it('Can not transfer above the amount', async () => {
    await expect(token.transfer(walletTo.address, 1007)).to.be.reverted;
  });
  it('Can not transfer from empty account', async () => {
    const tokenFromOtherWallet = token.connect(walletTo);
    await expect(tokenFromOtherWallet.transfer(wallet.address, 1))
      .to.be.reverted;
  });
  it('Calls totalSupply on BasicToken contract', async () => {
    await token.totalSupply();
    expect('totalSupply').to.be.calledOnContract(token);
  });
  it('Calls balanceOf with sender address on BasicToken contract', async () => {
    await token.balanceOf(wallet.address);
    expect('balanceOf').to.be.calledOnContractWith(token, [wallet.address]);
  });
});
					
				

More examples available on our GitHub

How to install

To start using with npm, type:

npm i ethereum-waffle

To start using with yarn, type:

yarn add ethereum-waffle

Patterns and solutions

Dynamic mocking   Testing the effects of a call   Testing with ENS   Fixtures (coming soon)

Materials

Blogpost on Ethworks blog

  • Introducing Waffle support for Jest (experimental)
  • Smart contract testing with ENS and Waffle
  • ? Waffle 3.0 released! With ethers.js 5.0 and more!
  • New Waffle matcher: expect().to.be.calledOnContract()
  • Mocking Solidity smart contracts with Waffle
  • Introducing Waffle
  • Waffle 2.0 released
  • Smart Contracts testing still sucks, how we want to make it better

Tutorials on Ethereum.org

  • Waffle: Dynamic mocking and testing contract calls
  • Waffle say hello world tutorial with hardhat and ethers
  • Testing smart contracts with Waffle

Waffle is created by

Maintained by