Quickstart
This page gets you from install to a working scenario quickly.
Prerequisites
vitesttest runnerviemclients/utilitiesanvilon yourPATH(for local runtime/fork execution)
For forked examples, set:
export MAINNET_RPC_URL="https://..."Install
Choose one package manager:
bun add -D @statecraft/vitest vitest viemnpm install -D @statecraft/vitest vitest viemStep 1: first passing scenario (local chain)
Start with withChain() so you can run without external RPC:
import { test, expect } from "vitest";
import { parseEther } from "viem";
import { scenario, withChain, withFundedWallet } from "@statecraft/vitest";
test(
"funded wallet on local chain",
scenario(
withChain(),
withFundedWallet({
balance: parseEther("1"),
}),
async ({ wallet, publicClient }) => {
const const balance: bigintbalance = await publicClient.getBalance({ address: wallet });
expect<bigint>(actual: bigint, message?: string): Assertion<bigint> (+1 overload)expect(balance).toBe(parseEther("1"));
},
),
);Step 2: switch to a pinned fork
Once the local scenario works, move to withFork() for real mainnet state while staying deterministic:
import { test, expect } from "vitest";
import { parseEther } from "viem";
import { scenario, withFork, withFundedWallet } from "@statecraft/vitest";
test(
"funded wallet on pinned mainnet fork",
scenario(
withFork({
rpcUrl: process.env.MAINNET_RPC_URL!,
blockNumber: 22_000_000n,
}),
withFundedWallet({
balance: parseEther("1"),
}),
async ({ wallet, publicClient }) => {
const balance = await publicClient.getBalance({ address: wallet });
expect(balance).toBe(parseEther("1"));
},
),
);Next steps
packages/examples/examples/scenarios.test.ts includes:
- fresh local chain + funded wallet
- forked mainnet + funded wallet + real contract call
- forked mainnet + funded wallet + USDC via
withFundedWallet.erc20orwithErc20Balance - runtime bytecode injection with
withContracts - real deployment flow with
withDeployments - suite-scoped runtime reuse with
withExternalRuntimepluswithSnapshot
When you are ready for fixture ordering, lifecycle terminology (managed vs external), and typing behavior, read Core concepts.
ERC-20 balances (optional)
On Anvil-style local/forked nodes, you can seed token balances in two ways:
withFundedWallet({ erc20: [...] })when recipient is the scenario walletwithErc20Balance({ token, amount, to? })when you need explicit recipient control
See Core concepts for behavior and caveats.