PaperTiger.Test (PaperTiger v1.0.2)

Copy Markdown View Source

Test helpers for running PaperTiger tests concurrently.

Provides a sandbox mechanism similar to Ecto.Adapters.SQL.Sandbox that isolates test data by namespace, allowing tests to run with async: true.

Usage

defmodule MyApp.StripeTest do
  use ExUnit.Case, async: true

  setup :checkout_paper_tiger

  test "creates a customer" do
    # Data is isolated to this test process
    {:ok, customer} = PaperTiger.TestClient.create_customer(%{...})
  end
end

How It Works

When checkout_paper_tiger/1 is called:

  1. Stores the test process PID as a namespace in the process dictionary
  2. All subsequent PaperTiger operations scope data to that namespace
  3. On test exit, only that namespace's data is cleaned up

This allows multiple tests to run concurrently without interfering with each other's data.

Summary

Functions

Asserts that a webhook was delivered with the given event type.

Returns HTTP headers for authenticated sandbox requests.

Returns the base URL for PaperTiger HTTP requests.

Checks out a PaperTiger sandbox for the current test.

Cleans up all data for the given namespace.

Clears all collected webhook deliveries for the current namespace.

Returns the current namespace, or :global if not in a sandboxed test.

Enables webhook collection mode for the current test.

Gets all webhook deliveries collected during the test.

Gets webhook deliveries filtered by event type.

Asserts that no webhook was delivered with the given event type.

Returns HTTP headers needed for sandbox isolation.

Functions

assert_webhook_delivered(type_pattern)

@spec assert_webhook_delivered(String.t()) :: [map()]

Asserts that a webhook was delivered with the given event type.

This is a convenience helper that combines getting deliveries and asserting. Returns the matching deliveries for further assertions.

Example

test "customer creation triggers webhook" do
  {:ok, customer} = Stripe.Customer.create(%{email: "test@example.com"})

  [delivery] = PaperTiger.Test.assert_webhook_delivered("customer.created")
  assert delivery.event_data.object.email == "test@example.com"
end

auth_headers(opts \\ [])

@spec auth_headers(keyword()) :: [{String.t(), String.t()}]

Returns HTTP headers for authenticated sandbox requests.

Combines authorization header with sandbox namespace headers. Use this helper for most HTTP requests to PaperTiger.

Options

  • :api_key - Override the default API key (default: "sk_test_mock")

Example

Req.post(base_url("/v1/customers"),
  form: [email: "test@example.com"],
  headers: auth_headers()
)

# With custom API key
Req.get(url, headers: auth_headers(api_key: "sk_test_custom"))

base_url(path \\ "")

@spec base_url(String.t()) :: String.t()

Returns the base URL for PaperTiger HTTP requests.

Uses the configured port from application config.

Example

iex> PaperTiger.Test.base_url()
"http://localhost:4001"

iex> PaperTiger.Test.base_url("/v1/customers")
"http://localhost:4001/v1/customers"

checkout_paper_tiger(context \\ %{})

@spec checkout_paper_tiger(map()) :: :ok

Checks out a PaperTiger sandbox for the current test.

Use as a setup callback:

setup :checkout_paper_tiger

Or call directly in setup block:

setup do
  PaperTiger.Test.checkout_paper_tiger(%{})
  :ok
end

Child Process Support

This function also sets a shared namespace via Application env, which allows child processes (like Phoenix LiveView) to use the same sandbox. This is essential for integration tests where Stripe calls happen in spawned processes.

Returns :ok for use with ExUnit's setup callbacks.

cleanup_namespace(namespace)

@spec cleanup_namespace(pid() | :global) :: :ok

Cleans up all data for the given namespace.

Called automatically on test exit when using checkout_paper_tiger/1.

clear_delivered_webhooks()

@spec clear_delivered_webhooks() :: :ok

Clears all collected webhook deliveries for the current namespace.

Useful when testing multiple operations and wanting to verify webhooks from a specific action.

Example

test "verifies webhooks for second operation only" do
  {:ok, _} = Stripe.Customer.create(%{email: "first@example.com"})
  PaperTiger.Test.clear_delivered_webhooks()

  {:ok, _} = Stripe.Customer.create(%{email: "second@example.com"})

  # Only sees the second customer's webhook
  assert [%{event_type: "customer.created"}] = PaperTiger.Test.get_delivered_webhooks()
end

current_namespace()

@spec current_namespace() :: pid() | :global

Returns the current namespace, or :global if not in a sandboxed test.

enable_webhook_collection()

@spec enable_webhook_collection() :: :ok

Enables webhook collection mode for the current test.

Call this in your test setup to capture webhooks instead of delivering them. Automatically restores the previous mode on test exit.

Example

setup do
  :ok = checkout_paper_tiger(%{})
  :ok = enable_webhook_collection()
  :ok
end

test "creates customer and triggers webhook" do
  {:ok, _customer} = Stripe.Customer.create(%{email: "test@example.com"})
  [delivery] = PaperTiger.Test.assert_webhook_delivered("customer.created")
  assert delivery.event_data.object.email == "test@example.com"
end

get_delivered_webhooks()

@spec get_delivered_webhooks() :: [map()]

Gets all webhook deliveries collected during the test.

Only works when webhook_mode: :collect is configured.

Returns a list of delivery records sorted by creation time (oldest first).

Example

setup do
  Application.put_env(:paper_tiger, :webhook_mode, :collect)
  on_exit(fn -> Application.delete_env(:paper_tiger, :webhook_mode) end)
  :ok
end

test "creates customer and triggers webhook" do
  {:ok, _customer} = Stripe.Customer.create(%{email: "test@example.com"})

  deliveries = PaperTiger.Test.get_delivered_webhooks()
  assert [%{event_type: "customer.created"}] = deliveries
end

get_delivered_webhooks(type_pattern)

@spec get_delivered_webhooks(String.t()) :: [map()]

Gets webhook deliveries filtered by event type.

Supports wildcard patterns like "customer." or "invoice.payment_".

Examples

# Get all customer.created events
get_delivered_webhooks("customer.created")

# Get all customer events
get_delivered_webhooks("customer.*")

# Get all invoice payment events
get_delivered_webhooks("invoice.payment_*")

refute_webhook_delivered(type_pattern)

@spec refute_webhook_delivered(String.t()) :: :ok

Asserts that no webhook was delivered with the given event type.

Example

test "soft delete doesn't trigger delete webhook" do
  {:ok, customer} = Stripe.Customer.create(%{email: "test@example.com"})
  PaperTiger.Test.clear_delivered_webhooks()

  soft_delete_customer(customer)

  PaperTiger.Test.refute_webhook_delivered("customer.deleted")
end

sandbox_headers()

@spec sandbox_headers() :: [{String.t(), String.t()}]

Returns HTTP headers needed for sandbox isolation.

Include these headers in HTTP requests to PaperTiger to ensure data is scoped to the current test's namespace.

Example

Req.post(url, headers: PaperTiger.Test.sandbox_headers())

# Or merge with other headers:
Req.get(url,
  headers: [{"authorization", "Bearer sk_test_mock"}] ++ PaperTiger.Test.sandbox_headers()
)