
Security News
Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.
@open-draft/test-server
Advanced tools
Spawns HTTP/HTTPS/WS/WSS local servers for testing.
I happened to do a lot of network testing. In my test suites, I often need to perform requests against actual HTTP/WebSocket servers, but need the flexibility to model whatever scenarios I want, including on a per-test basis. Traditional server packages likes express or fastify are great but too verbose for this particular use case.
So I've built this utility. I've been using this library for years to help me perfect the test suite for Mock Service Worker. But why build it at all?
It's also a bit silly that in 2024 some server libraries don't return a connection promise and don't give you any adequate means to get the server's actual URL. Those two are quite essential when testing the network.
This library is built on top of Hono, and you should definitely check it out! For once, it's an incredible environment-agnostic server library. But also, because you can attach existing Hono middleware to your test serves to send them to the moon.
npm install @open-draft/test-server
import { createTestHttpServer } from '@open-draft/test-server/http'
const server = createTestHttpServer({
defineRoutes(router) {
router.get('/numbers', () => {
return Response.json([1, 2, 3])
})
},
})
beforeAll(async () => {
await server.listen()
})
afterAll(async () => {
await server.close()
})
test('fetches all the numbers', async () => {
const response = await fetch(server.http.url('/numbers'))
expect(response.status).toBe(200)
await expect(response.json()).resolves.toEqual([1, 2, 3])
})
import { createTestHttpServer } from '@open-draft/test-server/http'
import { createTestWebSocketServer } from '@open-draft/test-server/ws'
const server = createTestHttpServer()
const wss = createTestWebSocketServer({
// Attach the test WebSocket server to an existing HTTP server.
server,
pathname: '/ws',
})
// Running the HTTP server will establish the WebSocket middleware as well.
await server.listen()
console.log('WebSocket server is running at:', wss.ws.url())
wss.ws.on('connect', (socket) => {
console.log('new connection:', socket.id)
})
Both the createTestHttpServer() and createTestWebSocketServer() utilities are disposable, which means they can be created within function closures (e.g. your test cases) and will be automatically cleaned up once that closure is garbage-collected.
// my.test.js
import { createTestHttpServer } from '@open-draft/test-server/http'
it('fetches a resource by id', async () => {
await using server = createTestHttpServer({
defineRoutes(router) {
router.get('/resource/:id', () => {
return Response.json({ a: 1 })
})
}
})
await fetch(server.http.url('/resource/abc-123'))
})
In the test case above, the test HTTP server will automatically be closed once the test case is done!
The "rooms" you can create in the test HTTP server are also disposable, which allows you to append additional behaviors to an already existing test server instance.
const server = createTestHttpServer()
beforeAll(async () => await server.listen())
afterAll(async () => await server.listen())
it('handles errors when fetching a resource', async () => {
await using room = server.http.createRoom({
defineRoutes(router) {
router.get('/resource', () => {
return new Response(null, { status: 404 })
})
}
})
await fetch(room.url('/resource'))
})
Note that the request references the
/resourcepathname nested under the room (room.url()).
createTestHttpServer([options])Creates a test HTTP server instance. The server instance is not running until you call server.listen()
options (optional)
protocols, (optional) Array<'http' | 'htts', the list of protocols to spawn corresponding test servers. For example, providing ['http', 'https'] will spawn two test servers (HTTP and HTTPS) with the same route handlers.defineRoutes, (optional) (router: Hono) => void, a function describing the initial route handlers.const server = createTestHttpServer({
protocols: ['http', 'https'],
defineRoutes(router) {
router.get('/user', () => {
return Response.json(userFixture)
})
},
})
TestHttpServerTestHttpServer.listen([options])options (optional)
hostname, (optional) string, the exact hostname to use for this server.TestHttpServer.close()Closes the HTTP server, aborting any pending requests.
TestHttpServer.http.url([pathname])pathname (optional) string, a pathname to rebase against the server URL.const server = createTestHttpServer()
await server.listen()
server.http.url() // "http://localhost:57834"
server.http.url('/resource') // "http://localhost:57834/resource"
TestHttpServer.http.createRoom([options])Create a new room on this server. Room is a set of route handlers scoped under a random base path.
options (optional)
defineRoutes, (optional) (router: Hono) => void, a function describing the routes for this room. Note that all room routes are scoped to the random room base path.const server = createTestHttpServer()
await server.listen()
const room = server.http.creaetRoom({
defineRouter(router) {
router.get('/resource', () => new Response())
},
})
room.url() // "http://localhost:57834/48e34ef7-13d0-4b6b-862f-4a29475c3396"
await fetch(room.url('/resource'))
Creating rooms with their own route handlers allows you to reuse the same running server instance while imbuing it with different functionality on a per-test basis.
createTestWebSocketServer(options)options
server, TestHttpServer, a reference to the server instance created by calling the createTestHttpServer() utility.pathname, string, a pathname of the given HTTP server where the WebSocket connection must be established.TestWebSocketServer.ws.url()TestWebSocketServer.wss.url()Returns an absolute URL to this WebSocket connection.
Note that the
.url()method on the WebSocket server does not accept apathname. The WebSocket protocol does not define the concept of sub-resources, so there is no point in referencing nested paths that point at nothing.
TestWebSocketServer.on(type, listener)Adds an event listener to the underlying WebSocket connection.
const wss = createTestWebSocketServer({
server,
pathname: '/ws',
})
wss.ws.on('connection', (socket) => {
// Handle any incoming WebSocket client connections
// to this test WebSocket server under HTTP.
})
TestWebSocketServer.once(type, listener)Adds a one-time event listener to this WebSocket connection.
TestWebSocketServer.off(type, listener)Removes the event listener for the given event type from this WebSocket connection.
TestWebSocketServer.close()Closes the WebSocket server, closing any active clients.
[!IMPORTANT] Note that closing the WebSocket server does not close the parent HTTP server. Closing the parent HTTP server, however, will automatically close any attached WebSocket servers.
FAQs
HTTP/HTTPS testing server for your tests.
The npm package @open-draft/test-server receives a total of 2,734 weekly downloads. As such, @open-draft/test-server popularity was classified as popular.
We found that @open-draft/test-server demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.

Research
Five malicious NuGet packages impersonate Chinese .NET libraries to deploy a stealer targeting browser credentials, crypto wallets, SSH keys, and local files.

Security News
pnpm 11 turns on a 1-day Minimum Release Age and blocks exotic subdeps by default, adding safeguards against fast-moving supply chain attacks.