vm.expectRevert() to verify your assertion catches violations and returns the expected error message.
Understanding this difference is important for writing effective tests and interpreting their results.
Quick Comparison
| Aspect | Testing | Production |
|---|---|---|
| When assertion fails | Transaction reverts | Transaction dropped (never enters block) |
| Which assertion runs | Specified by fnSelector | All matching assertions |
| Scope | Next external call only | All transactions to protected contracts |
Production: Transactions Are Dropped
In production, the Assertion Enforcer validates transactions during block building: Key behaviors:- Triggers are evaluated to determine which assertions run
- All matching assertions for all interacted contracts execute
- Failed transactions are dropped - they never enter the blockchain
- Users don’t see reverts; the transaction simply doesn’t get included
Testing: Transactions Revert
In testing,cl.assertion() registers an assertion to run on the next external call:
Key behaviors:
- You specify the assertion function via
fnSelector, but triggers still determine if it runs - Only the specified assertion runs, not all assertions for the contract
- Only the next external call is validated, then the registration is consumed
- Reverts simulate drops - use
vm.expectRevert()to test failure cases
The cl.assertion() Mental Model
cl.assertion() works like vm.prank() - it only affects the immediately following external call.
State Persistence
When an assertion passes, state changes persist for the rest of the test. You can assert on updated values and register subsequent assertions.Common Pitfalls
”Expected 1 assertion to be executed, but 0 were executed”
This error means the assertion didn’t run. Common causes:- External call between
cl.assertion()and target - the intervening call consumed the assertion registration - Called function doesn’t match a registered trigger - see below
- Target transaction reverts before assertion runs - the protocol function itself fails
Trigger Mismatch
ThefnSelector parameter specifies which assertion function to run, but triggers are still evaluated. The assertion only runs if the next external call matches a registered trigger for that assertion function.

