Unexpected HTTP Server Testing Plugin
unexpected-http is a plugin for the `unexpected` assertion library, specifically designed for testing HTTP servers and clients. It extends `unexpected`'s declarative syntax, allowing developers to write expressive assertions against HTTP requests and responses, mimicking the style of `unexpected-express`. As of version 9.0.0, it supports `unexpected` versions 10 through 13. The library enables fluent testing of server-side applications by asserting on status codes, headers, and body content of HTTP interactions. While its release cadence often aligns with its core `unexpected` dependency, it receives updates to maintain compatibility and introduce features relevant to HTTP testing. Its primary differentiator is its deep integration into the `unexpected` ecosystem, providing a consistent assertion experience across various testing scenarios, including frontend, backend, and API testing, by leveraging `unexpected`'s powerful diffing and introspection capabilities for failed assertions.
Common errors
-
Error: Cannot find module 'unexpected'
cause The core `unexpected` assertion library, which is a peer dependency, is not installed or not resolvable by your package manager.fixInstall `unexpected` in your project: `npm install unexpected` or `yarn add unexpected`. -
TypeError: expect(...).to yield response is not a function
cause The `unexpected-http` plugin has not been correctly applied to the `expect` instance, or `expect` itself is not correctly imported.fixEnsure `import { expect } from 'unexpected';` (or `const expect = require('unexpected').expect;`) is at the top of your test file, and `expect.use(unexpectedHttp);` is called to register the plugin. -
npm ERR! ERESOLVE unable to resolve dependency tree
cause Your project's version of `unexpected` conflicts with the peer dependency requirements of `unexpected-http`.fixExamine the `peerDependencies` field in `unexpected-http`'s `package.json` (or the error message) and adjust your `unexpected` version to fit the range. For example, `npm install unexpected@^13.0.0` or `npm install --legacy-peer-deps` (use `legacy-peer-deps` with caution as a temporary workaround).
Warnings
- breaking Version 9.0.0 includes breaking changes, primarily due to updates in its peer dependency `unexpected` and potential shifts in supported Node.js versions. Always consult the `unexpected` changelog for major version updates to understand core assertion library changes.
- gotcha Peer dependency conflicts with `unexpected` are common. If `npm install` or `yarn install` report warnings or errors about `unexpected`, it means your project's version of `unexpected` does not satisfy the range required by `unexpected-http`.
- gotcha When writing tests, ensure `expect.use(unexpectedHttp);` is called at a global level (e.g., in a setup file or before all tests) so that the HTTP assertions are available to your `expect` instance.
Install
-
npm install unexpected-http -
yarn add unexpected-http -
pnpm add unexpected-http
Imports
- unexpectedHttp
import { unexpectedHttp } from 'unexpected-http';import unexpectedHttp from 'unexpected-http';
- expect
const expect = require('unexpected');import { expect } from 'unexpected'; - unexpectedHttp (CommonJS)
const { unexpectedHttp } = require('unexpected-http');const unexpectedHttp = require('unexpected-http');
Quickstart
import { expect } from 'unexpected';
import unexpectedHttp from 'unexpected-http';
import express from 'express';
import supertest from 'supertest';
// Activate the unexpected-http plugin
expect.use(unexpectedHttp);
const app = express();
app.use(express.json()); // For parsing application/json
app.get('/hello', (req, res) => {
res.status(200).json({ message: 'Hello, World!' });
});
app.post('/echo', (req, res) => {
if (!req.body || Object.keys(req.body).length === 0) {
return res.status(400).json({ error: 'Request body is empty' });
}
res.status(200).json({ received: req.body });
});
describe('HTTP Server Tests with unexpected-http', () => {
let requestAgent: supertest.SuperTest<supertest.Test>;
beforeAll(() => {
// Use supertest to create a test agent for the Express app
requestAgent = supertest(app);
});
it('should respond with a greeting on GET /hello', async () => {
await expect(
requestAgent.get('/hello'),
'to yield response',
{
status: 200,
headers: { 'content-type': 'application/json; charset=utf-8' },
body: { message: 'Hello, World!' }
}
);
});
it('should echo the JSON body on POST /echo', async () => {
const payload = { data: 'test data', value: 123 };
await expect(
requestAgent.post('/echo').send(payload),
'to yield response',
{
status: 200,
headers: { 'content-type': 'application/json; charset=utf-8' },
body: { received: payload }
}
);
});
it('should return 400 for an empty body on POST /echo', async () => {
await expect(
requestAgent.post('/echo').send({}),
'to yield response',
400
);
});
});