Test Plugin¶
The test plugin (hardhat-arb-test) wraps Hardhat's test runner with Stylus support. It handles mode selection (container vs host), Solidity pre-compilation, and toolchain validation.
How arb:test Works¶
The task decides between two runners based on the --host flag or stylus.test.useHostToolchain config:
- Resolve mode Check
--hostflag or config. CallsetTestHostMode()from the deploy plugin so thatstylusViem.deployContract()uses the correct deploy path during tests. - Run tests Delegate to the host runner or the container runner.
- Reset mode Clear the host mode flag in a
finallyblock.
Container Mode (Default)¶
Container mode bypasses the Hardhat test runner and spawns node --test directly with --test-concurrency=1. This forces sequential execution to avoid overwhelming Docker with parallel devnode + compilation containers.
The flow:
- Warn Print a message explaining that tests run sequentially and suggesting
--hostfor faster parallel execution. - Set environment
HH_TEST=true, injecttsximport viaNODE_OPTIONS(so TypeScript tests run without a separate compile step). - Compile Solidity Run
hardhat buildunless--no-compileis set. - Resolve test files Find all
*.test.tsfiles in the configured test directory, or use the explicit file list. - Build args Assemble
node --testarguments (concurrency=1, grep, only, etc.). - Spawn Run
node --testas a child process and wait for exit.
If the test runner exits with a non-zero code or is killed by a signal, the task sets process.exitCode = 1.
Host Mode¶
Host mode delegates to Hardhat's built-in test runner (test:nodejs task), which runs tests in parallel. Before delegating, it validates host toolchain requirements.
The flow:
- Discover contracts Uses
discoverStylusContractsFromSources()to find all Stylus contracts and their required toolchains. - Validate toolchains Calls
validateAllToolchains()to checkrustup,cargo-stylus, each required toolchain, andwasm32-unknown-unknowntargets. Results are cached per unique toolchain set so repeated test runs skip validation. - Delegate Calls
hre.tasks.getTask(['test', 'nodejs']).run()with the original test options.
Preflight Cache¶
The state/preflight-cache.ts module avoids re-validating toolchains on every test run. It creates a cache key from the sorted, deduplicated toolchain versions. If that exact set has already been validated in this process, validation is skipped.
How Stylus Contracts Get Deployed in Tests¶
The test plugin itself does not deploy contracts. That happens through the deploy plugin's stylusViem network hook:
- Test calls
network.create()the node plugin auto-starts a temp Arbitrum node. - Test calls
stylusViem.deployContract('my-contract')the deploy plugin's hook discovers the contract, exports its ABI, and runscargo stylus deploy(in Docker or on host, depending on the mode set byarb:test). - The hook returns a viem contract instance with
.read,.write,.getEvents.
Integration Points¶
hardhat-arb-deployProvidessetTestHostMode()to coordinate the deploy mode during tests, and thestylusViemnetwork hook that handles actual deployment.hardhat-arb-utilsProvidesdiscoverStylusContractsFromSourcesandvalidateAllToolchainsfor host-mode preflight checks, andcreatePluginErrorfor error handling.