How to Write Tests for JSON Server Customizations: A Complete Guide
Use the Node.js native test runner with LowDB's Memory adapter to spin up real HTTP instances of your customized JSON Server and assert against live endpoints using fetch.
Testing customizations in typicode/json-server ensures your extended routes, middleware, and service-layer modifications remain stable across updates. Because JSON Server is built on TinyHTTP and exposes an Express-compatible App instance, you can import createApp directly into your test files, inject an in-memory LowDB database, and execute real HTTP requests against your custom logic.
This guide demonstrates the exact patterns used in the official repository to test static directories, custom endpoints, and service extensions.
Setting Up the Test Environment with In-Memory LowDB
Isolating your tests from the filesystem prevents flaky assertions and side effects. JSON Server uses LowDB for data persistence, and the Memory adapter provides a clean slate for every test run.
Installing Development Dependencies
You need utilities to acquire free ports and manage temporary files:
npm install --save-dev get-port tempy
get-port→ Resolves an available TCP port to avoid collisions.tempy→ Creates disposable directories for testing static file serving.
Creating an Isolated In-Memory Database
Import the Memory adapter and instantiate Low with your data type:
import { Low, Memory } from 'lowdb';
import type { Data } from './service.ts';
const db = new Low<Data>(new Memory<Data>(), { posts: [] });
This db instance is passed directly into createApp, ensuring no files are written to disk during test execution.
Testing JSON Server Custom Routes and Middleware
Custom routes must be registered before the generic /:name CRUD handlers. The test suite in src/app.test.ts demonstrates how to verify these extensions using the native Node.js test runner.
Spinning Up the App with Custom Static Directories
When testing static file serving, inject a temporary directory into the static option:
import { createApp } from './app.ts';
import { join } from 'node:path';
import { temporaryDirectory } from 'tempy';
import { writeFileSync } from 'node:fs';
// Create a temp folder with a test asset
const staticDir = temporaryDirectory();
writeFileSync(join(staticDir, 'hello.html'), '<h1>Hello</h1>');
// Initialize the server with custom static configuration
const app = createApp(db, { static: [staticDir] });
Writing Integration Tests with node:test and fetch
Use node:test and node:assert to execute real HTTP requests against the running server:
import test from 'node:test';
import assert from 'node:assert';
import getPort from 'get-port';
const port = await getPort();
const server = app.listen(port, () => {});
// Clean up after tests complete
test.after(() => server.close());
// Test custom static file serving
await test('serves custom static file', async () => {
const response = await fetch(`http://localhost:${port}/hello.html`);
assert.equal(response.status, 200);
const body = await response.text();
assert.equal(body, '<h1>Hello</h1>');
});
// Test built-in CRUD functionality still works
await test('GET /posts returns 200', async () => {
const response = await fetch(`http://localhost:${port}/posts`);
assert.equal(response.status, 200);
});
This pattern validates that your customizations do not interfere with the default JSON Server behavior.
Testing Custom Service Layer Extensions
For business logic extensions—such as adding a bulkDelete method to the Service class—write unit tests that bypass HTTP entirely. The existing src/service.test.ts provides the template.
Unit Testing Service Methods Without HTTP
Import the Service class and invoke methods directly against the in-memory database:
import { Service } from './service.ts';
import { Low, Memory } from 'lowdb';
import type { Data } from './service.ts';
const db = new Low<Data>(new Memory<Data>(), { posts: [] });
const service = new Service(db);
await test('bulkDelete removes all posts', async () => {
// Seed the database
db.data!.posts = [{ id: '1', title: 'First' }, { id: '2', title: 'Second' }];
await db.write();
// Execute custom service method
await service.bulkDelete('posts');
// Assert state
assert.equal(db.data!.posts.length, 0);
});
This approach is faster than HTTP integration tests and isolates logic errors from routing issues.
Running the Full Test Suite
Execute all tests using the Node.js native runner:
npm test
This command runs both src/app.test.ts and src/service.test.ts, validating HTTP endpoints and service-layer logic simultaneously.
Summary
- Isolate state using LowDB's
Memoryadapter to prevent filesystem dependencies in your test suite. - Use
createAppto instantiate the TinyHTTP server with custom static directories or middleware configurations. - Execute real HTTP requests via
fetchinsidenode:testblocks to verify routing and middleware behavior. - Test service extensions by instantiating the
Serviceclass directly against an in-memory database for fast, isolated unit tests. - Reference
src/app.test.tsandsrc/service.test.tsas canonical examples of integration and unit testing patterns in the JSON Server codebase.
Frequently Asked Questions
How do I test custom routes in JSON Server?
Register your custom routes inside the createApp function before the generic /:name CRUD handlers, then start the server on a random port using get-port and assert against the endpoint with fetch. The src/app.test.ts file demonstrates this pattern for static files and query parameters.
What testing framework does JSON Server use?
JSON Server uses the Node.js native test runner (node:test and node:assert), requiring no external testing frameworks like Jest or Mocha. This choice keeps the dependency tree minimal and leverages built-in Node.js features available in version 18 and later.
How do I mock the database for JSON Server tests?
Use LowDB's Memory adapter instead of the file-based JSON adapter. Create a new Low<Data>(new Memory<Data>(), defaultData) instance and pass it to createApp. This provides a fresh, isolated database for every test without writing to the filesystem.
Can I test static file serving in JSON Server?
Yes. Use the tempy package to create a temporary directory, write test files to it, and pass the directory path in the static option when calling createApp. Then start the server and request the file via fetch to verify it returns the correct content and HTTP 200 status.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →