CampaignFlow.MockServer.Test (CampaignFlow Client v2.2.0)

View Source

Test-only helpers for driving the mock CampaignFlow server from Elixir code.

These functions simulate events that would normally happen asynchronously inside the real CampaignFlow service. They are intended for end-to-end integration tests in host applications.

Example

# Create a referral via the normal POST /api/v2/referrals API,
# capture the campaign id from the response, then drive its lifecycle:
CampaignFlow.MockServer.Test.set_campaign_status(campaign_id, "live")

# Inspect the webhook events that were enqueued/delivered:
CampaignFlow.MockServer.Test.list_webhook_events()

Sync vs async delivery

When :webhook_delivery_mode in :mock_server config is :sync, set_campaign_status/2 blocks until webhook delivery completes (success or failure). This is the recommended mode for E2E tests.

When set to :async (the default), delivery happens via Task.Supervisor and set_campaign_status/2 returns immediately. Use deliver_pending_webhooks/0 to drain the queue synchronously when you need to assert.

Summary

Functions

Clears just the webhook events table (leaves campaigns/referrals in place).

Creates a new finance application linked to the given campaign.

Synchronously drains pending webhook deliveries (events whose next_retry_at is in the past or nil and attempts < max_attempts).

Returns all webhook events stored in the mock server, newest first.

Sets the status of a mock campaign and enqueues a campaign_status_change webhook for delivery.

Sets the status of a mock finance application and enqueues a finance_application_status_change webhook for delivery.

Functions

clear_webhook_events()

@spec clear_webhook_events() :: :ok

Clears just the webhook events table (leaves campaigns/referrals in place).

create_finance_application(campaign_id)

@spec create_finance_application(integer()) ::
  {:ok, struct()} | :not_found | {:error, term()}

Creates a new finance application linked to the given campaign.

The application starts in draft status. No webhook is fired by this function — only status changes trigger webhooks. Use set_finance_application_status/2 to drive subsequent transitions.

Returns {:ok, %FinanceApplication{}} on success, :not_found if the campaign id is unknown.

deliver_pending_webhooks()

@spec deliver_pending_webhooks() :: :ok

Synchronously drains pending webhook deliveries (events whose next_retry_at is in the past or nil and attempts < max_attempts).

Useful in :async mode tests that need to flush the queue before asserting on delivery state.

list_webhook_events()

@spec list_webhook_events() :: [
  %CampaignFlow.MockServer.Schema.WebhookEvent{
    __meta__: term(),
    attempts: term(),
    delivered_at: term(),
    event_type: term(),
    id: term(),
    inserted_at: term(),
    last_attempt_at: term(),
    last_error: term(),
    max_attempts: term(),
    next_retry_at: term(),
    payload: term(),
    response_body: term(),
    response_status: term(),
    status: term(),
    target_url: term(),
    updated_at: term()
  }
]

Returns all webhook events stored in the mock server, newest first.

set_campaign_status(campaign_id, new_status)

@spec set_campaign_status(integer(), String.t()) ::
  {:ok, map()} | :not_found | {:error, term()}

Sets the status of a mock campaign and enqueues a campaign_status_change webhook for delivery.

This is the Elixir-native equivalent of POST /api/v2/campaigns/:id/set-status. Both route through State.update_campaign_status_and_notify/2.

Returns:

  • {:ok, campaign} on success (API-shaped map, matching GET /campaigns/:id)
  • :not_found if the campaign id is unknown
  • {:error, {:invalid_status, status}} if the status is not in the OpenAPI enum
  • {:error, changeset} if the underlying update fails

set_finance_application_status(application_id, new_status)

@spec set_finance_application_status(integer(), String.t()) ::
  {:ok, struct()} | :not_found | {:error, term()}

Sets the status of a mock finance application and enqueues a finance_application_status_change webhook for delivery.

Returns:

  • {:ok, application} on success (the updated %FinanceApplication{} struct)
  • :not_found if the application id is unknown
  • {:error, {:invalid_status, status}} if the status is not in the OpenAPI enum
  • {:error, changeset} if the underlying update fails