0

This is my first post on stackoverflow so please be gentle...

I am trying to use Jest to do some end-to-end testing of a function that communicates with a smart contract deployed on a local development blockchain.

The issues I'm having probably stem from my lack of thourough understanding of how promises and the event loop work, but the test completes, before the stake function completes.

Here is the test:

test('stake', async () => {
        
        let tokenId;
        
        // test set up - make sure the address owns at least 1 NFT
        const currentBalance = (await nftContract.balanceOf(address)).toNumber();
        if (currentBalance > 0) {
            tokenId = (await stakingContractAddress.tokenOfOwnerByIndex(address, 0)).toNumber();
        } else {
            // if address owns no NFTs, mint one
            await mint(address)
        }
        
        // pre stake
        const addressBalance = (await nftContract.balanceOf(address)).toNumber();
        const stakedBalance = (await stakingContractAddress.numStaked(address)).toNumber();

        console.log(`addressBalance: ${addressBalance}`) // should be 1
        console.log(`stakedBalance: ${stakedBalance}`) // should be 0
        
        // stake
        await stake(tokenId, address); // I want this to fully complete before moving on.

        // post stake
        const newAddressBalance = (await nftContract.balanceOf(address)).toNumber();
        const newStakedBalance = (await stakingContractAddress.numStaked(address)).toNumber();

        console.log(`newAddressBalance: ${newAddressBalance}`) // should be 0 but is still 1
        console.log(`newStakedBalance: ${newStakedBalance}`) // should be 1 but is stil 0
        
        expect(newStakedBalance).toEqual(addressBalance);
        expect(newAddressBalance).toEqual(stakedBalance);

    });

Here is the stake function:

async function stake(tokenId, _address) {
    try {
        const tx = await nftContract['safeTransferFrom(address,address,uint256,bytes)'](
            _address, // from
            stakingContractAddress, // to
            tokenId,
            gas_price
        );
        await tx.wait(); // this is meant to wait until the transaction is mined on-chain
    } catch (err) {
        logger.info({message: err});
        process.exit(1);
    }
}

I have tried adding in at deliberate wait (below) right after the stake function is called in the test. But this has no effect. It also felt like it shouldn't be needed, as the transaction with the local blockchain should complete instantly.

function wait(ms){
    console.log(`waiting ${ms /1000} seconds`)
    var start = new Date().getTime();
    var end = start;
    while(end < start + ms) {
      end = new Date().getTime();
   }
 }

I've spent so much time trying to find a solution to this already with no luck.

Any help would be greatly appreciated!

Ben Naylor
  • 21
  • 1
  • have you tried `stake(tokenId, address).then(() => { /** assertions in here */ })` ? You **might** require to have return statements in your stake try and catch blocks. – hanorine Feb 23 '22 at 18:40
  • Alternatively, you could mock the stake method and use `mockResolvedValue` and `mockRejectedValue` as ways to help you with this unit test while testing the stake method on its own. – hanorine Feb 23 '22 at 18:42
  • [Here](https://stackoverflow.com/a/51045733/7309041) is something to try that might help resolve the promise. – hanorine Feb 23 '22 at 18:45
  • Thank you very much for your response! I have already tried what you suggested first with the .then(). I did also try using flushPromises, as suggested in the other thread you linked to. So far I haven't had any success. – Ben Naylor Feb 24 '22 at 09:33
  • I feel like I may be doing something fundamentally wrong, however. I am importing the stake function into my test file with the following line: ```const stake = require("./auto_staker");``` The full auto_staker script can be found here: https://github.com/0xnaylor/dark_forest_auto_staker/blob/main/scripts/auto_staker.js However, when I call the stake function in my test, the auto_staker file is just executed from top to bottom. As soon as execution reaches a promise (line 44) the promise in my test resolves without ever calling the stake function. – Ben Naylor Feb 24 '22 at 09:33
  • Am I structuring my code completely wrong or something? – Ben Naylor Feb 24 '22 at 09:34
  • Maybe each function needs to be moved into its own independent module. – Ben Naylor Feb 24 '22 at 09:52

1 Answers1

2

So after a bit of thought, I restructured the entire application to make it more modular and testable.

The inital application was a single script, which did work but was not testable.

The stake method, among others, is now in its own module and I have been able to successfully test the functionalion.

Moral of this story - Write modular code and think about testing from the start.

Ben Naylor
  • 21
  • 1