Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .test_patterns.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ tests:
- regex: "src/single-node/fees/private_payments"
owners:
- *phil
- regex: "src/e2e_token_contract/access_control"
- regex: "src/automine/token/access_control"
error_regex: "HttpRequestError: HTTP request failed."
owners:
- *charlie
- regex: "src/e2e_lending_contract"
- regex: "src/automine/token/lending"
error_regex: "✕ Depositing"
owners:
- *lasse
- regex: "src/e2e_lending_contract"
- regex: "src/automine/token/lending"
error_regex: "✕ Repay"
owners:
- *lasse
Expand Down Expand Up @@ -301,6 +301,11 @@ tests:
owners:
- *palla

- regex: "src/automine/.*\\.test\\.ts"
flake_group_id: e2e-p2p-epoch-flakes
owners:
- *palla

- regex: "p2p/src/client/test/.*\\.test\\.ts"
flake_group_id: e2e-p2p-epoch-flakes
owners:
Expand Down Expand Up @@ -396,7 +401,7 @@ tests:
- *palla

# http://ci.aztec-labs.com/153f5dcbb0f3799c
- regex: "src/e2e_offchain_payment.test.ts"
- regex: "src/automine/effects/offchain_payment.parallel.test.ts"
error_regex: "✕ reprocesses an offchain-delivered payment after an L1 reorg"
owners:
- *martin
Expand Down
216 changes: 189 additions & 27 deletions yarn-project/end-to-end/README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,215 @@
# End to End
# End-to-end tests

This package includes end-to-end tests that cover Aztec's main milestones.
These can be run locally either by starting anvil on a different terminal.
This package holds Aztec's end-to-end (e2e) tests: full-stack scenarios that spin up an Aztec node (or
several), a PXE, and an L1 (anvil) and exercise the system the way a real deployment would. It is the
integration layer above the per-package unit tests.

