# `PaperTiger.TestHelpers`
[🔗](https://github.com/EnaiaInc/paper_tiger/blob/v1.2.2/lib/paper_tiger/test_helpers.ex#L1)

ExUnit test helpers for PaperTiger.

Provides convenient functions for testing PaperTiger integrations:

## HTTP Request Helpers

Make HTTP requests with automatic Bearer token authentication:

    test "create customer" do
      response = PaperTiger.TestHelpers.post("/v1/customers", %{email: "test@example.com"})
      assert response["object"] == "customer"
    end

    response = PaperTiger.TestHelpers.get("/v1/customers")
    assert response["object"] == "list"

## Data Creation Helpers

Quickly create common Stripe objects:

    customer = PaperTiger.TestHelpers.create_customer(email: "user@example.com")
    product = PaperTiger.TestHelpers.create_product(name: "Premium")
    price = PaperTiger.TestHelpers.create_price(product["id"], unit_amount: 9999)
    subscription = PaperTiger.TestHelpers.create_subscription(customer["id"], price["id"])

## Assertion Helpers

Validate response structures:

    PaperTiger.TestHelpers.assert_stripe_object(response, "customer")
    PaperTiger.TestHelpers.assert_list_response(response)
    PaperTiger.TestHelpers.assert_error_response(response, "invalid_request_error")

## Time Helpers

Control time in tests:

    PaperTiger.TestHelpers.advance_time(days: 30)
    PaperTiger.TestHelpers.advance_time(seconds: 3600)
    PaperTiger.TestHelpers.reset_time()

All HTTP requests automatically include the Bearer token header.

# `advance_time`

```elixir
@spec advance_time(integer() | keyword()) :: :ok
```

Advances time by the given amount.

Only effective in `:manual` or `:accelerated` time modes.

## Parameters

Can pass either:
- A single integer representing seconds to advance
- A keyword list with time units:
  - `:seconds` - Number of seconds
  - `:minutes` - Number of minutes
  - `:hours` - Number of hours
  - `:days` - Number of days

## Examples

    iex> PaperTiger.TestHelpers.advance_time(86400)
    :ok

    iex> PaperTiger.TestHelpers.advance_time(days: 30)
    :ok

    iex> PaperTiger.TestHelpers.advance_time(days: 1, hours: 2, minutes: 30)
    :ok

# `assert_error_response`

```elixir
@spec assert_error_response(map(), String.t()) :: :ok | no_return()
```

Asserts that a response is a valid Stripe error response.

Error responses have the structure:
```
%{
  "error" => %{
    "type" => "...",
    "message" => "...",
    ...
  }
}
```

## Parameters

- `response` - The response to validate
- `expected_type` - The expected error type (e.g., "invalid_request_error", "card_error")

## Raises

`AssertionError` if the response is not a valid error structure or type doesn't match.

## Examples

    iex> response = PaperTiger.TestHelpers.get("/v1/customers/cus_invalid")
    iex> PaperTiger.TestHelpers.assert_error_response(response, "invalid_request_error")
    # Passes if it's a 404 error

    iex> PaperTiger.TestHelpers.assert_error_response(response, "card_error")
    # Raises AssertionError if type doesn't match

# `assert_list_response`

```elixir
@spec assert_list_response(map()) :: :ok | no_return()
```

Asserts that a response is a valid Stripe list response.

List responses have the structure:
```
%{
  "object" => "list",
  "data" => [...],
  "has_more" => true|false,
  "url" => "..."
}
```

## Parameters

- `response` - The response to validate

## Raises

`AssertionError` if the response is not a valid list structure.

## Examples

    iex> response = PaperTiger.TestHelpers.get("/v1/customers")
    iex> PaperTiger.TestHelpers.assert_list_response(response)
    # Passes

    iex> PaperTiger.TestHelpers.assert_list_response(%{})
    # Raises AssertionError

# `assert_stripe_object`

```elixir
@spec assert_stripe_object(map(), String.t()) :: :ok | no_return()
```

Asserts that a response is a valid Stripe object of the expected type.

## Parameters

- `object` - The object to validate (should be a map)
- `expected_type` - The expected object type string (e.g., "customer", "invoice")

## Raises

`AssertionError` if the object is not valid or type doesn't match.

## Examples

    iex> customer = PaperTiger.TestHelpers.create_customer()
    iex> PaperTiger.TestHelpers.assert_stripe_object(customer, "customer")
    # Passes

    iex> PaperTiger.TestHelpers.assert_stripe_object(customer, "invoice")
    # Raises AssertionError

# `create_customer`

```elixir
@spec create_customer(map() | keyword()) :: map()
```

Creates a customer with optional parameters.

## Parameters

`params` - Optional keyword list or map with:
- `:email` - Customer email
- `:name` - Customer name
- `:description` - Customer description
- `:metadata` - Metadata map
- `:phone` - Customer phone
- `:address` - Customer address
- `:shipping` - Shipping address
- `:tax_exempt` - Tax exemption status ("none", "exempt", "reverse")

## Returns

The created customer object as a map.

## Examples

    iex> customer = PaperTiger.TestHelpers.create_customer()
    iex> String.starts_with?(customer["id"], "cus_")
    true

    iex> customer = PaperTiger.TestHelpers.create_customer(email: "user@example.com", name: "John Doe")
    iex> customer["email"]
    "user@example.com"
    iex> customer["name"]
    "John Doe"

# `create_invoice`

```elixir
@spec create_invoice(String.t(), map() | keyword()) :: map()
```

Creates an invoice for a customer.

## Parameters

- `customer_id` - The customer ID (required)
- `params` - Optional keyword list or map with:
  - `:description` - Invoice description
  - `:metadata` - Metadata map
  - `:auto_advance` - Auto-finalize invoice (default: false)
  - `:collection_method` - "charge_automatically" or "send_invoice"
  - `:custom_fields` - Custom fields on invoice
  - `:days_until_due` - Days until payment due
  - `:default_payment_method` - Payment method ID
  - `:footer` - Invoice footer text
  - `:on_behalf_of` - Created on behalf of account

## Returns

The created invoice object as a map.

## Examples

    iex> customer = PaperTiger.TestHelpers.create_customer(email: "test@example.com")
    iex> invoice = PaperTiger.TestHelpers.create_invoice(customer["id"])
    iex> invoice["customer"]
    customer["id"]
    iex> invoice["object"]
    "invoice"

# `create_price`

```elixir
@spec create_price(String.t(), map() | keyword()) :: map()
```

Creates a price for a product with optional parameters.

## Parameters

- `product_id` - The product ID (required)
- `params` - Optional keyword list or map with:
  - `:unit_amount` - Price in cents (required)
  - `:currency` - Currency code (default: "usd")
  - `:type` - Price type ("one_time" or "recurring", default: "one_time")
  - `:recurring` - Recurring period for subscription prices
    - `:interval` - "day", "week", "month", or "year"
    - `:interval_count` - Number of intervals
  - `:metadata` - Metadata map
  - `:nickname` - Price nickname
  - `:billing_scheme` - "per_unit" or "tiered"

## Returns

The created price object as a map.

## Examples

    iex> product = PaperTiger.TestHelpers.create_product(name: "Plan")
    iex> price = PaperTiger.TestHelpers.create_price(product["id"], unit_amount: 9999)
    iex> price["unit_amount"]
    9999

    iex> price = PaperTiger.TestHelpers.create_price(
    ...>   product["id"],
    ...>   unit_amount: 2999,
    ...>   recurring: %{interval: "month", interval_count: 1}
    ...> )
    iex> price["type"]
    "recurring"

# `create_product`

```elixir
@spec create_product(map() | keyword()) :: map()
```

Creates a product with optional parameters.

## Parameters

`params` - Optional keyword list or map with:
- `:name` - Product name (required)
- `:active` - Whether product is active (default: true)
- `:description` - Product description
- `:metadata` - Metadata map
- `:images` - List of image URLs
- `:statement_descriptor` - Bank statement descriptor
- `:type` - Product type ("service" or "good")

## Returns

The created product object as a map.

## Examples

    iex> product = PaperTiger.TestHelpers.create_product(name: "Premium Plan")
    iex> product["name"]
    "Premium Plan"
    iex> product["object"]
    "product"

# `create_subscription`

```elixir
@spec create_subscription(String.t(), String.t(), map() | keyword()) :: map()
```

Creates a subscription for a customer.

## Parameters

- `customer_id` - The customer ID (required)
- `price_id` - The price ID (required)
- `params` - Optional keyword list or map with:
  - `:items` - Override items array (if not provided, uses [{price: price_id}])
  - `:default_payment_method` - Payment method ID
  - `:trial_period_days` - Number of trial days
  - `:metadata` - Metadata map
  - `:billing_cycle_anchor` - Anchor for billing cycle
  - `:cancel_at_period_end` - Cancel at end of period (boolean)
  - `:off_session` - Off-session indicator

## Returns

The created subscription object as a map.

## Examples

    iex> customer = PaperTiger.TestHelpers.create_customer()
    iex> product = PaperTiger.TestHelpers.create_product(name: "Plan")
    iex> price = PaperTiger.TestHelpers.create_price(product["id"], unit_amount: 2999)
    iex> subscription = PaperTiger.TestHelpers.create_subscription(customer["id"], price["id"])
    iex> subscription["customer"]
    customer["id"]

    iex> subscription = PaperTiger.TestHelpers.create_subscription(
    ...>   customer["id"],
    ...>   price["id"],
    ...>   trial_period_days: 14
    ...> )
    iex> subscription["status"]
    "trialing"

# `delete`

```elixir
@spec delete(
  String.t(),
  keyword()
) :: map()
```

Makes a DELETE request with automatic Bearer token authentication.

## Parameters

- `path` - Request path (e.g., "/v1/customers/cus_123")
- `opts` - Optional keyword list:
  - `:token` - Authorization token (default: "sk_test_123")
  - `:headers` - Additional headers as a keyword list

## Returns

Decoded JSON response as a map.

## Examples

    iex> response = PaperTiger.TestHelpers.delete("/v1/customers/cus_123")
    iex> response["deleted"]
    true

# `get`

```elixir
@spec get(String.t(), map(), keyword()) :: map()
```

Makes a GET request with automatic Bearer token authentication.

## Parameters

- `path` - Request path (e.g., "/v1/customers")
- `params` - Query parameters as a map (default: %{})
- `opts` - Optional keyword list:
  - `:token` - Authorization token (default: "sk_test_123")
  - `:headers` - Additional headers as a keyword list

## Returns

Decoded JSON response as a map.

## Examples

    iex> response = PaperTiger.TestHelpers.get("/v1/customers")
    iex> response["object"]
    "list"

    iex> response = PaperTiger.TestHelpers.get(
    ...>   "/v1/customers",
    ...>   %{limit: 10},
    ...>   headers: [x_request_id: "123"]
    ...> )

# `post`

```elixir
@spec post(String.t(), map(), keyword()) :: map()
```

Makes a POST request with automatic Bearer token authentication.

## Parameters

- `path` - Request path (e.g., "/v1/customers")
- `params` - Request body as a map
- `opts` - Optional keyword list:
  - `:token` - Authorization token (default: "sk_test_123")
  - `:headers` - Additional headers as a keyword list
  - `:content_type` - Content-Type header (default: "application/x-www-form-urlencoded")

## Returns

Decoded JSON response as a map.

## Examples

    iex> response = PaperTiger.TestHelpers.post("/v1/customers", %{email: "test@example.com"})
    iex> response["object"]
    "customer"

    iex> response = PaperTiger.TestHelpers.post(
    ...>   "/v1/customers",
    ...>   %{email: "admin@example.com"},
    ...>   headers: [x_custom: "value"]
    ...> )

# `reset_time`

```elixir
@spec reset_time() :: :ok
```

Resets time to the current system time.

Useful for cleaning up between tests. Clears any accumulated time offsets
and resets to real time.

## Examples

    iex> PaperTiger.TestHelpers.reset_time()
    :ok

---

*Consult [api-reference.md](api-reference.md) for complete listing*
