Skip to content

Assertions

Assertions verify that your machine behaves correctly. They're marked with the = prefix and appear in expect: blocks.

Basic Syntax

flow
expect:
  = order is in #paid
  = $total equals 1200
  = @customer received :confirmation

State Assertions

Current State

flow
expect:
  = order is in #paid
  = order is in #awaiting_payment
  = application is in #pending

Not in State

flow
expect:
  = order is not in #cancelled
  = order is not in #failed

State History

flow
expect:
  = order has entered #processing
  = order has been in #pending
  = order has never been in #cancelled

Context Assertions

Equality

flow
expect:
  = $total equals 1200
  = $status equals "active"
  = $is_premium equals true

Comparisons

flow
expect:
  = $total is greater than 100
  = $total is less than 2000
  = $total is at least 100
  = $total is at most 500
  = $discount is between 10 and 50

Not Equal

flow
expect:
  = $status is not "cancelled"
  = $retry_count is not 0

Empty/Not Empty

flow
expect:
  = $customer_name is not empty
  = $errors is empty
  = $items is not empty

Collection Assertions

Contains

flow
expect:
  = $items contains "Laptop"
  = $tags contains "urgent"
  = $roles contains "admin"

Count

flow
expect:
  = $items has 3 items
  = $items_count equals 3
  = $errors has 0 items

Empty/Not Empty

flow
expect:
  = $items is not empty
  = $errors is empty
  = $cart has items

Event Assertions

Event Received

flow
expect:
  = @customer received :order_confirmed
  = @payment received :refund_request
  = @warehouse received :ship_order

Event Emitted

flow
expect:
  = :payment_request was emitted to @payment
  = :notification was sent to @customer

Event Not Received

flow
expect:
  = @customer did not receive :error
  = :refund was not emitted

Event with Data

flow
expect:
  = @payment received :payment_request with $total
  = :order_confirmed was emitted with order_id: $order_id

Boolean Assertions

flow
expect:
  = $is_active is true
  = $is_cancelled is false
  = $has_discount is true

Timestamp Assertions

flow
expect:
  = $created_at is not empty
  = $updated_at is after $created_at
  = $completed_at is today

Negation

Use not or is not for negative assertions:

flow
expect:
  = order is not in #cancelled
  = $total is not 0
  = $items does not contain "Expired Item"
  = @customer did not receive :error

Multiple Assertions

All assertions in an expect: block must pass:

flow
expect:
  = order is in #paid              // AND
  = $total equals 1200             // AND
  = @customer received :confirmation  // AND
  = $items has 3 items             // All must pass

Event-Level vs Scenario-Level

Event-Level (after specific event)

flow
on :checkout from @customer (api)
  order moves to #awaiting_payment

  expect:
    = order is in #awaiting_payment    // Checked after :checkout

Scenario-Level (after all events)

flow
scenario: complete purchase

  on :checkout from @customer (api)
    ...

  on :payment_success from @payment
    ...

  expect:
    = order is in #paid               // Checked after all events

Assertion Patterns

Verify State Transition

flow
scenario: order payment

  given:
    order is in #pending

  on :payment_received from @payment (api)
    order moves to #paid

  expect:
    = order is not in #pending
    = order is in #paid

Verify Context Update

flow
scenario: apply discount

  given:
    $total: number is 100
    $discount: number is 0

  on :apply_coupon from @customer (api)
    $discount becomes 10
    $total decreases by $discount

  expect:
    = $discount equals 10
    = $total equals 90

Verify Event Communication

flow
scenario: order triggers payment

  on :checkout from @customer (api)
    emit :payment_request to @payment

  expect:
    = :payment_request was emitted to @payment
    = @payment received :payment_request

Verify Error Handling

flow
scenario: handle invalid cart

  given:
    cart is empty

  on :checkout from @customer (api)
    ? cart is empty
      emit :checkout_error to @customer

  expect:
    = order is not in #processing
    = @customer received :checkout_error

Response Assertions

Verify API responses returned by reply statements.

Status Code

flow
expect:
  = reply status is 201
  = reply status is 400

Field Values