```
anvil -p 8545 --host 0.0.0.0 --chain-id 31337
```
> **Two audiences.** The top of this document is a quick orientation for humans. The
> [Reference for agents](#reference-for-agents) section at the bottom is the detailed, exhaustive
> version — read that when you are placing, moving, or wiring up a test.

and then running
## Quick start

```
yarn test
Run a single test (spawns its own in-process anvil):

```bash
yarn test:e2e src/automine/token/transfer.parallel.test.ts
yarn test:e2e src/single-node/block-building/block_building.test.ts -t 'rejects double spend'
```

Or by running
Turn up logging with `LOG_LEVEL` (`verbose` is the useful default; `debug:sequencer,archiver` scopes it):

```bash
LOG_LEVEL=verbose yarn test:e2e src/single-node/proving/empty_blocks.test.ts
```
yarn test:integration
```

which will spawn the two processes.
Compose-based tests (those under `src/composed/`) need a running local network — see
[Compose / HA / web3signer tests](#compose--ha--web3signer-tests).

## Test categories

Tests are grouped by **node topology** — the shape of the network a test needs. The top-level folder is
the category; the second level names the behavior under test. Each category owns a base class that builds
its environment, so a test file only describes the scenario, not the wiring.

| Category | Topology | A test belongs here when… | README |
|---|---|---|---|
| [`automine/`](src/automine/README.md) | One node, deterministic `AutomineSequencer` — one block per tx, no committee/prover/validator. Fast. | it exercises contract or protocol behavior that doesn't depend on real block-building or consensus (transfers, nested calls, note discovery, tx semantics). | yes |
| [`single-node/`](src/single-node/README.md) | One node, production sequencer (interval block production), optional prover. | it asserts on sequencer, proving, partial-proof, L1-reorg, recovery, fee, or cross-chain behavior on a single sequencer. | yes |
| [`multi-node/`](src/multi-node/README.md) | N validators on an in-memory mock-gossip bus. | it needs a committee: consensus, attestations, slashing, governance, or multi-validator block production. | yes |
| `p2p/` | Real libp2p transport between nodes. | the networking transport itself is under test (gossip, rediscovery, req/resp). | — |
| [`infra/`](src/infra/README.md) | Targets a deployed/external network (local anvil or a public testnet). | its concern is deployment or network targeting, not a specific protocol behavior. | yes |

A handful of tests live **outside** this package, next to the code they test — see
[Tests that live elsewhere](#tests-that-live-elsewhere). Other non-category test groups (`composed/`,
`guides/`, `bench/`) are described in the reference section.

## Where does my test go?

1. **Does it need real networking transport?** → `p2p/`.
2. **Does it need a validator committee (consensus/slashing/governance)?** → `multi-node/`.
3. **Does it assert on the production sequencer, proving, reorgs, fees, or cross-chain flows?** →
`single-node/`.
4. **Is it pure contract/protocol behavior that's happy with one-block-per-tx?** → `automine/` (the
default home for most contract tests).
5. **Is it really a unit/integration test of one package with no Aztec node?** → it probably belongs in
that package, not here (see [Tests that live elsewhere](#tests-that-live-elsewhere)).

When in doubt, prefer `automine/` for contract behavior and `single-node/` for anything that watches the
chain advance.

---

## Reference for agents

This section is the detailed contract for adding, moving, and wiring tests. It assumes you've read the
overview above.

### Category base classes

Each category centralizes its environment in a base class. The hierarchy:

- `single-node/single_node_test_context.ts` → **`SingleNodeTestContext`**. Owns the environment
(in-process anvil + L1 deploy), node spawning (`createNonValidatorNode`, `createProverNode`), the
`ChainMonitor`, and the epoch/checkpoint/proof-window/reorg waiters.
- `multi-node/multi_node_test_context.ts` → **`MultiNodeTestContext extends SingleNodeTestContext`**.
Adds the N-validator topology over a mock-gossip bus, inheriting the base environment and waiters.
- `automine/automine_test_context.ts` → **`AutomineTestContext`**. A sibling of `SingleNodeTestContext`
(both wrap `fixtures/setup.ts:setup()`), but fixes the automine topology and makes `AUTOMINE_E2E_OPTS`
the default. Exposes `markProvenAndWarp`, `registerContract`, `applyManualParentChild`.
- `p2p/p2p_network.ts` → **`P2PNetworkTest`**. Real libp2p; node creation goes through
`setup_p2p_test.ts`.
- `infra/` has no shared base — its tests target a network selected by `L1_CHAIN_ID` (local anvil in CI,
a public testnet with credentials).

All of the above ultimately wrap `fixtures/setup.ts:setup(numberOfAccounts, opts)`, the single entry point
that deploys L1 contracts, starts the node(s), and provisions a PXE and accounts.

### Setup factories

Categories expose thin factories over their base's static `setup`, named by what the test wants, so a test
calls the factory instead of spreading option presets:

- `single-node/setup.ts`: `setupWithProver` (fake in-process prover — the single-node default) and
`setupBlockProducer` (no prover; raises `aztecProofSubmissionEpochs` to `1024` so unproven blocks
aren't pruned, and points the PXE at `syncChainTip: 'proposed'`).
- `automine` tests call `AutomineTestContext.setup({ numberOfAccounts })` directly.

### The harness pattern (domain setup on top of a category)

You can also run this by `docker-compose up` which will spawn 2 different containers for Anvil and the test runner.
A test suite with bespoke domain setup does **not** fork `setup()`. It subclasses the category base and
overrides a `protected hydrateFromContext(context)` split out of `setup`, so it reuses the base's
rollup/epoch-cache/chain-monitor/waiter/teardown machinery while adding its own domain state. Examples:

You can run a single test by running `yarn test:compose <test_name>`.
- `single-node/prover/` → `FullProverTest` (real Barretenberg env) extends `SingleNodeTestContext`.
- `single-node/fees/` → `FeesTest`; `single-node/cross-chain/` → `CrossChainMessagingTest`.
- `automine/token/` → `TokenContractTest` and `BlacklistTokenContractTest` extend `AutomineTestContext`
and run their `TokenSimulator`/snapshot setup after `super.setup()`.

## Running tests against legacy contract artifacts
When two suites share behavior: if their public APIs are nearly identical, use inheritance; if behavior
overlaps but APIs differ, compose. Don't duplicate a category's environment wiring.

### The `.parallel` suffix

CI splits each **top-level** `it` in a `.parallel.test.ts` file into its own docker job (via
`extract_test_names` in `bootstrap.sh`). Rules:

- A file with more than one top-level `it` **must** carry the `.parallel.test.ts` suffix.
- A file with a single top-level `it` (even if it has many `it`s nested inside sub-`describe`s — those
don't count) is a plain `.test.ts`.
- Each file has exactly one top-level `describe`, named to match its path
(e.g. `describe('automine/token/transfer', …)`).

### CI test discovery — `bootstrap.sh`

`end-to-end/bootstrap.sh` enumerates tests in two arrays, and a test must appear in the relevant one or it
**won't run in CI**:

- `test_cmds` (~line 37) — the standard run.
- `compat_test_cmds` (~line 290) — the forward/legacy-compat run (a subset).

Each leaf folder needs its own single-level glob line (e.g. `src/automine/token/*.test.ts`) in each array;
globs are not recursive, so every sub-folder is listed explicitly. Folders that organize by behavior get
one line per leaf. Bespoke handling to be aware of:

- **`avm_simulator`** (`automine/simulation/avm_simulator.test.ts`) has a dedicated line in `test_cmds`
that sets `DUMP_AVM_INPUTS_TO_DIR` (feeds the downstream `avm_check_circuit` job) and is therefore
excluded from the generic `simulation/` glob there (`!(avm_simulator)`). In `compat_test_cmds` it runs
as a regular test (no dump line), so it is **not** excluded there.
- **`kernelless_simulation`** is excluded from `compat_test_cmds` only.

After editing the arrays, confirm every `*.test.ts` resolves through exactly one line (no duplicate, no
omission). Per-test bash `TIMEOUT` overrides live in the `case` block in `test_cmds` and must stay in sync
with the test's `jest.setTimeout`.

### Flaky tests — `.test_patterns.yml`

Flaky/owner entries live in `.test_patterns.yml` at the **git root** (not in this package), keyed on the
test path. A bare entry flags the test as flaky whenever it fails; add `error_regex` to flag only on a
matching message; `skip: true` disables it. Blanket regex entries (e.g. `src/automine/.*\.test\.ts`) are
depth-agnostic and survive folder renames; path-specific entries must be updated when a file moves.

### Compose / HA / web3signer tests

`src/composed/` tests run against a **running local network** rather than an in-process stack, via
`scripts/run_test.sh` in different modes:

- `src/composed/*.test.ts` → `compose` mode (e.g. `e2e_persistence`, `uniswap_trade_on_l1_from_l2`,
`e2e_cheat_codes` — the compose variant, distinct from the relocated unit-style one).
- `src/composed/web3signer/*.test.ts` → `web3signer` mode (remote-signer scenarios).
- `src/composed/ha/*.test.ts` → `ha` mode (high-availability multi-process scenarios).
- `src/guides/*.test.ts` → tutorial/guide flows; `src/bench/` → benchmarks (see `bench_cmds`).

Run one compose test locally with `yarn test:compose <name>` (anvil + the test runner are spawned for
you), or `docker-compose up` for separate containers.

### Tests that live elsewhere

Tests with **no Aztec node** that exercise one package belong in that package, not here:

- L1 cheat-code behavior (`EthCheatCodes`/`RollupCheatCodes` against raw anvil) → `@aztec/ethereum`
(`ethereum/src/test/eth_cheat_codes.test.ts`).
- The `SequencerPublisher` integration test (anvil + L1 deploy, no node) → `@aztec/sequencer-client`
(`sequencer-client/src/publisher/`).

These run in their own package's test lane (both packages already run anvil-backed integration tests).

### Support directories (not test categories)

- `fixtures/` — the shared `setup()`, option presets (`fixtures.ts`), `CrossChainTestHarness`,
`l1_to_l2_messaging`, and common utils.
- `shared/` — shared test bodies and `timing_env.mjs`, a **custom jest `testEnvironment`** referenced from
this package's `package.json`. `yarn prepare` / the package-json check will try to revert it to the
default — don't let it.
- `simulators/` — in-TS reference models (`TokenSimulator`, `LendingSimulator`) used to assert contract
behavior.
- `test-wallet/`, `bench/`, `spartan/`, `quality_of_service/`, `forward-compatibility/` — helpers,
benchmarks, and network/ops tests outside the topology categories.

### Running tests against legacy contract artifacts

To verify that contracts deployed from a previous release still work against the current stack, set
`CONTRACT_ARTIFACTS_VERSION` to a published version of `@aztec/noir-contracts.js` / `@aztec/noir-test-contracts.js`:
`CONTRACT_ARTIFACTS_VERSION` to a published version of `@aztec/noir-contracts.js` /
`@aztec/noir-test-contracts.js`:

```
CONTRACT_ARTIFACTS_VERSION=4.1.3 yarn test:e2e src/e2e_amm.test.ts
```bash
CONTRACT_ARTIFACTS_VERSION=4.1.3 yarn test:e2e src/automine/token/transfer.parallel.test.ts
```

Only the JSON artifact files (`.../artifacts/*.json`) are redirected. The TypeScript wrapper classes
(e.g. `TokenContract`) continue to load from the current workspace and use the current `@aztec/aztec.js` — so this
exercises whether a deployed contract's ABI / bytecode / notes still work through the *new* client, not whether the
legacy wrapper code still imports cleanly.
(e.g. `TokenContract`) continue to load from the current workspace and use the current `@aztec/aztec.js` —
so this exercises whether a deployed contract's ABI / bytecode / notes still work through the *new* client,
not whether the legacy wrapper code still imports cleanly.

The first run downloads the pinned packages into `.legacy-contracts/<version>/node_modules/` (cached across runs). A
startup banner and a per-redirect line are printed to stderr so you can confirm the legacy artifacts were actually
loaded:
The first run downloads the pinned packages into `.legacy-contracts/<version>/node_modules/` (cached across
runs). A startup banner and a per-redirect line are printed to stderr so you can confirm the legacy
artifacts were actually loaded:

```
[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=4.1.3
[legacy-contracts][jest] redirecting @aztec/noir-contracts.js/artifacts/*.json -> .legacy-contracts/4.1.3/...
[legacy-contracts][jest] redirected token_contract-Token.json -> /abs/.../.legacy-contracts/4.1.3/.../token_contract-Token.json
```

When `CONTRACT_ARTIFACTS_VERSION` is unset the test run is byte-identical to the default behaviour. The cache is
populated automatically on first use.
When `CONTRACT_ARTIFACTS_VERSION` is unset the test run is byte-identical to the default behaviour. The
cache is populated automatically on first use.
25 changes: 21 additions & 4 deletions yarn-project/end-to-end/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,19 @@ function test_cmds {
else
echo "$prefix:NAME=e2e_prover_full_fake FAKE_PROOFS=1 $run_test_script simple single-node/prover/full"
fi
echo "$prefix:TIMEOUT=30m:NAME=e2e_avm_simulator $(set_dump_avm e2e_avm_simulator) $run_test_script simple src/e2e_avm_simulator.test.ts"
echo "$prefix:TIMEOUT=30m:NAME=automine/simulation/avm_simulator $(set_dump_avm e2e_avm_simulator) $run_test_script simple src/automine/simulation/avm_simulator.test.ts"

local tests=(
# List all standalone and nested tests, except for the ones listed above.
src/e2e_*/*.test.ts
src/automine/*.test.ts
src/automine/contracts/*.test.ts
src/automine/contracts/deploy/*.test.ts
src/automine/contracts/nested/*.test.ts
src/automine/token/*.test.ts
src/automine/accounts/*.test.ts
src/automine/effects/*.test.ts
src/automine/simulation/!(avm_simulator).test.ts
src/single-node/block-building/*.test.ts
src/single-node/proving/*.test.ts
src/single-node/l1-reorgs/*.test.ts
Expand Down Expand Up @@ -296,6 +304,14 @@ function compat_test_cmds {

local tests=(
src/e2e_*/*.test.ts
src/automine/*.test.ts
src/automine/contracts/*.test.ts
src/automine/contracts/deploy/*.test.ts
src/automine/contracts/nested/*.test.ts
src/automine/token/*.test.ts
src/automine/accounts/*.test.ts
src/automine/effects/*.test.ts
src/automine/simulation/!(kernelless_simulation).test.ts
src/single-node/fees/*.test.ts
src/single-node/cross-chain/*.test.ts
src/single-node/bot/*.test.ts
Expand All @@ -306,9 +322,10 @@ function compat_test_cmds {
)
for test in "${tests[@]}"; do
local name
if [[ "$test" == src/p2p/* ]]; then
# The p2p/ folder has no `e2e_` prefix to strip; flatten its path into an e2e_p2p_<file> name
# (matching the historical e2e_p2p/<file> names) by dropping "src/", ".test.ts", and slashes.
if [[ "$test" == src/p2p/* || "$test" == src/automine/* ]]; then
# The p2p/ and automine/ folders have no `e2e_` prefix to strip; flatten their path into an
# e2e_<path> name (matching the historical e2e_p2p/<file> names) by dropping "src/", ".test.ts",
# and slashes.
name=${test#src/}
name=e2e_${name%.test.ts}
name=${name//\//_}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default [
},
},
{
files: ['src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts'],
files: ['src/automine/contracts/fixtures/storage_proof_fetcher.ts'],
rules: {
camelcase: 'off',
'no-console': 'off',
Expand Down
Loading
Loading