View Source Sentry.Test.Assertions (Sentry v13.1.0)

ExUnit assertion helpers for testing Sentry reports.

These helpers work with data collected by Sentry.Test and reduce boilerplate when asserting on captured events, transactions, and logs.

Usage

import Sentry.Test.Assertions

Examples

Assert that exactly one event was captured with specific fields:

assert_sentry_report(:event, level: :error, message: %{formatted: "hello"})

Assert a transaction:

assert_sentry_report(:transaction, transaction: "my_span")

Use the log shorthand:

assert_sentry_log(:info, "User session started")
assert_sentry_log(:info, ~r/session started/, trace_id: "abc123")

Use the metric shorthand (find semantics — works with multiple co-emitted metrics):

assert_sentry_metric(:counter, name: "button.clicks")
assert_sentry_metric(:distribution, name: "response.time")

Find a specific event among many:

events = Sentry.Test.pop_sentry_reports()
event = find_sentry_report!(events, message: %{formatted: ~r/hello/})

Awaiting Asynchronous Reports

Log and metric events flow through the Sentry.TelemetryProcessor pipeline asynchronously. The type-form of assert_sentry_report/2 and assert_sentry_log/3 await internally — they flush the telemetry pipeline and poll the collector with exponential backoff until at least one matching item is captured, up to a timeout (default 1000ms).

Tests typically do not need to call Sentry.TelemetryProcessor.flush/0 or Process.sleep/1 before these assertions.

Override the default via the reserved :timeout keyword:

assert_sentry_report(:log, [level: :info, body: "hi"], timeout: 2000)
assert_sentry_log(:info, "hi", timeout: 2000)
assert_sentry_metric(:counter, name: "clicks", timeout: 2000)

Summary

Functions

Asserts that a log was captured matching the given level and body pattern.

Asserts that a metric was captured matching the given type and criteria.

Asserts that a report matches the given criteria.

Asserts that exactly one transaction envelope is collected via ref and matches the given criteria.

Finds the first item in items that matches all criteria.

Collects up to :count transaction envelopes via ref and returns the first one matching criteria. Raises if no transaction matches.

Asserts that no Sentry check-in envelope reaches the Bypass envelope collector identified by ref within timeout ms (default 100).

Functions

Link to this function

assert_sentry_log(level, body_pattern, extra_criteria \\ [])

View Source (since 13.0.0)
@spec assert_sentry_log(Sentry.LogEvent.level(), String.t() | Regex.t(), keyword()) ::
  Sentry.LogEvent.t()

Asserts that a log was captured matching the given level and body pattern.

Awaits asynchronously-captured logs: the pipeline is flushed and the collector is polled until a log matching the criteria is found or the timeout elapses (default 1000ms, overridable via the :timeout reserved key in extra_criteria).

Once at least one candidate log is available, finds the first one matching level and body_pattern. This uses find semantics (not assert-exactly-1) because logs often come in batches.

The optional third argument is a keyword list of extra criteria to match on any Sentry.LogEvent field, plus the reserved :timeout option.

Returns the matched log event.

Examples

assert_sentry_log(:info, "User session started")
assert_sentry_log(:error, ~r/connection refused/)
assert_sentry_log(:info, "User session started", trace_id: "abc123")
assert_sentry_log(:info, "User session started", attributes: %{id: 312})
assert_sentry_log(:info, "slow path", timeout: 2000)
Link to this function

assert_sentry_metric(type, criteria \\ [])

View Source (since 13.0.0)
@spec assert_sentry_metric(
  :counter | :distribution | :gauge,
  keyword()
) :: Sentry.Metric.t()

Asserts that a metric was captured matching the given type and criteria.

Awaits asynchronously-captured metrics: the pipeline is flushed and the collector is polled until a metric matching the criteria is found or the timeout elapses (default 1000ms, overridable via the :timeout reserved key in criteria).

Uses find semantics (not assert-exactly-1), so this succeeds even when multiple metrics were emitted together — as is common when a single request records several measurements.

Unmatched metrics are returned to an inbox so that multiple successive assert_sentry_metric/2 calls in the same test each see a clean slate.

Returns the matched metric.

Examples

assert_sentry_metric(:counter, name: "button.clicks")
assert_sentry_metric(:distribution, name: "response.time", value: 42.5)
assert_sentry_metric(:gauge, name: "memory.usage", attributes: %{pool: "main"})
assert_sentry_metric(:counter, name: "requests", timeout: 2000)
Link to this function

assert_sentry_report(type_or_item, criteria)

