Skip to content

cmu test ​

cmu test compiles smart contracts and executes the automated test suite against an ephemeral local DevNet. The network is spun up automatically before tests run and shut down immediately after, leaving no persistent state.

Usage ​

bash
cmu test [options]

NODE.JS 22 REQUIRED

The test DevNet needs Node.js 22 or newer, even though the CLI itself runs on Node 20.12+. The check runs before the compile, so a too-old runtime fails immediately rather than after spending a build:

bash
error: test failed
the local DevNet needs Node.js 22 or newer, but this is Node v20.12.0.
    npm skips EDR's native binary on older Node without reporting it, so no chain can start.
hint: upgrade Node.js, or install a version manager such as nvm or fnm.

Options ​

FlagDescription
--gasReport gas used by transactions during the run.
--allow-corsAllow cross-origin browser access to the test RPC proxy. Off by default to prevent DNS rebinding.
-y, --yesSkip the confirmation prompt before executing project code.

-v, --verbose is available globally; see Global Options.

Requirements ​

  • A test/ directory must exist in the project root containing .ts or .js test files.
  • Test files are executed using Mocha as the test runner.
  • TypeScript test files are loaded via ts-node/register automatically.

WARNING

If the test/ directory does not exist, the command exits with an error before starting the DevNet.

Executing Project Code ​

Before anything is compiled, cmu test lists every project file it is about to execute as code: cmu.config.ts/js and the test files mocha will run. Those are every .ts file under test/ (recursively) when there is at least one, otherwise every .js file. It then asks for confirmation:

bash
warning: the following project files will be executed as code:
      cmu.config.ts  ->  /home/you/my-token/cmu.config.ts
      Template.test.ts  ->  /home/you/my-token/test/Template.test.ts

    They run with your full environment, including anything set in .env or your
    shell, and can do anything your user account can. The test files also get a
    PRIVATE_KEY for a devnet account derived from the devnet mnemonic. This is
    the same trust model as Hardhat, Foundry and Truffle; see the 'Trust Model'
    section of the README.

? Execute these files? (y/N)

The prompt defaults to no. -y, --yes skips it; in a non-interactive session the command refuses rather than continuing. You are asked once: the compile that follows does not ask again. See the trust model.

The PRIVATE_KEY the test files get is the one described under Environment Injection, for the ephemeral DevNet, not your session key.

Pre-Test Steps ​

Before running any test file, the command performs the following steps automatically:

  1. Check the runtime — refuses immediately on Node older than 22.
  2. Confirm trust — lists cmu.config.ts/js and the test files, and asks once. See Executing Project Code.
  3. Compile — triggers cmu compile to ensure all contract artifacts are up to date.
  4. Start ephemeral DevNet — starts an in-process Hardhat 3 network and fronts it with a local JSON-RPC proxy on port 8555 with Chain ID 1912.
  5. Inject environment — passes network credentials to the test process via environment variables.

Ephemeral DevNet ​

The test DevNet is created fresh for every cmu test run and destroyed immediately after all tests complete.

ParameterValue
RPC endpointhttp://127.0.0.1:8555
Chain ID1912
Accounts10 pre-funded accounts
Default balance100 ETH each
LoggingQuiet (suppressed)

The chain is an in-process Hardhat 3 network running on EDR, created with a config override and served through the CLI's own JSON-RPC proxy rather than Hardhat's node task.

The first generated account's private key is automatically used as the deployer for test transactions. Accounts are derived from a random mnemonic on every run, so the deployer address differs between invocations.

WARNING

Port 8555 is never freed on your behalf. If something already holds it, the run stops rather than killing the process that owns it:

bash
error: test failed
port 8555 is already in use.
hint: stop the process using it, then run `cmu test` again.

Free the port yourself and re-run. This applies identically on every platform.

RPC Access Control ​

The test RPC proxy listens only on 127.0.0.1 and additionally rejects requests that look like they originate from a web page. A request is refused when it carries an Origin header, or when its Host header is not one of 127.0.0.1:8555, localhost:8555, or [::1]:8555.

Refused requests receive HTTP 403 with a JSON-RPC error of code -32600:

bash
Forbidden: cross-origin or non-local request rejected. Pass --allow-cors to cmu test to allow browser access.

This protects the unlocked test accounts from DNS-rebinding attacks, where a malicious page resolves its own hostname to 127.0.0.1 and issues signed transactions against the local node.

WARNING

--allow-cors disables that protection and responds with Access-Control-Allow-Origin: *, letting any website reach the test RPC and its pre-funded accounts while cmu test is running. Use it only when a browser-based test harness genuinely requires it. The command prints a warning at startup when the flag is active.

Environment Injection ​

The following variables are injected into the test process at runtime:

VariableValue
CMU_RPC_URLhttp://127.0.0.1:8555
CMU_CHAIN_ID1912
PRIVATE_KEYPrivate key of account #0

These variables are available inside test files for constructing providers and signers.

Test Runner ​

Test files are detected and executed based on extension:

File TypeRunner Command
.tsnpx mocha -r ts-node/register test/**/*.ts
.jsnpx mocha test/**/*.js

If the test/ directory contains .ts files, the TypeScript runner is used for the entire suite.

Gas Profiler ​

When --gas is provided, the command generates a gas usage report after all tests complete by iterating over every block mined during the test session.

bash
=========================================================================================
Gas profile
=========================================================================================
| Block | Transaction Hash                                                   | Gas Used |
-----------------------------------------------------------------------------------------
| 1     | 0x...                                                              | 21000    |
| 2     | 0x...                                                              | 84123    |
-----------------------------------------------------------------------------------------
Total gas used: 105123

INFO

Reporting is a convenience, not part of the run. If the profiler fails it prints a warning and the already-decided test result stands:

bash
warning: could not produce the gas report; the tests themselves were unaffected.

Pass -v to see the underlying error. The DevNet is still closed cleanly either way.

Shutdown ​

After all tests and the gas profiler complete, the ephemeral DevNet is closed automatically:

bash
CointMU DevNet stopped.

The shutdown runs in a finally block, ensuring the DevNet is always stopped even if the test suite fails.

Success Output ​

bash
Compiling contracts...
Compiled StandardERC20
Starting the CointMU DevNet...

========================================
Running tests with Mocha
========================================

[test output]

All tests passed.
CointMU DevNet stopped.

If any test fails, the command exits with code 1:

bash
error: test failed
test run exited with code 1