Bird
Raised Fist0
Blockchain / Solidityprogramming~10 mins

Testing with ethers.js in Blockchain / Solidity - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Testing with ethers.js
Write test script
↓
Setup ethers.js provider and signer
↓
Deploy or connect to contract
↓
Call contract functions
↓
Check results with assertions
↓
Report pass/fail
↓
End test
The test script sets up ethers.js, deploys or connects to a contract, calls functions, checks results, and reports success or failure.
Execution Sample
Blockchain / Solidity
import { expect } from 'chai';
import { ethers } from 'hardhat';

describe('SimpleStorage', () => {
  it('stores and retrieves a value', async () => {
    const SimpleStorage = await ethers.getContractFactory('SimpleStorage');
    const storage = await SimpleStorage.deploy();
    await storage.deployed();

    await storage.store(42);
    expect(await storage.retrieve()).to.equal(42n);
  });
});
This test deploys a SimpleStorage contract, stores the number 42, then checks if retrieving returns 42.
Execution Table
StepActionEvaluationResult
1Import chai and ethersModules loadedReady to use expect and ethers
2Get contract factory for SimpleStorageFactory createdCan deploy contract
3Deploy SimpleStorage contractTransaction sentContract deployed at address
4Wait for deployment to completeDeployment minedContract ready
5Call store(42) on contractTransaction sentValue 42 stored
6Call retrieve() on contractReturns 42Value retrieved is 42
7Assert retrieved value equals 42Check passesTest passes
8Test endsNo errorsTest suite completes successfully
💡 Test ends after assertion passes confirming contract stores and retrieves value correctly
Variable Tracker
VariableStartAfter Step 3After Step 5After Step 6Final
SimpleStorageundefinedContract factory objectContract factory objectContract factory objectContract factory object
storageundefinedContract instance deployedContract instance deployedContract instance deployedContract instance deployed
storedValueundefinedundefined42 stored42 retrieved42
Key Moments - 3 Insights
Why do we wait for deployment to complete before calling store()?
Because the contract must be fully deployed on the blockchain before we can interact with it. See step 4 in execution_table where deployment is mined before proceeding.
What happens if the retrieved value does not equal 42?
The assertion in step 7 would fail, causing the test to fail and report an error. This ensures the contract logic is correct.
Why do we use async/await in the test?
Because blockchain calls are asynchronous and we must wait for transactions to complete before checking results, as shown in steps 3, 4, 5, and 6.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the value of storedValue after step 5?
Aundefined
BContract deployed
C42 stored
D42 retrieved
💡 Hint
Check the 'storedValue' row in variable_tracker after step 5
At which step does the test confirm the contract stores the value correctly?
AStep 7
BStep 5
CStep 3
DStep 6
💡 Hint
Look at the assertion step in execution_table where the test passes
If we remove await before storage.store(42), what likely happens?
ATest runs faster and passes
BTest fails because store transaction may not complete before retrieve
CNo change, test still passes
DDeployment fails
💡 Hint
Recall why async/await is used in key_moments and steps 5-6 in execution_table
Concept Snapshot
Testing with ethers.js:
- Import ethers and chai for blockchain and assertions
- Deploy or connect to contract asynchronously
- Call contract functions with await
- Use expect() to check results
- Tests pass if assertions succeed
- Async/await ensures correct order of blockchain calls
Full Transcript
This visual execution shows how to test a smart contract using ethers.js. First, the test script imports necessary modules. Then it gets the contract factory and deploys the contract, waiting for deployment to finish. Next, it calls the store function to save a value and waits for the transaction. Then it calls retrieve to get the stored value. Finally, it asserts the retrieved value equals the stored one. The test passes if the assertion succeeds. Variables like the contract instance and stored value change step by step. Key moments include waiting for deployment and using async/await to handle asynchronous blockchain calls. The quiz checks understanding of variable states and test flow.

Practice

(1/5)
1. What is the main purpose of using ethers.js in testing smart contracts?
easy
A. To create new blockchain networks
B. To design the user interface of a blockchain app
C. To mine new blocks on the blockchain
D. To interact with smart contracts and verify their behavior programmatically

Solution

  1. Step 1: Understand ethers.js role

    ethers.js is a library that helps developers interact with Ethereum smart contracts in code.
  2. Step 2: Identify testing purpose

    In testing, ethers.js lets you call contract functions and check if they behave as expected.
  3. Final Answer:

    To interact with smart contracts and verify their behavior programmatically -> Option D
  4. Quick Check:

    ethers.js tests contract behavior = A [OK]