View Source (since 13.0.0)
@spec assert_sentry_report(
  :event | :transaction | :log | :metric,
  keyword()
) ::
  Sentry.Event.t()
  | Sentry.Transaction.t()
  | Sentry.LogEvent.t()
  | Sentry.Metric.t()
@spec assert_sentry_report(map() | [map()], keyword() | [{binary(), term()}]) :: map()

Asserts that a report matches the given criteria.

This function has two forms:

Auto-pop by type

When the first argument is a type atom (:event, :transaction, or :log), it pops collected items internally — no need to call pop_sentry_reports/0 yourself. Asserts that exactly one item was captured and validates it.

Explicit data

When the first argument is a map or single-element list, it validates the item against the criteria directly. Use this with data from envelope collection helpers.

Criteria

Each key-value pair in criteria is checked against the item:

  • Regex — matches with =~/2
  • Plain map (not a struct) — recursive subset match: every key in the expected map must exist in the actual value with a matching value
  • Any other value — compared with ==/2

Atom keys are resolved with a string-key fallback, so atom-key criteria also work on decoded JSON maps.

Returns the matched item for further assertions.

Examples

event = assert_sentry_report(:event,
  level: :error,
  source: :plug,
  message: %{formatted: "hello"}
)

assert_sentry_report(:transaction, transaction: "test_span")

# With explicit data from envelope collection:
[event] = collect_sentry_events(ref, 1)
assert_sentry_report(event, "tags" => %{"oban_queue" => "default"})
Link to this function

assert_sentry_transaction(ref, criteria \\ [])

View Source (since 13.1.0)
@spec assert_sentry_transaction(
  reference(),
  keyword()
) :: map()

Asserts that exactly one transaction envelope is collected via ref and matches the given criteria.

This is shorthand for:

assert_sentry_report(collect_sentry_transactions(ref, 1), criteria)

Reserved option in criteria:

  • :timeout — ms to wait for the envelope (default: 1000)

Use with a collector created via Sentry.Test.setup_sentry(collect_envelopes: true).

Returns the matched transaction map.

Examples

test "GET /transaction", %{conn: conn, ref: ref} do
  get(conn, ~p"/transaction")

  assert_sentry_transaction(ref,
    transaction: "test_span",
    contexts: %{trace: %{op: "test_span"}}
  )
end
Link to this function

find_sentry_report!(items, criteria)

View Source (since 13.0.0)
@spec find_sentry_report!([map()], keyword() | [{binary(), term()}]) :: map()

Finds the first item in items that matches all criteria.

Raises with a descriptive error if no match is found. Works with both structs (atom keys) and decoded JSON maps (string keys).

Examples

events = Sentry.Test.pop_sentry_reports()
event = find_sentry_report!(events, message: %{formatted: ~r/hello/})
Link to this function

find_sentry_transaction!(ref, criteria)

View Source (since 13.1.0)
@spec find_sentry_transaction!(
  reference(),
  keyword()
) :: map()

Collects up to :count transaction envelopes via ref and returns the first one matching criteria. Raises if no transaction matches.

This is shorthand for:

find_sentry_report!(collect_sentry_transactions(ref, count, timeout: timeout), criteria)

Reserved options in criteria:

  • :count — max number of envelopes to collect (default: 1)
  • :timeout — ms to wait for each envelope (default: 1000)

Examples

find_sentry_transaction!(ref,
  count: 10,
  timeout: 2000,
  transaction: "PhoenixAppWeb.UserLive.Index.handle_event#save",
  contexts: %{trace: %{origin: "opentelemetry_phoenix"}}
)
Link to this function

refute_sentry_check_in(ref, timeout \\ 100)

View Source (since 13.1.0)
@spec refute_sentry_check_in(reference(), timeout()) :: :ok

Asserts that no Sentry check-in envelope reaches the Bypass envelope collector identified by ref within timeout ms (default 100).

The Sentry.TelemetryProcessor pipeline is flushed first, so a check-in that was buffered (rather than sent synchronously) is still detected rather than silently slipping past the timeout window.

Use with a collector created via Sentry.Test.setup_sentry(collect_envelopes: [type: "check_in"]) (or Sentry.Test.setup_bypass_envelope_collector/2 with type: "check_in"), so that only check-in envelopes are forwarded to the test process.

Examples

test "ignores non-cron jobs", %{ref: ref} do
  :telemetry.execute([:oban, :job, :start], %{}, %{job: %Oban.Job{}})
  refute_sentry_check_in(ref)
end