Ben Naylor
Ben Naylor

Reputation: 31

Jest test completing before promise has resolved

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!

Upvotes: 0

Views: 1091

Answers (1)

Ben Naylor
Ben Naylor

Reputation: 31

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.

Upvotes: 3

Related Questions