Docs
Testing

Built-in matchers and helpers

Reference map for transaction predicates, map expectations, and out-action helpers in Acton tests

Before writing custom matchers, check the built-in ones first. Acton already ships a useful set of helpers for transaction search, map assertions, and out-action inspection.

Available since: Acton 1.2

Use Acton Studio to review local test traces and inspect emulator test results.

Transaction search matchers

Use these functions to find or assert on transactions from net.send(...):

  • findTransaction()
  • toHaveSuccessfulDeploy()
  • toHaveSuccessfulTx()
  • toHaveTx()
  • toNotHaveTx()
  • toHaveBouncedTx()
  • toHaveFailedTx()

You can mix exact scalar matches and predicate functions inside SearchParams:

expect(res).toHaveTx({
    from: fun (addr: address): bool {
        return addr == deployer.address;
    },
    to: harness.address,
    value: grams("0.5"),
    opcode: 0x0000_0001,
});

Important matcher semantics:

  • SearchParams fields accept either exact values or predicate functions.
  • toHaveSuccessfulTx() forces success = true and defaults exitCode = 0 unless overridden explicitly.
  • toHaveFailedTx() requires a non-zero exitCode.
  • Bounced-message opcode matching should be done with toHaveBouncedTx() or an explicit bounced: true filter.
  • Predicate functions can be useful for custom diagnostics, but runtime errors inside those predicates surface back to the test output.
Available since: Acton 1.1

The sendMode field filters child transactions by the parent send action's mode. It accepts an exact value or a predicate, like the other SearchParams fields.

Go deeper in:

Numeric and list matchers

Available since: Acton 1.2

toBeInRange(min, max) includes both bounds. lisp_list<T> supports toContain, toNotContain, toBeEmpty, toBeNonEmpty, and toHaveLength.

toBeApproxEqRel(expected, maxDelta, maxDeltaDenominator) accepts a custom denominator. Its default is 100; use 1_000_000 for millionths. See the matcher reference.

Get-method execution metadata

Available since: Acton 1.2

net.runGetMethodExt<Ret>() returns the saved stack with meta.gasUsed and meta.exitCode, including VM failures. isSuccess() accepts exit codes 0 and 1; unwrap() checks success and decodes as Ret. expect(result).toHaveExitCode(code) checks the exit code without decoding.

External message matchers

Available since: Acton 1.1

net.sendExternal(...) returns an ExternalSendResult. When the external-in message is accepted, result.transactions contains the produced transaction trace. When the contract rejects the message before acceptance, the trace is null and result.error contains emulator metadata such as externalNotAccepted, message and vmExitCode.

val result = net.sendExternal(msg);

expect(result).toBeAccepted();

val txs = result.unwrap();
expect(txs).toHaveAllSuccessfulTxs();

val tx = result.at(0);
result.giveName("external vote");

Available helpers:

  • isAccepted() reports acceptance during local emulation. After a network broadcast, use waitForFirstTransaction() or waitForTrace() instead.
  • unwrap() returns the produced SendResultList or fails with the same external diagnostics as toBeAccepted().
  • at(index) unwraps the trace and returns one SendResult.
  • giveName(name) names the external trace for the Test UI and gas/fee reports.
  • waitForFirstTransaction() waits for the root on-chain transaction, or returns null when the external message was not accepted.
  • waitForTrace() waits for the full on-chain trace, or returns null when the external message was not accepted.
  • findExternalOutMessage<T>() searches external-out messages in the accepted trace, or returns null for rejected external-in messages.

Available matchers:

  • toBeAccepted() expects an accepted external-in message and a produced trace.
  • toBeNotAccepted() expects rejection before acceptance.
  • toHaveExternalVmExitCode(exitCode) checks the VM exit code reported for a rejected external-in message. For accepted messages, use transaction matchers on result.unwrap().

Failed toBeAccepted() checks include the external status, emulator reason, VM exit code when available, known exit-code description or ABI error name, source location, and full backtrace when the test is run with --backtrace full.

val result = net.sendExternal(invalidMsg);

expect(result).toBeNotAccepted();
expect(result).toHaveExternalVmExitCode(10);

Rejected external-in diagnostics include the matcher location and, with --backtrace full, the contract-side onExternalMessage backtrace.

Available since: Acton 1.2

acceptanceKnown indicates whether acceptance is known. After a real-network broadcast, isAccepted() reports an error because submission alone does not prove acceptance. Use waitForFirstTransaction() or waitForTrace() to inspect execution.

Go deeper in:

Map expectations

Map helpers are useful for get-method results and in-memory fixtures:

val balances: map<int32, int32> = net.runGetMethod(ledger.address, "balances");

expect(balances).toContainKey(1);
expect(balances).toContainValue(20);
expect(balances).toNotContainKey(99);
expect(balances).toNotContainValue(777);
expect(balances).toBeNonEmpty();
expect(balances).toHaveLength(2);

Available helpers:

  • toContainKey()
  • toNotContainKey()
  • toContainValue()
  • toNotContainValue()
  • toBeEmpty()
  • toBeNonEmpty()
  • toHaveLength()

Practical note:

  • toHaveLength() counts the current number of keys after overwrites, not the number of set() calls used to build the map.

Go deeper in:

Out-action helpers

Use action helpers to inspect C5 output, planned sends, or action kinds:

val outActions = testing.outActions();

expect(outActions).toBeSendMessageAt<IncreaseCounter>(2);

val action = outActions.getSendMessageAt(2);
val body = outActions.getSendMessageBodyAt<IncreaseCounter>(2);

The most useful entry points are:

  • testing.outActions() for the current VM out list
  • SendResult.allOutActions() for one executed transaction result
  • OutMessage.outActions(mode) for a message before it is sent
  • OutActionList.at()
  • OutActionList.getSendMessageAt()
  • OutActionList.getSendMessageBodyAt()
  • Expectation<OutActionList>.toBeSendMessageAt()

Important out-action semantics:

  • Out-action indexing is reversed: index 0 is the last produced action.
  • kind() returns stable string tags such as "send-message" and "reserve-currency".
  • getSendMessageAt() and getSendMessageBodyAt() return null when the selected action is not a send-message action.
  • toBeSendMessageAt<Msg>() verifies that the action is a send-message action and that typed message loading succeeds. For body-field assertions, load the message or body separately.

Go deeper in:

When to write custom matchers

If the built-in helpers still do not match a domain-specific vocabulary, extend Expectation<T> with a custom matcher.

Last updated on

On this page