> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craveup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> Test your storefront with mock data, test mode, and example test suites.

Crave provides tools for testing your storefront integration without affecting live data. This guide covers test API keys, mock data patterns, and example test suites.

## Test mode

Use a test API key (prefixed with `sk_test_`) to make requests against the production API without creating real orders or processing real payments.

```env filename=".env.local" theme={null}
NEXT_PUBLIC_CRAVEUP_API_KEY=sk_test_your_test_key
```

Test mode behaves identically to production with these differences:

| Behavior    | Production         | Test mode                |
| ----------- | ------------------ | ------------------------ |
| Orders      | Sent to restaurant | Logged but not sent      |
| Payments    | Real charges       | Stripe test mode         |
| Webhooks    | Production URL     | Test URL (if configured) |
| Rate limits | 200/10 min         | 200/10 min (same)        |

Generate a test API key from the [Dashboard](https://craveup.com/login) under **Settings > API Keys > Test Keys**.

## Test Stripe payments

In test mode, Crave automatically uses Stripe's test environment. Use Stripe's test card numbers:

| Card                  | Scenario                    |
| --------------------- | --------------------------- |
| `4242 4242 4242 4242` | Successful payment          |
| `4000 0000 0000 3220` | 3D Secure required          |
| `4000 0000 0000 0002` | Card declined               |
| `4000 0025 0000 3155` | SCA authentication required |

Use any future expiry date and any 3-digit CVC.

## Unit testing the SDK

The SDK accepts a custom `fetch` implementation, making it easy to mock API responses in tests:

```ts filename="__tests__/cart.test.ts" theme={null}
import { describe, it, expect, vi } from 'vitest';
import { createStorefrontClient } from '@craveup/storefront-sdk';

function createMockClient(responses: Record<string, unknown>) {
  const mockFetch = vi.fn(async (url: string) => ({
    ok: true,
    status: 200,
    headers: new Headers({ 'content-length': '1' }),
    json: async () => responses[url] ?? {},
    text: async () => JSON.stringify(responses[url] ?? {}),
  }));

  const client = createStorefrontClient({
    apiKey: 'sk_test_mock',
    fetch: mockFetch as unknown as typeof fetch,
  });

  return { client, mockFetch };
}

describe('cart', () => {
  it('adds an item and returns updated cart', async () => {
    const { client } = createMockClient({
      'https://api.craveup.com/api/v1/locations/loc_123/carts/cart_456/cart-item': {
        cartId: 'cart_456',
        cart: {
          id: 'cart_456',
          totalQuantity: 1,
          orderTotalWithServiceFee: '12.99',
        },
      },
    });

    const result = await client.cart.addItem('loc_123', 'cart_456', {
      productId: 'prod_margherita',
      quantity: 1,
      selections: [],
      itemUnavailableAction: 'remove_item',
    });

    expect(result.cart.totalQuantity).toBe(1);
    expect(result.cart.orderTotalWithServiceFee).toBe('12.99');
  });
});
```

## Test error handling

Verify your app handles API errors correctly:

```ts filename="__tests__/errors.test.ts" theme={null}
import { describe, it, expect } from 'vitest';
import { createStorefrontClient, ApiError } from '@craveup/storefront-sdk';

describe('error handling', () => {
  it('throws ApiError on 400 response', async () => {
    const mockFetch = async () => ({
      ok: false,
      status: 400,
      statusText: 'Bad Request',
      headers: new Headers(),
      text: async () => JSON.stringify({
        error: 'VALIDATION_ERROR',
        message: 'Invalid product ID',
      }),
    });

    const client = createStorefrontClient({
      apiKey: 'sk_test_mock',
      fetch: mockFetch as unknown as typeof fetch,
    });

    await expect(
      client.cart.addItem('loc_123', 'cart_456', {
        productId: 'invalid',
        quantity: 1,
        selections: [],
        itemUnavailableAction: 'remove_item',
      })
    ).rejects.toThrow(ApiError);
  });
});
```

## Integration testing

For integration tests against the real API, use your test API key and clean up after each test:

```ts filename="__tests__/integration/ordering-flow.test.ts" theme={null}
import { describe, it, expect, afterEach } from 'vitest';
import { createStorefrontClient } from '@craveup/storefront-sdk';

const storefront = createStorefrontClient({
  apiKey: process.env.CRAVEUP_TEST_API_KEY!,
});

const LOCATION_ID = process.env.CRAVEUP_TEST_LOCATION_ID!;
let cartId: string | undefined;

afterEach(async () => {
  if (cartId) {
    await storefront.cart.delete(LOCATION_ID, cartId).catch(() => {});
    cartId = undefined;
  }
});

describe('ordering flow', () => {
  it('creates a session and adds an item', async () => {
    const session = await storefront.orderingSessions.start(LOCATION_ID, {
      marketplaceId: LOCATION_ID,
    });

    expect(session.cartId).toBeDefined();
    cartId = session.cartId!;

    const result = await storefront.cart.addItem(LOCATION_ID, cartId, {
      productId: 'prod_test_item',
      quantity: 1,
      selections: [],
      itemUnavailableAction: 'remove_item',
    });

    expect(result.cart.totalQuantity).toBe(1);
  });
});
```

## Testing webhook handlers

Send mock webhook payloads to your local handler:

```ts filename="__tests__/webhooks.test.ts" theme={null}
import { describe, it, expect } from 'vitest';
import { createHmac } from 'crypto';

const WEBHOOK_SECRET = 'whsec_test_secret';

function signPayload(payload: string): string {
  return createHmac('sha256', WEBHOOK_SECRET).update(payload).digest('hex');
}

describe('webhook handler', () => {
  it('processes order.created events', async () => {
    const payload = JSON.stringify({
      id: 'evt_test_123',
      type: 'order.created',
      data: {
        orderId: 'ord_test_456',
        cartId: 'cart_test_789',
        locationId: 'loc_test_123',
        customerName: 'Test User',
        total: '25.98',
      },
    });

    const response = await fetch('http://localhost:3000/api/webhooks', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Crave-Signature': signPayload(payload),
      },
      body: payload,
    });

    expect(response.status).toBe(200);
  });
});
```

## Next steps

<CardGroup cols={2}>
  <Card title="Error Codes" icon="triangle-alert" href="/guides/error-codes">
    Handle every error the API can return.
  </Card>

  <Card title="Deployment" icon="rocket" href="/guides/deployment">
    Deploy your storefront to production.
  </Card>
</CardGroup>
