Writing TypeScript tests
Solidity tests are great for unit testing, but sometimes you need more complex tests that interact with multiple contracts or simulate real-world scenarios. For that, use TypeScript tests.
Create a new file at test/Counter.ts with the following content to write a simple TypeScript test that interacts with the Counter contract:
import assert from "node:assert/strict";import { describe, it } from "node:test";
import { network } from "hardhat";
describe("Counter", async function () { const { viem } = await network.connect(); const publicClient = await viem.getPublicClient();
it("The sum of the Increment events should match the current value", async function () { const counter = await viem.deployContract("Counter"); const deploymentBlockNumber = await publicClient.getBlockNumber();
// run a series of increments for (let i = 1n; i <= 10n; i++) { await counter.write.incBy([i]); }
const events = await publicClient.getContractEvents({ address: counter.address, abi: counter.abi, eventName: "Increment", fromBlock: deploymentBlockNumber, strict: true, });
// check that the aggregated events match the current value let total = 0n; for (const event of events) { total += event.args.by; }
assert.equal(total, await counter.read.x()); });});This test:
- Deploys an instance of the
Countercontract using Viem. - Calls the
incByfunction multiple times. - Gets all the events emitted by the contract during those calls.
- Checks that the sum of the
byarguments in theIncrementevents matches the current value ofxin the contract.
Run the TypeScript tests:
npx hardhat test nodejspnpm hardhat test nodejsyarn hardhat test nodejsBesides being written in TypeScript, there are two important differences between these tests and the Solidity tests you wrote earlier:
- TypeScript tests use a test runner from the TypeScript ecosystem. Hardhat works with any test runner. In this case, you’re using the built-in
node:testmodule. - While Solidity tests run directly on the EVM, TypeScript tests run on a locally simulated network. Each time a test calls
network.connect(), it gets a fresh blockchain state, and any changes made during the test are discarded at the end. This is useful for integration tests, where you want a more realistic environment with proper blocks and transactions.
You can run both Solidity and TypeScript tests together by using the main test task:
npx hardhat testpnpm hardhat testyarn hardhat test