npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

payload-test-api-route-handler

v1.0.0

Published

Test Payload CMS v3+ API route handlers in-process using Axios — no HTTP server needed. Supports auth, transactions, request patching, built-in CRUD endpoints, and custom endpoints.

Readme

payload-test-api-route-handler

Test Payload CMS API routes without a running server.

npm version npm downloads License: MIT TypeScript Payload CMS

An in-process test utility for Payload CMS v3+ that lets you exercise API route handlers, authentication, database transactions, and custom endpoints using a standard Axios client — without starting a live HTTP server.


Why?

Testing Payload CMS endpoints typically requires spinning up a full Next.js dev server. This is slow, flaky, and makes CI pipelines painful.

This package gives you a drop-in Axios client that routes requests directly into Payload's handler pipeline in-process. Your tests run in milliseconds, not seconds.

Traditional approach          This package
┌──────────┐                  ┌──────────┐
│  Test     │ ── HTTP ──►     │  Test     │
│  Suite    │                 │  Suite    │
└──────────┘                  └─────┬────┘
     │                              │
     ▼                              ▼  (in-process)
┌──────────┐                  ┌──────────┐
│  HTTP    │                  │  Payload │
│  Server  │                  │  Handler │
└─────┬────┘                  └──────────┘
      │                       No network. No server.
      ▼                       Just fast tests.
┌──────────┐
│  Payload │
│  Handler │
└──────────┘

Features

  • 🚀 Zero Server — No HTTP server, no port conflicts, no startup delay
  • 🔐 Full Auth Pipeline — JWT login, token resolution, req.user — it all works
  • 🗄️ Real Transactions — Database transaction context flows through hooks exactly like production
  • 🧬 Request Patching — Inject custom user sessions, override route params, mock anything
  • 📦 Standard Axios — Interceptors, defaults, client.defaults.headers — everything you expect
  • 🧪 Framework Agnostic — Works with Vitest, Jest, or any test runner
  • 🎯 Full Endpoint Coverage — Config endpoints, collection endpoints, global endpoints, and built-in CRUD

Installation

# npm
npm install --save-dev payload-test-api-route-handler

# yarn
yarn add -D payload-test-api-route-handler

# pnpm
pnpm add -D payload-test-api-route-handler

Peer dependency: Requires payload v3.85.1 or later.

Quick Start

import { describe, it, expect, beforeAll } from 'vitest';
import { getPayload } from 'payload';
import { buildConfig } from 'payload';
import { sqliteAdapter } from '@payloadcms/db-sqlite';
import { lexicalEditor } from '@payloadcms/richtext-lexical';
import { createTesterAxios } from 'payload-test-api-route-handler';

describe('My API', () => {
  let config;

  beforeAll(async () => {
    config = await buildConfig({
      db: sqliteAdapter({ client: { url: 'file::memory:' } }),
      editor: lexicalEditor({}),
      secret: 'test-secret-at-least-32-chars-long!!',
      collections: [
        {
          slug: 'posts',
          fields: [{ name: 'title', type: 'text', required: true }],
          endpoints: [
            {
              path: '/featured',
              method: 'get',
              handler: async () =>
                Response.json({ featured: true }),
            },
          ],
        },
      ],
    });

    await getPayload({ config });
  });

  it('hits a custom endpoint', async () => {
    const client = createTesterAxios(config);
    const res = await client.get('/api/posts/featured');

    expect(res.status).toBe(200);
    expect(res.data).toEqual({ featured: true });
  });

  it('creates a post via built-in CRUD', async () => {
    const client = createTesterAxios(config);
    const res = await client.post('/api/posts', {
      title: 'Hello World',
    });

    expect(res.status).toBe(201);
    expect(res.data.doc.title).toBe('Hello World');
  });
});

Usage Recipes

Authentication Flow

const client = createTesterAxios(config);

// Login
const { data } = await client.post('/api/users/login', {
  email: '[email protected]',
  password: 'password',
});

// Set token for all subsequent requests
client.defaults.headers.common['Authorization'] = `JWT ${data.token}`;

// Now all requests are authenticated
const res = await client.get('/api/users/me');
expect(res.data.user.email).toBe('[email protected]');

Request Patching

Inject a mock user, override route parameters, or modify the request before it hits the handler:

const client = createTesterAxios(config, {
  requestPatcher: (req) => {
    // Force a specific user for all requests
    req.user = { id: '1', email: '[email protected]' };
    return req;
  },
});

Custom Axios Configuration

const client = createTesterAxios(config, {
  axiosConfig: {
    timeout: 5000,
    // Don't throw on 4xx/5xx — useful for testing error responses
    validateStatus: () => true,
  },
});

const res = await client.get('/api/nonexistent');
expect(res.status).toBe(404);

API Reference

createTesterAxios(config, options?)

Creates an Axios instance that routes requests in-process to Payload CMS handlers.

Parameters:

| Parameter | Type | Description | |-----------|------|-------------| | config | SanitizedConfig | The sanitized config returned by buildConfig() | | options.requestPatcher | (req: PayloadRequest) => PayloadRequest \| Promise<PayloadRequest> | Mutate the request before handler execution | | options.axiosConfig | AxiosRequestConfig | Default Axios configuration for the instance |

Returns: AxiosInstance — a standard Axios client.


Exported Utilities

| Export | Description | |--------|-------------| | createTesterAxios | Main entry point — creates the test Axios client | | createAxiosAdapter | Lower-level adapter if you need custom Axios setup | | matchEndpoint | Manually match a path/method to a Payload endpoint | | matchRoute | Pattern matching utility for Express-style :param routes | | buildPayloadRequest | Construct a PayloadRequest from raw URL, method, headers | | EndpointNotFoundError | Thrown when no matching endpoint is found | | HandlerExecutionError | Thrown when a handler throws during execution |

How It Works

createTesterAxios(config)
        │
        ▼
   Axios Instance
   (custom adapter)
        │
   client.get('/api/posts/featured')
        │
        ▼
  ┌─────────────────┐
  │ matchEndpoint()  │  ← Resolves handler + route params
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │ buildPayload     │  ← Creates PayloadRequest with
  │ Request()        │    auth, headers, body, transaction
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │ requestPatcher() │  ← Optional mutation hook
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │ handler(req)     │  ← Your endpoint handler runs
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │ Response →       │  ← Converted to AxiosResponse
  │ AxiosResponse    │
  └─────────────────┘

Contributing

Contributions are welcome! Please feel free to open an issue or submit a pull request.

# Clone and install
git clone https://github.com/000MaDz000/payload-test-api-route-handler.git
cd payload-test-api-route-handler
pnpm install

# Run tests
pnpm test

# Build
pnpm build

# Lint & format
pnpm lint
pnpm format

License

MIT © MaDz