Roadmap
Where Soroban Testkit is going, and which parts are open for contributors. Anything listed here is a proposal until an issue exists for it — the tracker is the source of truth.
Shipped in v0.1.0
Test context + builder
One call to get a mocked Env, an admin address and pre-generated users.
Event and auth matchers
Chainable assert_emitted, assert_count, assert_no_auth_required, with contract and topic filtering.
Budget snapshots
Read the CPU and memory one call metered, and diff two readings of a running budget.
proptest strategies
Token amounts, ledger sequences and timestamps bounded to realistic ranges.
Test suite for the toolkit
Unit tests in all four crates, plus cargo fmt, clippy -D warnings, docs build and a cargo deny supply-chain gate in CI.
Worked integration example
A real Soroban contract tested with fixtures, event matchers, budget assertions and authorization failures.
Landed since v0.1.0
Storage snapshots and diffs
StorageSnapshot::capture enumerates a contract's live instance, persistent and temporary entries from the ledger snapshot, and diff() reports added, removed and rewritten keys — #4, closed.
Negative event assertions
assert_not_emitted() and assert_none_match() prove a topic stayed silent, quoting the unexpected event when they fail — #11, closed.
Event payload assertions
assert_data_matches() reads what an event carried — a typed deserialize, one field of the map a #[contractevent] struct publishes, or the raw ScVal — and a failure prints every payload it rejected — #18, closed.
Events aggregated across calls
EventLog gathers each invocation's events as a test runs, and matcher() hands the sequence to the same filters and assertions — so assert_count, with_topic and assert_not_emitted speak about several calls at once, and topics() reads the order back — #19, closed.
Error code decoder
DecodedError::from_error names the host category and meaning behind a packed error code, and ErrorRegistry adds words for your own #[contracterror] codes — #5, closed.
Ledger time helpers
advance_time(), set_timestamp() and advance_ledger() move the clock or the height on their own, so a vesting or TTL test reads as a span instead of as a hand-built LedgerInfo — #12, closed.
Context reset
reset() swaps in a fresh env — ledger, events, auths and storage gone — and carries every address across, so a two-phase test keeps its actors instead of rebuilding its fixture — #17, closed.
Budget regression detection
BudgetGuard and budget_guard! hold a call to a CPU and memory ceiling plus a growth allowance against a recorded cost, and BudgetBaseline keeps those costs in a committed JSON file — every breach printed as one parseable line — #3, closed.
Budgets diffed in CI
examples/counter/budget.json commits the counter's hot-path costs, one ignored test records them and another enforces them, and the Budget baseline workflow runs the check on a pinned runner and reports every case on the pull request — #14, closed.
Published on crates.io
All four crates are live on the registry as soroban-testkit-core, -assert, -fixtures and -generators, with 0.3.0 as the current stable release, so a consumer adds a version requirement instead of a Git pin. The release tag stays available for anyone who wants to pin the source commit its CI went green on.
Next cycle
| Area | Work | Complexity |
|---|---|---|
| Assertions | assert_event_emitted! macro with topic and data matching (#1) | complexity:high |
| Assertions | assert_auth_matches! macro (#2) | complexity:medium |
| Fixtures | Contract registration in the builder (#6) | complexity:medium |
| Generators | Address strategies (#7) and XDR-compatible values (#8) | complexity:medium / high |
| Generators | Arbitrary implementations for Soroban types (#16) | complexity:medium |
| Examples | Token example exercising every crate (#9) | complexity:medium |
Later
Non-goals
It will not replace the official SDK's testing primitives, will not become a network simulator or transaction builder, and will not fork soroban-env-host. Testkit stays a thin, composable layer on top of the SDK.
Shaping the roadmap
Roadmap items start life as issues. If you want a feature that is not here, open a discussion in the issue tracker; if it is accepted and labelled with a complexity tag, it enters the next Wave cycle.
Everything above is claimable once labelled. Pick something that matches the time you have.
Open the tracker