Keploy logo
Express logo

Keploy as a Express testing framework

Keploy tests Express applications by recording real requests through the running server and every database or HTTP call they trigger, then replaying both as assertions. The full middleware chain is exercised, because the request travelled it — no hand-built app instance, no supertest wiring.

Generate Express tests free
keploy record -c "node server.js"
18.4K+VS Code1.2M+300M+mocks created

What Keploy gives a Express team

Express 4 and 5, unchanged

Keploy wraps your real entrypoint, so the middleware stack under test is the one your server assembles. Router structure, CJS versus ESM, and TypeScript all make no difference to capture.

  • Express 4 and 5
  • No exported app object needed
  • CJS, ESM, and TypeScript
  • Any router and middleware order
The problem

Why Express integration tests slow teams down

The friction is rarely the assertions. It is everything around them — spinning up dependencies, keeping mocks honest, and repairing tests after every refactor.

Three ways to do it

Testing Express: by hand, with supertest + nock, or with Keploy

supertest binds an app the test file assembles, so middleware configured in your server entrypoint is missing. Keploy records the running process, so the app under test is the app you deploy.

Select any row for the full comparison, with code.

Same coverage, three costs

What you write for Express vs what Keploy records

All three produce the same assertion. Only the third still passes after the next refactor without anyone editing it.

By hand2–4 hours
confirmOrder.manual.test.js
hand-written
// Hand-written: the handler is called directly, past the middleware.
const confirmOrder = require('../src/routes/confirmOrder');
 
function mockRes() {
const res = { statusCode: 200, body: null };
res.status = (c) => ((res.statusCode = c), res);
res.json = (b) => ((res.body = b), res);
return res;
}
 
test('confirms an authorized order', async () => {
const req = {
params: { id: 'ord_1' },
body: { paymentToken: 'tok_123' },
app: { locals: { repo: fakeRepo, payments: fakePayments } },
};
const res = mockRes();
 
await confirmOrder(req, res);
 
expect(res.statusCode).toBe(200);
expect(res.body.state).toBe('CONFIRMED');
});

Fast and dependency-free, and it proves nothing about whether the route is reachable, authenticated, or receiving a parsed body.

supertest + nock1–2 hours
confirmOrder.supertest.test.js
tool-assisted
// supertest + nock — the app is assembled by the test file.
const nock = require('nock');
const request = require('supertest');
const express = require('express');
const ordersRouter = require('../src/routes/orders');
 
let app;
 
beforeEach(async () => {
app = express();
app.use(express.json());
app.use('/orders', ordersRouter);
await seedOrders([{ _id: 'ord_1', amountMinor: 4200, state: 'NEW' }]);
 
nock('https://api.payments.example.com')
.post('/v1/payment_intents/tok_123/confirm')
.reply(200, { status: 'AUTHORIZED' });
});
 
afterEach(() => nock.cleanAll());
 
it('confirms an authorized order', async () => {
const res = await request(app)
.post('/orders/ord_1/confirm')
.send({ paymentToken: 'tok_123' });
 
expect(res.status).toBe(200);
expect(res.body.state).toBe('CONFIRMED');
});

Note what is missing: helmet, the rate limiter, the auth middleware, and the error handler that server.js mounts. This app is not that app.

With Keploy~5 minutes
test-1.yaml
auto-generated
# Recorded with: keploy record -c 'node server.js'
# The request travelled the real middleware stack.
version: api.keploy.io/v1beta1
kind: Http
name: test-1
spec:
req:
method: POST
url: /orders/ord_1/confirm
header:
Content-Type: application/json
Authorization: Bearer <captured>
body: '{"paymentToken":"tok_123"}'
resp:
status_code: 200
header:
X-RateLimit-Remaining: "99"
body:
id: "ord_1"
state: "CONFIRMED"
amountMinor: 4200
confirmedAt: "2026-09-02T11:04:18Z"
noise:
- body.confirmedAt
- header.X-RateLimit-Remaining
mocks:
- kind: Mongo
operation: "orders.findOne({ _id: 'ord_1' })"
- kind: Http
url: https://api.payments.example.com/v1/payment_intents/tok_123/confirm
status: 200

The rate-limit header in the response is evidence the request passed through the real stack — something a test-file-assembled app never shows.

Times are estimates for authoring one endpoint’s coverage from scratch, not measurements.

Keploy vs the alternatives

Express testing tools, compared

The options a team on Node.js actually reaches for, and where each one genuinely wins. Select a row for the full comparison.

Best in classStrongPartialNot covered

Assessments reflect each tool’s documented behaviour, not benchmark measurements.

How it works

Record your Express app once, replay it forever

Keploy sits below your Express process at the network layer. It watches the calls your app already makes, then serves them back on replay so tests run with no dependencies attached.

Keploy records a GET call to /api/v1/orders/{id} on a Express service and captures the dependency calls it makes.

An example shape of a captured call. Your own endpoints and dependencies come from your real traffic, so nothing here has to be written by hand.
Mock coverage

What Keploy mocks for Express, with zero config

7 of the 7 dependencies a typical Express service talks to are stubbed from the recording itself — no mock classes, no fixture files, no containers in CI.

Quick start

Your first Express test suite in under five minutes

Every command below runs against your existing Express service. Nothing in your source tree changes.

  1. 1Install the Keploy CLI

    A standalone binary, not an npm package — package.json and your lockfile stay untouched.

    curl -sSL https://keploy.io/install.sh | bash
  2. 2Record your server

    Use the entrypoint you deploy, so the middleware stack under test is the real one.

    keploy record -c "node server.js"
  3. 3Hit your routes

    Each request becomes a test case with its Mongo and HTTP calls captured alongside it.

    curl -X POST localhost:3000/orders/ord_1/confirm -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"paymentToken":"tok_123"}'
  4. 4Replay in CI

    Replay serves recorded dependency responses, so the runner needs no database or broker.

    keploy test -c "node server.js" --delay 8

Ready to try it on your own Express service?

Ecosystem

Works with the rest of your Express stack

Keploy records at the network layer, so framework and driver choices inside your Express app do not change how it captures traffic.

  • Node.js logo

    Node.js

    The runtime page covers driver-level mock coverage in depth.

  • Mongoose logo

    Mongoose

    Model calls record as MongoDB wire traffic, not as method calls.

  • Prisma logo

    Prisma

    Recorded as the Postgres or MySQL protocol the client emits.

  • Passport logo

    Passport

    Auth middleware runs on every recorded request, so tokens are exercised.

  • TypeScript logo

    TypeScript

    Wrap the compiled entrypoint or tsx — capture is source-agnostic.

  • Docker logo

    Docker

    Record in a container or on the host; replay needs neither.

FAQ

Express testing with Keploy: common questions

Join our GlobalCommunity

Connect with developers worldwide. Follow updates, ask questions, share feedback, and ship faster with other Keploy builders.

1.2M+Installs
18.4K+GitHub
100K+Devs
300M+Mocks
1K+Contributors
#1OSS Trending
4.9★★★★★from 500+ reviews onG2GartnerVS CodeChrome
★★★★★

Best report of integration and API tests I've seen — which we don't get from RestAssured.

G2
★★★★★

Future of microservices testing. I don't write tests now!

G2 · 5/5
★★★★★

An amazing product that simplifies the automation.

Gartner · 4.0
XGitHubSlackYouTubeLinkedIn
Built by developers, for developers.Let's build the future, together.