# How to Test Medusa API Routes: Complete Integration Testing Guide

> Learn to test Medusa API routes effectively with the createServer fixture. This guide covers integration testing and offers a supertest wrapper for authenticated HTTP requests.

- Repository: [Medusa/medusa](https://github.com/medusajs/medusa)
- Tags: how-to-guide
- Published: 2026-05-19

---

**You can test Medusa API routes using the `createServer` fixture, which spins up an in-memory Express server with full dependency injection and provides a supertest wrapper to execute authenticated HTTP requests against your routes.**

Medusa's HTTP layer is built on a lightweight Express server that loads route handlers via the **ApiLoader**. The testing framework provides a special fixture at [`packages/core/framework/src/http/__fixtures__/server/index.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__fixtures__/server/index.ts) that creates a fully-wired stack for integration testing, including authentication, query-string handling, and complete service registration.

## Understanding the Test Infrastructure

### The createServer Fixture

The `createServer` function, located in [`packages/core/framework/src/http/__fixtures__/server/index.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__fixtures__/server/index.ts), builds an in-memory Express application that mirrors production behavior. It loads all Medusa modules, registers the Awilix container, and loads routes from the repository root. The fixture returns a `request` function that wraps **supertest**, automatically handling `Content-Type`, `Accept`, and `Host` headers while building query strings.

### Request Scope and Dependency Injection

Each test request receives a `.scope` property pointing to a fresh Awilix container, replicating Medusa's runtime request scoping. This ensures that services, repositories, and the workflow engine are properly instantiated per request, as implemented in the core framework.

## Setting Up Your Test Environment

Import the fixture and initialize the server in your test suite's `beforeAll` block:

```typescript
import { createServer } from "@medusajs/core/framework/src/http/__fixtures__/server"

const { request } = await createServer(__dirname)

```

The `__dirname` parameter points to the repository root, allowing the **ApiLoader** to discover and register all API routes, including [`packages/medusa/src/api/store/products/route.ts`](https://github.com/medusajs/medusa/blob/main/packages/medusa/src/api/store/products/route.ts).

## Testing Admin Routes with Authentication

### Generating Admin JWT Tokens

The `request` function supports session injection via the `adminSession` option. The fixture automatically generates JWT tokens using the secret from your test configuration:

```typescript
const response = await request("GET", "/admin/stores", {
  adminSession: { userId: "admin_user_id" },
  headers: adminHeaders,
})

expect(response.status).toBe(200)

```

## Testing Store Routes with Publishable Keys

For customer-facing endpoints, create a publishable API key using admin credentials, then pass it in the `x-publishable-api-key` header:

```typescript
const publishableKey = await api.post(
  "/admin/api-keys",
  { title: "store key", type: "publishable" },
  adminHeaders
).then(r => r.data.api_key)

const storeHeaders = {
  headers: { "x-publishable-api-key": publishableKey.token },
}

const resp = await request("GET", "/store/products", {
  headers: storeHeaders,
})

expect(resp.status).toBe(200)
expect(resp.body.products).toBeInstanceOf(Array)

```

## Validating Query Parameters and Pagination

Test filtering and pagination by passing a `query` object. The fixture automatically serializes these into query strings and validates `req.filterableFields` and `req.queryConfig` processing:

```typescript
const resp = await request("GET", "/store/products", {
  query: { limit: 10, offset: 0, q: "unique" },
  headers: storeHeaders,
})

expect(resp.body.count).toBeLessThanOrEqual(10)
expect(resp.body.products[0].id).toBeDefined()

```

## Testing Inventory and Field Selection

Verify that computed fields like inventory quantities are properly injected by specifying fields in the request:

```typescript
const resp = await request("GET", "/store/products", {
  query: { fields: ["variants.inventory_quantity"] },
  headers: storeHeaders,
})

expect(resp.body.products[0].variants[0]).toHaveProperty("inventory_quantity")

```

## Complete Test Suite Example

A typical integration test in [`integration-tests/http/__tests__/product/store/product.spec.ts`](https://github.com/medusajs/medusa/blob/main/integration-tests/http/__tests__/product/store/product.spec.ts) follows this pattern:

```typescript
describe("GET /store/products", () => {
  let request: any
  let storeHeaders: any

  beforeAll(async () => {
    ;({ request } = await createServer(__dirname))
    
    const publishableKey = await api.post(
      "/admin/api-keys", 
      { title: "test key", type: "publishable" }, 
      adminHeaders
    ).then(r => r.data.api_key)
    
    storeHeaders = { 
      headers: { "x-publishable-api-key": publishableKey.token } 
    }
  })

  it("returns a list of published products", async () => {
    const resp = await request("GET", "/store/products", { 
      headers: storeHeaders 
    })
    
    expect(resp.status).toBe(200)
    expect(resp.body.products).toEqual(
      expect.arrayContaining([
        expect.objectContaining({ id: expect.any(String) })
      ])
    )
  })
})

```

This approach exercises the complete request-response lifecycle, validating route registration in [`packages/medusa/src/api/store/products/route.ts`](https://github.com/medusajs/medusa/blob/main/packages/medusa/src/api/store/products/route.ts), business logic execution, and authentication middleware.

## Summary

- **Use `createServer`** from [`packages/core/framework/src/http/__fixtures__/server/index.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__fixtures__/server/index.ts) to spin up an in-memory Express server with full Medusa module loading.
- **Authenticate requests** using `adminSession` for JWT-backed admin access or `x-publishable-api-key` headers for store routes.
- **Test query handling** by passing `query` objects to validate `filterableFields` and pagination logic.
- **Verify field selection** to ensure computed properties like `inventory_quantity` are properly serialized.
- **Reference existing patterns** in [`integration-tests/http/__tests__/product/store/product.spec.ts`](https://github.com/medusajs/medusa/blob/main/integration-tests/http/__tests__/product/store/product.spec.ts) and [`packages/core/framework/src/http/__tests__/bodyparser.spec.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__tests__/bodyparser.spec.ts).

## Frequently Asked Questions

### What is the createServer fixture in Medusa?

The `createServer` fixture is a testing utility in [`packages/core/framework/src/http/__fixtures__/server/index.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__fixtures__/server/index.ts) that creates an in-memory Express application, registers the Awilix dependency container, loads all API routes via the ApiLoader, and returns a supertest wrapper. It provides isolated request scopes and automatic header management for integration testing.

### How do I authenticate requests in Medusa API tests?

For admin routes, pass an `adminSession` option with a `userId` to the request function, which automatically generates a JWT using your test configuration secrets. For store routes, first create a publishable API key via the admin API, then include it in the `x-publishable-api-key` header.

### Can I test query parameters and filters in Medusa integration tests?

Yes. The `request` function accepts a `query` object that automatically serializes into URL parameters, allowing you to test `req.filterableFields`, `req.queryConfig`, pagination limits, and search queries against the full database layer.

### Where are the Medusa API route tests located in the repository?

Integration tests for API routes are located in `integration-tests/http/__tests__/`, such as [`integration-tests/http/__tests__/product/store/product.spec.ts`](https://github.com/medusajs/medusa/blob/main/integration-tests/http/__tests__/product/store/product.spec.ts). Lower-level HTTP utility tests reside in [`packages/core/framework/src/http/__tests__/bodyparser.spec.ts`](https://github.com/medusajs/medusa/blob/main/packages/core/framework/src/http/__tests__/bodyparser.spec.ts).