Skip to content

Test File Syntax (.test.flow)

Test files contain variations of the happy path defined in .flow files.

Test File Structure

flow
test: @machine_name

  for scenario: scenario name

    for :event:
      test name:
        // variations + assertions

    test name:
      // path divergence + assertions

Transition Tests

Target specific event handlers with for :event::

flow
test: @order

  for scenario: checkout

    for :checkout:
      empty cart rejected:
        with scenario:
          cart is empty
        = @customer received :error

      payment declined:
        assume:
          ? payment successful = false
        = order is in #payment_failed

Scenario Tests (Path Divergence)

Test full flow variations with after/receive/then:

flow
test: @order

  for scenario: checkout

    payment fails:
      after :checkout
      receive :payment_failed from @payment
      = order is in #payment_failed

    retry then succeed:
      after :checkout
      receive :payment_failed from @payment
      then :payment_success from @payment
      = order is in #paid

Variation Sources

flow
// Override scenario-level given
with scenario:
  cart is empty

// Override event data
with event:
  payment_method is "bank_transfer"

// Override event-level given
with given:
  shipping_address is invalid

// Override context variables
with context:
  $total is 5000

assume: System

Control guard and action behavior in tests:

flow
assume:
  // Force guard result
  ? cart is valid = false

  // Action returns value
  process payment returns { transaction_id: "TXN-123" }

  // Action throws error
  send email throws "SMTP error"

observe: System

Watch actions without changing behavior:

flow
observe:
  send confirmation email
  update inventory

= send confirmation email was called
= send confirmation email was called with:
    to: @customer.email
= update inventory was not called

System Test Syntax

For machine systems, target specific machines:

flow
test: system checkout

  for scenario: complete purchase

    for :checkout to @order:
      guest rejected:
        with scenario:
          @customer is not logged in
        = @customer received :login_required

    for :payment_request to @payment:
      gateway down:
        assume:
          @payment.process throws "Unavailable"
        = @order is in #payment_failed

Complete Example

flow
test: @order

  for scenario: checkout

    // Transition tests
    for :checkout:
      empty cart:
        with scenario:
          cart is empty
        = @customer received :empty_cart_error

      guest user:
        with scenario:
          @customer is not logged in
        = @customer received :login_required

    // Path divergence tests
    payment fails:
      after :checkout
      receive :payment_failed from @payment
      = order is in #payment_failed
      = @customer received :payment_failed_notice

    retry succeeds:
      after :checkout
      receive :payment_failed from @payment
      then :retry_payment from @customer
      then :payment_success from @payment
      = order is in #paid

Released under the MIT License.