Testing
View SourceForja provides the Forja.Testing module with helpers for verifying event emission and processing in your test suite.
Setup
Import Forja.Testing in your test modules:
defmodule MyApp.OrderTest do
use MyApp.DataCase
import Forja.Testing
# ...
endAsserting events were emitted
assert_event_emitted/3
Verifies that an event of the given type was persisted in the database:
test "creates order and emits event" do
{:ok, order} = MyApp.Orders.create_order(%{total: 5000})
# Assert the event exists
event = assert_event_emitted(:my_app, "order:created")
assert event.source == "orders"
# Assert with payload matching
assert_event_emitted(:my_app, "order:created", %{"total" => 5000})
endPayload matching checks that the event payload contains the specified keys with matching values. It does not require an exact match -- extra keys in the payload are allowed.
refute_event_emitted/2
Verifies that no event of the given type exists:
test "invalid order does not emit event" do
{:error, _} = MyApp.Orders.create_order(%{total: -1})
refute_event_emitted(:my_app, "order:created")
endProcessing events synchronously
process_all_pending/1
Processes all unprocessed events synchronously using the :inline path. This is useful when you need handlers to execute before making assertions:
test "handler sends notification" do
Forja.emit(:my_app, "order:created", payload: %{"order_id" => "123"})
# Process all pending events (handlers execute here)
process_all_pending(:my_app)
# Now assert on side effects
assert_received {:notification_sent, "123"}
endIdempotency testing
assert_event_deduplicated/2
Verifies that exactly one event exists with the given idempotency key:
test "duplicate emission is prevented" do
Forja.emit(:my_app, "order:created",
payload: %{"order_id" => "123"},
idempotency_key: "order-123"
)
# Second emission with same key
Forja.emit(:my_app, "order:created",
payload: %{"order_id" => "123"},
idempotency_key: "order-123"
)
# Only one event exists
assert_event_deduplicated(:my_app, "order-123")
endTesting handlers in isolation
invoke_handler/4
Calls a handler directly with a fabricated event, without persisting anything:
test "OrderNotifier sends email for order:created" do
result = invoke_handler(
MyApp.Events.OrderNotifier,
"order:created",
%{"order_id" => "123", "email" => "user@example.com"}
)
assert result == :ok
assert_received {:email_sent, "user@example.com"}
endThis is useful for unit testing handler logic without the full Forja infrastructure.