Skip to content

End-to-End Testing

The end-to-end tests drive a real, running Orchard with Playwright. Each test runs against a full stack brought up with Docker: a regtest Bitcoin node, Lightning nodes, a Cashu mint, and Orchard built from the repository source.

  • Docker with the Compose plugin.
  • Playwright’s browsers, installed once with npx playwright install.
  • For the AI tests only: Ollama reachable at host.docker.internal:11434.
  • For the mainchain tests only: a Bitcoin full node (bitcoind 26+) running on your host, so the stack’s pruned node can load a UTXO snapshot built from your local chain.

The tests run against five backend configurations, each a different combination of Lightning node, mint implementation, and database:

ConfigBitcoinLightningMintDatabase
lnd-nutshell-sqlitecorelndnutshellSQLite
cln-nutshell-postgrescoreclnnutshellPostgres
lnd-cdk-sqlitecorelndcdkSQLite
cln-cdk-postgrescoreclncdkPostgres
fake-cdk-postgrescdkPostgres

fake-cdk-postgres runs without Bitcoin or Lightning, to exercise Orchard when those services are absent.

To override defaults for your machine, copy the template to e2e/.env (gitignored) and uncomment what you need:

Terminal window
cp e2e/.env.example e2e/.env
VariableDefaultDescription
AI_MODELThe Ollama model the AI tests run against (for example llama3.2 or gemma3:4b). Pull it first with ollama pull <model>.

Each regtest stack runs a sidecar that mines one block on a fixed interval to keep the chain advancing (skipped on fake-cdk-postgres, which has no Bitcoin node).

VariableDefaultDescription
MINE_INTERVAL_SECONDS30Seconds between mined blocks.

Tunables for the cadence simulator:

VariableDefaultDescription
ACTIVITY_INTERVAL_SECONDS90Base delay between cycles.
ACTIVITY_JITTER_SECONDS15Random plus/minus jitter on that delay.
ACTIVITY_DISRUPT_SECONDS4How long each pause/unpause fault lasts.
ACTIVITY_DISRUPT_EVERY1Inject a fault every N cycles.
ACTIVITY_RECOVERY_TIMEOUT60Seconds to wait for a service to recover before aborting.
ACTIVITY_SEEDoptionalFix the RNG seed for reproducible cycle timing.

Point the mainchain tests and their bootstrap at your host Bitcoin node:

VariableDefaultDescription
BITCOIN_CLIbitcoin-cli on PATHFull path to your host’s bitcoin-cli.
BITCOIN_CLI_ARGSExtra args if your node uses rpcauth, for example -rpcuser=you -rpcpassword=secret.
HOST_BITCOIN_P2P_PORT8333The host port the stack’s pruned node connects to.

After loading the snapshot, the stack’s pruned mainchain node catches up to the chain tip once, using bitcoind’s fast defaults. On a constrained laptop you can throttle that container’s CPU and memory (slower catch-up, but it only happens once):

VariableDefaultDescription
MAINCHAIN_PARauto (all cores)Script-verification threads; the biggest CPU lever.
MAINCHAIN_DBCACHE450UTXO cache in MiB; the biggest RAM lever.
MAINCHAIN_BLOCKSONLY0Set 1 to disable transaction relay.
MAINCHAIN_MAXMEMPOOL300Mempool ceiling in MiB.
  1. Bring up every stack. This blocks until they are all healthy:

    Terminal window
    npm run e2e:up
  2. Run the test suite:

    Terminal window
    npm run e2e:test
  3. Tear the stacks down when you are done. This removes their volumes:

    Terminal window
    npm run e2e:down

To work with a single stack instead, pass its config name to e2e:up and e2e:down, and filter e2e:test by project. Each project is named <config>:<port>:

Terminal window
npm run e2e:up cln-cdk-postgres
npm run e2e:test -- --project=cln-cdk-postgres:3323
npm run e2e:down cln-cdk-postgres

To watch a stack while it runs, use npm run e2e:logs <config>; to list its services, npm run e2e:ps <config>.

The AI tests use a separate config and need Ollama running:

Terminal window
npm run e2e:test:ai

A Supertest-based API harness runs separately from the Playwright suite:

Terminal window
npm run test:server:e2e

A cadence simulator can drive sustained, repeating traffic against the running stacks while you run tests, including fault injection. Start a runner on every stack, check on them, then stop them when you are done:

Terminal window
npm run e2e:sim:up # start
npm run e2e:sim:status # check
npm run e2e:sim:down # stop

To work with a single stack instead, pass its config name. Following a runner’s logs is per-stack only — against all they would interleave:

Terminal window
npm run e2e:sim:up cln-cdk-postgres
npm run e2e:sim:logs cln-cdk-postgres # follow this stack
npm run e2e:sim:down cln-cdk-postgres

One stack (cln-nutshell-postgres) can run against a real mainnet Bitcoin node to exercise chain features. It needs a one-time snapshot, built with npm run e2e:bootstrap-mainchain, and a bitcoind running on your host. See the repository’s e2e README for the host requirements.

Every spec under e2e/specs must carry at least one tag (for example @canary, @lightning, @cdk, @postgres) declaring which stacks it is meaningful for. A spec with no tag matches no stack and silently does not run.

For the full configuration matrix, network topologies, exposed ports, and tag reference, see e2e/README.md in the repository.


Development End-to-End Testing

Last updated: