Home / Guides / Testing

Testing

Emissions includes test helpers for capturing emitted events and making assertions in your test suite.

Setup

1. Configure the Test Adapter

# config/test.exs
config :emissions,
  adapters: [{Emissions.Testing.TestAdapter, []}],
  handlers: []

2. Initialize the Event Store

# test/test_helper.exs
Emissions.Testing.setup()
ExUnit.start()

3. Reset Between Tests

setup do
  Emissions.Testing.reset()
  :ok
end

Assertions

Import Emissions.Testing to use the assertion macros:

defmodule MyApp.OrdersTest do
  use ExUnit.Case
  import Emissions.Testing

  setup do
    Emissions.Testing.reset()
    :ok
  end

  test "creating an order emits order_created" do
    MyApp.Orders.create(%{item: "widget", qty: 5})

    assert_emitted(:order_created)
  end

  test "can assert on event payload" do
    MyApp.Orders.create(%{item: "widget", qty: 5})

    assert_emitted(:order_created, fn event ->
      assert event.payload.item == "widget"
      assert event.payload.qty == 5
    end)
  end

  test "failed operations don't emit events" do
    MyApp.Orders.create(%{invalid: true})

    refute_emitted(:order_created)
  end
end

assert_emitted/1

Asserts that at least one event with the given name was emitted:

assert_emitted(:order_created)

assert_emitted/2

Asserts the event was emitted and runs a function on each matching event for further assertions:

assert_emitted(:order_created, fn event ->
  assert event.payload.total > 0
  assert event.metadata.source == "api"
end)

refute_emitted/1

Asserts that no event with the given name was emitted:

refute_emitted(:order_canceled)

Querying Events

For more complex assertions, query the event store directly:

# Get all captured events
events = Emissions.Testing.get_events()

# Get events by name
order_events = Emissions.Testing.events_named(:order_created)

# Check if an event was emitted
Emissions.Testing.emitted?(:order_created)

Async Considerations

Because events flow through a GenStage pipeline, there is a small delay between commit/0 and events arriving at the test adapter. If your tests assert immediately after the code under test runs, you may need a brief wait:

test "events arrive after pipeline processes them" do
  MyApp.Orders.create(%{item: "widget"})

  # Allow the GenStage pipeline to deliver
  Process.sleep(50)

  assert_emitted(:order_created)
end

If your code under test already calls Emissions.commit() and the test calls the code synchronously, this is typically sufficient. The 50ms sleep is a conservative safety margin.

Testing Handlers

To test handlers in isolation, call them directly without the pipeline:

test "handler processes order_created" do
  result = MyApp.SearchIndexHandler.handle_event(
    :order_created,
    %{id: 1, name: "Widget"},
    %{}
  )

  assert result == :ok
end

To test handlers with cascading events, start a buffer first:

test "handler emits cascading events" do
  Emissions.start()
  result = MyApp.FulfillmentHandler.handle_event(:order_created, order, %{})
  assert result == :ok
  Emissions.commit()

  Process.sleep(50)
  assert_emitted(:order_fulfillable)
end