flow
expect:
  = reply.id is not empty
  = reply.status equals "awaiting_payment"
  = reply.total equals 1200

Nested Fields

flow
expect:
  = reply.customer.name equals "John"
  = reply.customer.email is not empty
  = reply.shipping.method equals "express"

Field Presence

flow
expect:
  = reply contains id
  = reply contains customer
  = reply does not contain tracking
  = reply does not contain internal_id

Async Callback Assertions

Verify async callback delivery:

flow
expect:
  = callback for :generate_report was sent
  = callback for :process_order was not sent

Complete Response Testing Example

flow
scenario: checkout flow

  on :checkout from @customer (api)
    $order_id becomes uuid()
    order moves to #awaiting_payment

    reply 201 with:
      | id     | $order_id     |
      | status | current_state |
      | total  | $total        |

    expect:
      = order is in #awaiting_payment
      = reply status is 201
      = reply.id equals $order_id
      = reply.status equals "awaiting_payment"
      = reply contains total
      = reply does not contain tracking

See Machine Responses for full response syntax.

Custom Assertions

For complex assertions, use natural language that maps to bindings:

flow
expect:
  = payment was processed successfully
  = inventory was updated correctly
  = email was sent to customer

These map to custom assertion classes in your binding code.

Assertion Debugging

When assertions fail, you get detailed output:

✗ order is in #paid
  Expected: #paid
  Actual:   #awaiting_payment

  Event trace:
    1. :checkout → #awaiting_payment
    2. :payment_failed → #awaiting_payment (no transition)

Best Practices

Be Specific

flow
// Good - specific
expect:
  = $total equals 1200
  = order is in #paid

// Avoid - vague
expect:
  = order is valid
  = everything worked

Test What Matters

flow
// Good - testing the outcome
expect:
  = order is in #paid
  = @customer received :confirmation

// Avoid - testing implementation details
expect:
  = internal_counter equals 5
  = temp_flag is true

Cover Edge Cases

flow
scenario: empty cart checkout

  given:
    cart is empty

  on :checkout from @customer (api)
    ...

  expect:
    = order is not in #paid
    = @customer received :empty_cart_error
flow
expect:
  // State assertions
  = order is in #completed

  // Context assertions
  = $total equals 1200
  = $items_count equals 3

  // Event assertions
  = @customer received :confirmation
  = @warehouse received :ship_order

Validation Assertions

Assertions for testing data validation and context constraints.

Validation Event Assertions

Verify that validation succeeded or failed:

flow
expect:
  = :validation_failed was emitted
  = :validation_failed was not emitted

Validation Error Assertions

Check specific validation errors:

flow
expect:
  = $errors contains "email"
  = $errors contains "email.required"
  = $errors contains "amount.greater than 0"
  = validation error count is 2

Constraint Violation Assertions

Verify context constraint behavior:

flow
expect:
  = :constraint_violated was emitted
  = :constraint_violated was not emitted
  = $field was rolled back
  = $retry_count is still 5

Complete Validation Test Example

flow
scenario: checkout validation

  on :checkout from @customer (api) with:
    | field | value          | validation                       |
    | email | "not-an-email" | required, string, valid email    |
    | total | -50            | required, number, greater than 0 |

  expect:
    = :validation_failed was emitted
    = order is not in #awaiting_payment
    = validation error count is 2
    = $errors contains "email"
    = $errors contains "total"

scenario: context constraint check

  given:
    $retry_count: number is 5

  on :retry_checkout from @customer (api)
    $retry_count increases by 1
      | $retry_count | required, integer, between 0 and 5 |

  expect:
    = :constraint_violated was emitted
    = $retry_count is still 5

Validation Assertion Patterns

AssertionPurpose
= :validation_failed was emittedEvent validation failed
= :validation_failed was not emittedEvent validation succeeded
= :constraint_violated was emittedContext constraint failed
= $errors contains "field"Specific field failed validation
= validation error count is NExact number of errors
= $field was rolled backContext action was reversed
= $field is still VALUEValue unchanged after rollback

See Data Validation for complete validation documentation.

Released under the MIT License.