Hint: Remember: ethers.js tests contracts by calling their functions [OK]
Common Mistakes:
  • Confusing ethers.js with UI design tools
  • Thinking ethers.js mines blocks
  • Assuming ethers.js creates blockchains
2. Which of the following is the correct way to get a signer from a provider in ethers.js?
easy
A. const signer = provider.signer();
B. const signer = provider.getSigner();
C. const signer = provider.getsigner();
D. const signer = provider.sign();

Solution

  1. Step 1: Recall ethers.js signer method

    The correct method to get a signer from a provider is getSigner() with capital S.
  2. Step 2: Check method spelling and casing

    Options B, C, and D have incorrect method names or casing.
  3. Final Answer:

    const signer = provider.getSigner(); -> Option B
  4. Quick Check:

    Correct method is getSigner() = A [OK]
Hint: Method names are case-sensitive; use getSigner() exactly [OK]
Common Mistakes:
  • Using wrong casing like signer() instead of getSigner()
  • Misspelling method names
  • Confusing signer with sign
3. Consider this ethers.js test code snippet:
const tx = await contract.setValue(42);
await tx.wait();
const value = await contract.getValue();
console.log(value);
What will be printed to the console?
medium
A. 42
B. undefined
C. Transaction hash
D. Error: contract.getValue is not a function

Solution

  1. Step 1: Understand transaction and wait

    The code calls setValue(42) on the contract, then waits for the transaction to confirm with tx.wait().
  2. Step 2: Retrieve stored value

    After confirmation, it calls getValue() which returns the stored value 42.
  3. Final Answer:

    42 -> Option A
  4. Quick Check:

    Confirmed setValue(42) then getValue() = 42 [OK]
Hint: Always wait for tx confirmation before reading updated state [OK]
Common Mistakes:
  • Not awaiting tx.wait() before reading value
  • Expecting transaction hash instead of value
  • Assuming getValue() is undefined
4. You wrote this test code but it throws an error:
const tx = contract.setValue(10);
await tx.wait();
What is the likely cause of the error?
medium
A. Missing await before contract.setValue(10)
B. tx.wait() is not a function
C. contract.setValue does not exist
D. Provider is not connected

Solution

  1. Step 1: Check async call to contract method

    contract.setValue(10) returns a Promise, so it must be awaited to get the transaction object.
  2. Step 2: Identify missing await issue

    Without await, tx is a Promise, which does not have a wait() method, causing the error.
  3. Final Answer:

    Missing await before contract.setValue(10) -> Option A
  4. Quick Check:

    Await async call before tx.wait() = C [OK]
Hint: Always await contract calls returning transactions before wait() [OK]
Common Mistakes:
  • Forgetting await before async contract calls
  • Assuming tx is transaction without awaiting
  • Not checking provider connection first
5. You want to test a smart contract function transfer(address to, uint amount) that emits an event Transfer. Which ethers.js testing approach correctly waits for the transaction and verifies the event was emitted?
hard
A. await contract.transfer(addr, 100); expect(tx.events[0].event).to.equal('Transfer');
B. const receipt = await contract.transfer(addr, 100); expect(receipt.events[0].event).to.equal('Transfer');
C. const tx = await contract.transfer(addr, 100); const receipt = await tx.wait(); expect(receipt.events[0].event).to.equal('Transfer');
D. const tx = contract.transfer(addr, 100); expect(tx.events[0].event).to.equal('Transfer');

Solution

  1. Step 1: Await the transaction call

    Use await to get the transaction object from contract.transfer.
  2. Step 2: Wait for transaction confirmation and get receipt

    Call tx.wait() to get the receipt which contains event logs.
  3. Step 3: Verify event in receipt

    Check receipt.events[0].event equals 'Transfer' to confirm event emitted.
  4. Final Answer:

    const tx = await contract.transfer(addr, 100); const receipt = await tx.wait(); expect(receipt.events[0].event).to.equal('Transfer'); -> Option C
  5. Quick Check:

    Await tx, wait receipt, check event = D [OK]
Hint: Always await tx, then wait for receipt to check events [OK]
Common Mistakes:
  • Not awaiting transaction before wait()
  • Trying to access events on tx instead of receipt
  • Ignoring event verification after transaction
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard