Overview

The LocalNodeManager is a core utility of the @coinbase/onchaintestkit package, providing robust, programmatic control over local Ethereum (Anvil) nodes for end-to-end blockchain application testing. It is designed for seamless integration with Playwright and supports advanced scenarios such as parallel test execution, dynamic port allocation, chain state manipulation, and account impersonation.

Why is this important?

Testing blockchain applications often requires fine-grained control over the blockchain state, fast resets, and the ability to run multiple isolated nodes in parallel. LocalNodeManager abstracts away the complexity of managing Anvil nodes, enabling reliable, reproducible, and scalable test environments for dApps, smart contracts, and wallet integrations.

Architecture

Quick Start

import { LocalNodeManager } from '@coinbase/onchaintestkit'
import { baseSepolia } from 'viem/chains'

// Create a node manager with automatic port allocation
const node = new LocalNodeManager({
    chainId: baseSepolia.id,
    forkUrl: process.env.E2E_TEST_FORK_URL,
    forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"),
    hardfork: "cancun",
})

// Start the node
await node.start()
console.log(`Node running on port ${node.getPort()}`)

// Manipulate chain state
const snapshotId = await node.snapshot()
// ...run tests...
await node.revert(snapshotId)

// Clean up
await node.stop()

Key Features

Common Use Cases

Testing Smart Contracts

const node = new LocalNodeManager({
    chainId: 31337,
    defaultBalance: parseEther("100"),
})

await node.start()

// Deploy and test contracts
const provider = new ethers.JsonRpcProvider(node.rpcUrl)
// ... deploy contracts, run tests

Testing onchain Interactions

// Fork mainnet for realistic testing
const node = new LocalNodeManager({
    chainId: 1,
    forkUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY",
    forkBlockNumber: 18000000n,
})

await node.start()

// Test against real mainnet state

Time-Dependent Testing

await node.start()

// Test staking rewards after 30 days
await node.increaseTime(30 * 24 * 60 * 60)

// Mine a block to apply the time change
await node.mine()

Next Steps