supertest
🕷 Super-agent driven library for testing node.js HTTP servers using a fluent API. Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
Top Related Projects
Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
Promise based HTTP client for the browser and node.js
🏊🏾 Simplified HTTP request client.
🌐 Human-friendly and powerful HTTP request library for Node.js
A light-weight module that brings the Fetch API to Node.js
Newman is a command-line collection runner for Postman
Quick Overview
Supertest is a popular Node.js library for testing HTTP servers. It provides a high-level abstraction for testing HTTP, making it easier to send requests and assert responses in your tests. Supertest is often used in combination with testing frameworks like Mocha or Jest.
Pros
- Easy to use and intuitive API
- Supports both callback and promise-based testing
- Integrates well with various Node.js testing frameworks
- Allows for testing of both Express applications and raw Node.js http servers
Cons
- Limited to testing HTTP servers only
- May not be suitable for complex API testing scenarios
- Doesn't provide built-in support for authentication or session management
- Can be slower compared to unit tests due to the nature of HTTP requests
Code Examples
- Basic GET request test:
const request = require('supertest');
const app = require('../app');
describe('GET /users', function() {
it('responds with json', function(done) {
request(app)
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
- POST request with data:
const request = require('supertest');
const app = require('../app');
describe('POST /users', function() {
it('creates a new user', function(done) {
request(app)
.post('/users')
.send({ name: 'John Doe', email: 'john@example.com' })
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(201)
.end(function(err, res) {
if (err) return done(err);
expect(res.body.name).to.equal('John Doe');
done();
});
});
});
- Using async/await:
const request = require('supertest');
const app = require('../app');
describe('GET /users/:id', function() {
it('responds with user details', async function() {
const response = await request(app)
.get('/users/1')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body.id).to.equal(1);
expect(response.body.name).to.be.a('string');
});
});
Getting Started
To use Supertest in your project, follow these steps:
- Install Supertest:
npm install supertest --save-dev
- In your test file, require Supertest and your app:
const request = require('supertest');
const app = require('../app');
- Write your tests using Supertest:
describe('GET /', function() {
it('responds with 200', function(done) {
request(app)
.get('/')
.expect(200, done);
});
});
- Run your tests using your preferred test runner (e.g., Mocha, Jest).
Competitor Comparisons
Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
Pros of Superagent
- More versatile and feature-rich for general HTTP requests
- Supports both Node.js and browser environments
- Offers a chainable API for building complex requests
Cons of Superagent
- Larger library size, which may impact performance in some scenarios
- Steeper learning curve due to more extensive API
- Not specifically designed for testing, unlike Supertest
Code Comparison
Superagent:
const superagent = require('superagent');
superagent
.get('/api/users')
.query({ limit: 10 })
.end((err, res) => {
// Handle response
});
Supertest:
const request = require('supertest');
const app = require('./app');
request(app)
.get('/api/users')
.query({ limit: 10 })
.expect(200)
.end((err, res) => {
// Assert response
});
Summary
Superagent is a more general-purpose HTTP client library, while Supertest is specifically designed for testing HTTP servers. Superagent offers more flexibility and features for making various types of HTTP requests, but Supertest provides a simpler API focused on testing Express.js applications. The choice between the two depends on the specific use case, with Supertest being more suitable for testing scenarios and Superagent for broader HTTP client needs.
Promise based HTTP client for the browser and node.js
Pros of Axios
- Supports both browser and Node.js environments
- Provides automatic request and response transformations
- Offers built-in CSRF protection and request cancellation
Cons of Axios
- Larger bundle size compared to Supertest
- More complex setup for simple API testing scenarios
- Lacks some specific testing-focused features present in Supertest
Code Comparison
Axios:
const axios = require('axios');
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Supertest:
const request = require('supertest');
const express = require('express');
const app = express();
request(app)
.get('/user')
.query({ ID: 12345 })
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
Summary
Axios is a versatile HTTP client for both browser and Node.js, offering features like request/response transformations and CSRF protection. It's well-suited for general-purpose API interactions. Supertest, on the other hand, is specifically designed for testing HTTP servers, providing a more streamlined API for asserting HTTP responses in test environments. While Axios offers broader functionality, Supertest excels in simplicity for API testing scenarios.
🏊🏾 Simplified HTTP request client.
Pros of Request
- More versatile and can be used for various HTTP requests beyond testing
- Supports a wider range of HTTP methods and features
- Has a larger ecosystem of plugins and extensions
Cons of Request
- Requires more setup and configuration for testing purposes
- Less focused on testing-specific features
- Deprecated and no longer actively maintained
Code Comparison
Request:
const request = require('request');
request('http://www.example.com', (error, response, body) => {
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
});
Supertest:
const request = require('supertest');
const express = require('express');
const app = express();
request(app)
.get('/')
.expect(200)
.end((err, res) => {
if (err) throw err;
});
Summary
While Request is more versatile for general HTTP requests, Supertest is specifically designed for testing HTTP servers. Supertest provides a more streamlined and testing-focused API, making it easier to write and maintain tests for Express applications. Request, on the other hand, offers more flexibility for various HTTP-related tasks but requires more setup for testing scenarios. It's worth noting that Request is deprecated, which may impact its long-term viability for new projects.
🌐 Human-friendly and powerful HTTP request library for Node.js
Pros of Got
- More feature-rich HTTP client with support for various protocols (HTTP, HTTPS, HTTP2)
- Built-in request retrying and pagination support
- Extensive documentation and active community support
Cons of Got
- Steeper learning curve due to more advanced features
- Larger package size compared to SuperTest
- May be overkill for simple API testing scenarios
Code Comparison
SuperTest:
const request = require('supertest');
const app = require('../app');
request(app)
.get('/users')
.expect(200)
.end((err, res) => {
if (err) throw err;
});
Got:
const got = require('got');
(async () => {
try {
const response = await got('http://example.com/users');
console.log(response.body);
} catch (error) {
console.error(error);
}
})();
Summary
SuperTest is specifically designed for testing HTTP servers and is often used in conjunction with testing frameworks like Mocha. It provides a simple and intuitive API for making assertions about HTTP responses.
Got, on the other hand, is a more general-purpose HTTP client with a wider range of features. It's suitable for both testing and production use cases, offering advanced functionality like request retrying, pagination, and support for various protocols.
Choose SuperTest for straightforward API testing in Node.js applications, especially when working with Express.js. Opt for Got when you need a more powerful HTTP client with additional features and flexibility across different scenarios.
A light-weight module that brings the Fetch API to Node.js
Pros of node-fetch
- Lightweight and focused on HTTP requests, making it more versatile for various use cases
- Implements the Fetch API, providing a familiar interface for developers coming from browser-based JavaScript
- Supports both CommonJS and ES modules, offering flexibility in different Node.js environments
Cons of node-fetch
- Requires more setup and configuration for testing scenarios compared to SuperTest
- Lacks built-in assertion methods, necessitating additional libraries for test assertions
- May require more code to handle complex testing scenarios, especially for API testing
Code Comparison
node-fetch:
import fetch from 'node-fetch';
const response = await fetch('https://api.example.com/data');
const data = await response.json();
expect(response.status).toBe(200);
expect(data).toHaveProperty('id');
SuperTest:
const request = require('supertest');
const app = require('../app');
request(app)
.get('/api/data')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
expect(res.body).toHaveProperty('id');
});
Summary
node-fetch is a versatile HTTP client library that closely mimics the browser's Fetch API, making it suitable for various HTTP requests in Node.js. SuperTest, on the other hand, is specifically designed for testing HTTP servers, offering a more streamlined approach to API testing with built-in assertion methods. While node-fetch provides more flexibility, SuperTest excels in simplifying the process of writing and running API tests.
Newman is a command-line collection runner for Postman
Pros of Newman
- Supports running Postman collections, allowing for easy integration with existing Postman workflows
- Provides a command-line interface for automation and CI/CD integration
- Offers detailed reporting options, including JUnit XML and HTML formats
Cons of Newman
- Requires Postman collections, which may not be suitable for all testing scenarios
- Less flexible for custom JavaScript-based assertions compared to SuperTest
- Steeper learning curve for those unfamiliar with Postman's ecosystem
Code Comparison
SuperTest:
const request = require('supertest');
const app = require('../app');
request(app)
.get('/users')
.expect(200)
.end((err, res) => {
if (err) throw err;
});
Newman:
const newman = require('newman');
newman.run({
collection: require('./my-collection.json'),
environment: require('./my-environment.json'),
reporters: 'cli'
}, function (err) {
if (err) { throw err; }
});
Summary
SuperTest is more lightweight and integrates seamlessly with Node.js applications, making it ideal for unit and integration testing of Express-based APIs. Newman, on the other hand, leverages Postman collections for comprehensive API testing, offering robust reporting and CI/CD integration. The choice between the two depends on your existing workflow, testing requirements, and preference for JavaScript-based assertions versus Postman's GUI-driven approach.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
SuperTest
HTTP assertions made easy via superagent. Maintained for Forward Email and Lad.
About
The motivation with this module is to provide a high-level abstraction for testing HTTP, while still allowing you to drop down to the lower-level API provided by superagent.
Getting Started
Install SuperTest as an npm module and save it to your package.json file as a development dependency:
npm install supertest --save-dev
Once installed it can now be referenced by simply calling require('supertest');
Example
You may pass an http.Server
, or a Function
to request()
- if the server is not
already listening for connections then it is bound to an ephemeral port for you so
there is no need to keep track of ports.
SuperTest works with any test framework, here is an example without using any test framework at all:
const request = require('supertest');
const express = require('express');
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'john' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
To enable http2 protocol, simply append an options to request
or request.agent
:
const request = require('supertest');
const express = require('express');
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'john' });
});
request(app, { http2: true })
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
request.agent(app, { http2: true })
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
Here's an example with mocha, note how you can pass done
straight to any of the .expect()
calls:
describe('GET /user', function() {
it('responds with json', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
You can use auth
method to pass HTTP username and password in the same way as in the superagent:
describe('GET /user', function() {
it('responds with json', function(done) {
request(app)
.get('/user')
.auth('username', 'password')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
One thing to note with the above statement is that superagent now sends any HTTP
error (anything other than a 2XX response code) to the callback as the first argument if
you do not add a status code expect (i.e. .expect(302)
).
If you are using the .end()
method .expect()
assertions that fail will
not throw - they will return the assertion as an error to the .end()
callback. In
order to fail the test case, you will need to rethrow or pass err
to done()
, as follows:
describe('POST /users', function() {
it('responds with json', function(done) {
request(app)
.post('/users')
.send({name: 'john'})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if (err) return done(err);
return done();
});
});
});
You can also use promises:
describe('GET /users', function() {
it('responds with json', function() {
return request(app)
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.then(response => {
expect(response.body.email).toEqual('foo@bar.com');
})
});
});
Or async/await syntax:
describe('GET /users', function() {
it('responds with json', async function() {
const response = await request(app)
.get('/users')
.set('Accept', 'application/json')
expect(response.headers["Content-Type"]).toMatch(/json/);
expect(response.status).toEqual(200);
expect(response.body.email).toEqual('foo@bar.com');
});
});
Expectations are run in the order of definition. This characteristic can be used to modify the response body or headers before executing an assertion.
describe('POST /user', function() {
it('user.name should be an case-insensitive match for "john"', function(done) {
request(app)
.post('/user')
.send('name=john') // x-www-form-urlencoded upload
.set('Accept', 'application/json')
.expect(function(res) {
res.body.id = 'some fixed id';
res.body.name = res.body.name.toLowerCase();
})
.expect(200, {
id: 'some fixed id',
name: 'john'
}, done);
});
});
Anything you can do with superagent, you can do with supertest - for example multipart file uploads!
request(app)
.post('/')
.field('name', 'my awesome avatar')
.field('complex_object', '{"attribute": "value"}', {contentType: 'application/json'})
.attach('avatar', 'test/fixtures/avatar.jpg')
...
Passing the app or url each time is not necessary, if you're testing
the same host you may simply re-assign the request variable with the
initialization app or url, a new Test
is created per request.VERB()
call.
request = request('http://localhost:5555');
request.get('/').expect(200, function(err){
console.log(err);
});
request.get('/').expect('heya', function(err){
console.log(err);
});
Here's an example with mocha that shows how to persist a request and its cookies:
const request = require('supertest');
const should = require('should');
const express = require('express');
const cookieParser = require('cookie-parser');
describe('request.agent(app)', function() {
const app = express();
app.use(cookieParser());
app.get('/', function(req, res) {
res.cookie('cookie', 'hey');
res.send();
});
app.get('/return', function(req, res) {
if (req.cookies.cookie) res.send(req.cookies.cookie);
else res.send(':(')
});
const agent = request.agent(app);
it('should save cookies', function(done) {
agent
.get('/')
.expect('set-cookie', 'cookie=hey; Path=/', done);
});
it('should send cookies', function(done) {
agent
.get('/return')
.expect('hey', done);
});
});
There is another example that is introduced by the file agency.js
Here is an example where 2 cookies are set on the request.
agent(app)
.get('/api/content')
.set('Cookie', ['nameOne=valueOne;nameTwo=valueTwo'])
.send()
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.text).to.be.equal('hey');
return done();
});
API
You may use any superagent methods,
including .write()
, .pipe()
etc and perform assertions in the .end()
callback
for lower-level needs.
.expect(status[, fn])
Assert response status
code.
.expect(status, body[, fn])
Assert response status
code and body
.
.expect(body[, fn])
Assert response body
text with a string, regular expression, or
parsed body object.
.expect(field, value[, fn])
Assert header field
value
with a string or regular expression.
.expect(function(res) {})
Pass a custom assertion function. It'll be given the response object to check. If the check fails, throw an error.
request(app)
.get('/')
.expect(hasPreviousAndNextKeys)
.end(done);
function hasPreviousAndNextKeys(res) {
if (!('next' in res.body)) throw new Error("missing next key");
if (!('prev' in res.body)) throw new Error("missing prev key");
}
.end(fn)
Perform the request and invoke fn(err, res)
.
Notes
Inspired by api-easy minus vows coupling.
License
MIT
Top Related Projects
Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
Promise based HTTP client for the browser and node.js
🏊🏾 Simplified HTTP request client.
🌐 Human-friendly and powerful HTTP request library for Node.js
A light-weight module that brings the Fetch API to Node.js
Newman is a command-line collection runner for Postman
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot