1

I have a Solidity contract that inherits from ERC721PresetMinterPauserAutoId

I want to write a test that verifies that a Transfer event has been emitted by the contract after the public mint(to) function has been invoked. Here's what my tests look like so far:

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MyContract -- Contract Tests", function () {
    let admin, addr1, addr2;
    let myContract;
    let minterRole = ethers.utils.id("MINTER_ROLE");

    beforeEach(async () => {
        ([admin, addr1, addr2] = await ethers.getSigners());
        const MyContract = await ethers.getContractFactory('MyContract');
        myContract = await MyContract.deploy();
    });   

    // Test passes
    it("Should not allow account without MINTER_ROLE to mint", async function() {
        await expect(myContract.connect(addr1).mint(addr1.address))
                .to.be.revertedWith('ERC721PresetMinterPauserAutoId: must have minter role to mint');

    });

    it("Should allow account with MINTER_ROLE to mint", async function() {
        await myContract.connect(admin).grantRole(minterRole, addr1.address);
        expect(await myContract.hasRole(minterRole, addr1.address)).to.equal(true);

        await expect(myContract.connect(addr1).mint(addr1.address))
            .to.emit(myContract, 'Transfer')
            .withArgs(address(0), addr1.address, 1); // <-- this part is broken
    });
});

Obviously address(0) is undefined. I looked at the source code for the underlying _mint function and it looks like the following:

function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
}

So I have a few questions.

  • How do I capture the arguments captured for the emitted event in my test so I can debug the output?
  • What is the correct way to test that the arguments emitted by the event? I'm hard coding the token counter to 1 but that's because I haven't found an API yet that tells me the total number of tokens minted. Also, I'm not entirely sure how to test for address(0).
2

This example shows how to work with events in Hardhat in general, and it includes a test that illustrates some scenarios.

The tl;dr is that, given a contract like this one:

contract EventEmitter {
  event MyEventWithData(uint, string);

  function emitMyEventWithData(uint x, string calldata s) public {
    emit MyEventWithData(x, s);
  }
}

You can check it in a test like this (notice that this relies on hardhat-waffle):

  it("Should emit MyEventWithData", async function () {
    const EventEmitter = await ethers.getContractFactory("EventEmitter");
    const eventEmitter = await EventEmitter.deploy();
    await eventEmitter.deployed();

    await expect(eventEmitter.emitMyEventWithData(42, "foo"))
      .to.emit(eventEmitter, "MyEventWithData")
      .withArgs(42, "foo");
  });
2
  • Is there a way to dump the args that the event has emitted in the test? Sep 16 at 15:50
  • Check the scripts/getEventsFromTx.js file in the linked example Sep 17 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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