Test helpers for apps using LatticeStripe.
This module ships with the LatticeStripe hex package so downstream users can construct realistic Stripe webhook events in their test suites without needing to know Stripe's HMAC signing scheme.
Usage
# High-level: get a typed %Event{} struct for testing event handlers
import LatticeStripe.Testing
test "handles payment_intent.succeeded webhook" do
event = generate_webhook_event("payment_intent.succeeded", %{
"id" => "pi_test_123",
"amount" => 2000,
"currency" => "usd",
"status" => "succeeded"
})
assert {:ok, :processed} = MyApp.Webhooks.handle(event)
end
# Low-level: get a signed raw payload + header for Plug-level testing
test "verifies webhook signature via Plug" do
{payload, sig_header} = generate_webhook_payload(
"customer.created",
%{"id" => "cus_test_456", "email" => "new@example.com"},
secret: "whsec_test_secret"
)
conn =
Plug.Test.conn(:post, "/webhooks", payload)
|> Plug.Conn.put_req_header("stripe-signature", sig_header)
|> MyApp.Router.call([])
assert conn.status == 200
endImportant Note
This module is intended for use in test environments only. It ships in lib/
(not test/support/) so downstream users can import it without configuring
custom elixirc_paths — but it has no side effects and is safe to include in
production releases.
Summary
Functions
Converts a canonical CreditNote fixture map into %LatticeStripe.CreditNote{}.
Converts a canonical Dispute fixture map into %LatticeStripe.Dispute{}.
Converts a canonical thin-event notification fixture map into
%LatticeStripe.EventNotification{}.
Converts a canonical File fixture map into %LatticeStripe.File{}.
Converts a canonical FileLink fixture map into %LatticeStripe.FileLink{}.
Generates a signed thin-event webhook payload pair for Plug-level testing.
Builds a %LatticeStripe.Event{} struct for the given event type and object data.
Generates a signed webhook payload pair for Plug-level testing.
Converts a canonical Mandate fixture map into %LatticeStripe.Mandate{}.
Converts a canonical Quote fixture map into %LatticeStripe.Quote{}.
Converts a canonical SetupAttempt fixture map into %LatticeStripe.SetupAttempt{}.
Converts a canonical Tax Calculation fixture map into %LatticeStripe.Tax.Calculation{}.
Converts a canonical TaxId fixture map into %LatticeStripe.TaxId{}.
Converts a canonical Tax Transaction fixture map into %LatticeStripe.Tax.Transaction{}.
Functions
@spec credit_note(map()) :: LatticeStripe.CreditNote.t()
Converts a canonical CreditNote fixture map into %LatticeStripe.CreditNote{}.
@spec dispute(map()) :: LatticeStripe.Dispute.t()
Converts a canonical Dispute fixture map into %LatticeStripe.Dispute{}.
@spec event_notification(map()) :: LatticeStripe.EventNotification.t()
Converts a canonical thin-event notification fixture map into
%LatticeStripe.EventNotification{}.
Direct typed-builder parallel to dispute/1, customer/1, etc. — use this when
your test needs a typed %EventNotification{} value without going through
signature verification.
Example
import LatticeStripe.Test.Fixtures.EventNotification
notif = LatticeStripe.Testing.event_notification(event_notification_map())
assert notif.type == "v2.core.account.updated"When you need a signed wire-format payload (for example to exercise a Phoenix
controller calling Webhook.parse_event_notification/4), use
generate_thin_event_payload/3 instead.
@spec file(map()) :: LatticeStripe.File.t()
Converts a canonical File fixture map into %LatticeStripe.File{}.
@spec file_link(map()) :: LatticeStripe.FileLink.t()
Converts a canonical FileLink fixture map into %LatticeStripe.FileLink{}.
Generates a signed thin-event webhook payload pair for Plug-level testing.
Thin-event counterpart to generate_webhook_payload/3 — produces a wire-format
/v2/events notification payload (object: "v2.core.event", ISO 8601 created,
no data or pending_webhooks keys) and a matching Stripe-Signature header.
Returns {payload_string, signature_header_value} that round-trips through
LatticeStripe.Webhook.parse_event_notification/4 without modification.
Use generate_webhook_payload/3 for snapshot v1 webhooks (construct_event/4)
and this helper for thin-event v2 webhooks (parse_event_notification/4).
Calling the wrong helper produces a structurally-valid payload that decodes to
a mostly-nil struct — keep snapshot and thin-event test paths obviously
distinct in your test suite.
Parameters
type- Stripe thin-event type string, e.g."v2.core.account.updated"related_object_data- Therelated_objectmap (%{"id" => ..., "type" => ..., "url" => ...}) ornilfor snapshot-style v2 events (default:nil)opts- Options::secret- Webhook signing secret (required; raisesKeyErrorif absent):timestamp- Unix-seconds timestamp integer used both to sign the payload and to derive the ISO 8601createdfield (default: current system time):id- Event ID string (default:"evt_test_" <> random_hex(16)):context- Free-formcontextstring (default:nil):livemode- boolean (default:false)
Returns
{raw_payload_string, stripe_signature_header_value} — the same shape as
generate_webhook_payload/3.
Example
{payload, sig_header} =
LatticeStripe.Testing.generate_thin_event_payload(
"v2.core.account.updated",
%{
"id" => "acct_test_123",
"type" => "v2.core.account",
"url" => "/v2/core/accounts/acct_test_123"
},
secret: "whsec_test"
)
{:ok, notif} =
LatticeStripe.Webhook.parse_event_notification(payload, sig_header, "whsec_test")
assert notif.type == "v2.core.account.updated"
assert notif.related_object.id == "acct_test_123"Pass nil for related_object_data to produce a snapshot-style v2 event (the
notification will have related_object: nil; adopters dispatch these to
Webhook.fetch_event/3 rather than fetch_related_object/3).
@spec generate_webhook_event(String.t(), map(), keyword()) :: LatticeStripe.Event.t()
Builds a %LatticeStripe.Event{} struct for the given event type and object data.
Constructs a realistic Stripe event shape without making any HTTP calls.
The data.object map is whatever you pass as object_data.
Parameters
type- Stripe event type string, e.g."payment_intent.succeeded"object_data- Thedata.objectmap for the event (default:%{})opts- Options::id- Event ID string (default:"evt_test_" <> random_hex(16)):api_version- API version string (default:"2026-03-25.dahlia"):livemode- boolean (default:false)
Returns
A %LatticeStripe.Event{} struct.
Canonical raw maps from LatticeStripe.Testing.Fixtures.* compose directly
with this helper.
Example
file = LatticeStripe.Testing.Fixtures.File.file_json()
event = LatticeStripe.Testing.generate_webhook_event(
"payment_intent.succeeded",
file
)
assert event.type == "payment_intent.succeeded"
assert event.data["object"]["id"] == file["id"]
Generates a signed webhook payload pair for Plug-level testing.
Returns {payload_string, signature_header_value} where the signature
is computed using Webhook.generate_test_signature/3. The returned pair
passes Webhook.construct_event/4 without modification.
The raw event map is JSON-encoded directly (before Event.from_map/1) to
avoid round-trip encoding issues with the %Event{} struct.
Parameters
type- Stripe event type string, e.g."customer.created"object_data- Thedata.objectmap for the event (default:%{})opts- Options::secret- Webhook signing secret (required):timestamp- Unix timestamp integer to embed in signature (default: current time)- Other opts (
:id,:api_version,:livemode) are forwarded togenerate_webhook_event/3
Returns
{raw_payload_string, stripe_signature_header_value}
Canonical raw maps from LatticeStripe.Testing.Fixtures.* compose directly
with this helper.
Example
dispute = LatticeStripe.Testing.Fixtures.Dispute.dispute_json()
{payload, sig_header} = LatticeStripe.Testing.generate_webhook_payload(
"payment_intent.succeeded",
dispute,
secret: "whsec_test"
)
{:ok, event} = LatticeStripe.Webhook.construct_event(payload, sig_header, "whsec_test")
assert event.type == "payment_intent.succeeded"
@spec mandate(map()) :: LatticeStripe.Mandate.t()
Converts a canonical Mandate fixture map into %LatticeStripe.Mandate{}.
@spec quote(map()) :: LatticeStripe.Quote.t()
Converts a canonical Quote fixture map into %LatticeStripe.Quote{}.
@spec setup_attempt(map()) :: LatticeStripe.SetupAttempt.t()
Converts a canonical SetupAttempt fixture map into %LatticeStripe.SetupAttempt{}.
@spec tax_calculation(map()) :: LatticeStripe.Tax.Calculation.t()
Converts a canonical Tax Calculation fixture map into %LatticeStripe.Tax.Calculation{}.
@spec tax_id(map()) :: LatticeStripe.TaxId.t()
Converts a canonical TaxId fixture map into %LatticeStripe.TaxId{}.
@spec tax_transaction(map()) :: LatticeStripe.Tax.Transaction.t()
Converts a canonical Tax Transaction fixture map into %LatticeStripe.Tax.Transaction{}.