DamTan
DamTan

Reputation: 309

How to mock a transaction with a smart contract with eth-testing

I want to test the mint function of my Vue app. The user should be able to mint an NFT when this function is called. To achieve that, I need to call the mint function of my smart contract.

mint: async function(){
  if(typeof window.ethereum !== 'undefined') {
    let accounts = await window.ethereum.request({method : 'eth_requestAccounts'});
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    const contract = new ethers.Contract(this.contractAddress, NftContract.abi, signer);
    try {
      let overrides = {
        from: accounts[0],
        value: this.data.cost
      }
      //error to mock the transaction
const transaction = await contract.mint(accounts[0], 1, overrides);
          await transaction.wait();
          this.getData();
          this.setSuccess('The NFT mint is successful');
        }
        catch(err) {
          console.log(err);
          this.setError('An error occured to mint');
        }
      }
    }

The mint function of my smart contract:

  function mint(address _to, uint256 _mintAmount) public payable {
    uint256 supply = totalSupply();
    require(!paused);
    require(_mintAmount > 0);
    require(_mintAmount <= maxMintAmount);
    require(supply + _mintAmount <= maxSupply);

    if (msg.sender != owner()) {
        if(whitelisted[msg.sender] != true) {
          require(msg.value >= cost * _mintAmount);
        }
    }

    for (uint256 i = 1; i <= _mintAmount; i++) {
      _safeMint(_to, supply + i);
    }
  }

I'm using the eth-testing library (https://www.npmjs.com/package/eth-testing?activeTab=readme) to mock my smart contract interaction.

Initally, the total supply of my contract is 5. After the call of the function and the mint of 1 NFT, it should return the total supply of 6. My test with Jest is the following:

  it('when the user mint 1 NFT, the totalSupply should increment and a successful message should appear (mint funtion)', async () => {
// Start with not connected wallet
testingUtils.mockNotConnectedWallet();
// Mock the connection request of MetaMask
const account = testingUtils.mockRequestAccounts(["0xe14d2f7105f759a100eab6559282083e0d5760ff"]);
//allows to mock the chain ID / network to which the provider is connected --> 0x3 Ropsten network
testingUtils.mockChainId("0x3");
// Mock the network to Ethereum main net
testingUtils.mockBlockNumber("0x3");

const abi = NftContract.abi;
// An address may be optionally given as second argument, advised in case of multiple similar contracts
const contractTestingUtils = testingUtils.generateContractUtils(abi);
let transaction;
//transaction = await contractTestingUtils.mockCall("mint", account, String('10000000000000000')); //Invalid argument
//transaction = await contractTestingUtils.mockCall("mint"); //bad result from back end
//transaction = await contractTestingUtils.mockCall("mint", [account, 1, ethers.utils.parseUnits("0.01", "ether")]); //Invalid argument
//transaction = await contractTestingUtils.mockTransaction("mint"); //Cannot read properties of undefined (reading 'toLowerCase')
transaction = await contractTestingUtils.mockTransaction("mint", undefined, {
    triggerCallback: () => {
      contractTestingUtils.mockCall("cost", ['10000000000000000']);
      contractTestingUtils.mockCall("totalSupply", ['5']);
    }
}); //Cannot read properties of undefined (reading 'toLowerCase')

await wrapper.vm.mint();
await wrapper.vm.getData();

console.log('********wrapper.vm.data');
console.log(wrapper.vm.data);

expect(wrapper.vm.data.totalSupply).toBe('6');
});

I'm don't understand how to mock my transaction, I tried some solution but with errors.

Upvotes: 0

Views: 914

Answers (1)

maribies
maribies

Reputation: 1

I'm just learning too, and thought I'd try to help out with what seems to work for me... from what I've figured out so far, you'll need the contract's abi. which, for me, using hardhat is generated and found under artifacts/contracts/{YourContractName}.sol. I saved this into a fixture file called ABI, which I import into my tests. Then I was able to do mockContract.mockCall("mintNFT", [transaction]); With mockNFT the function name that I want to mock, which is contained in the ABI and returns a transaction. (Transaction is saved in a variable, which is a viable transaction hash). You might also want to consider doing something like the example here, which works like testingUtils.generateContractUtils(ABI).mockTransaction("mintNFT"); with testingUtils being a var from the libs method generateTestingUtils.

Upvotes: 0

Related Questions