Supercharge supertest with a promise interface
JavaScript
Latest commit ab56510 Dec 29, 2016 @benesch benesch deprecate project!
SuperTest 2.0 supports proomises natively. Use that instead!
Fix #44.

README.md

Promises/A+ logo

supertest-as-promised

Build Status

This project is deprecated! As of v2.0.0, SuperTest has native support for promises. Don't use SuperTest as Promised in new projects; use SuperTest directly!

If you're currently using SuperTest as Promised, here's how to switch to native SuperTest:

  • SuperTest returns only ES6 promises. SuperTest as Promised, by contrast, returns Bluebird promises by default, or promise objects from a library of your choosing using BYOP support. Every promise library worth its salt supports ES6 promise interop, though, so it should be a small matter to cast ES6 promises to your custom promise library's promises. Here's a simple SuperTest as Promised snippet that relies on the .delay method of Bluebird promises

    var request = require("supertest-as-promised");
    
    request(app)
      .get("/kittens")
      .expect(201)
      .toPromise()
      .delay(10)
      .then(function (res) { /* ... */ })

    that can be trivially converted to use SuperTest 2.0 like so:

    var request = require("supertest");
    var BluebirdPromise = require("bluebird");
    
    BluebirdPromise.resolve(
      request(app)
        .get("/kittens")
        .expect(201))
      .delay(10)
      .then(function (res) { /* ... */ })
  • SuperTest does not ship a .toPromise method. You'll need to remove calls to this method. You were probably using .toPromise because you wanted a proper Promise object. YourPromiseLibrary.resolve(...) will probably do the trick; see the example above.

SuperTest as Promised will continue to receive bugfixes, but no new features. Cheers, folks! It's been a good two years.

Overview

SuperTest as Promised supercharges SuperTest with a then method.

Instead of layering callbacks on callbacks in your tests:

request(app)
  .get("/user")
  .expect(200, function (err, res) {
    if (err) return done(err);

    var userId = res.body.id;
    request(app)
      .post("/kittens")
      .send({ userId: userId, ... })
      .expect(201, function (err, res) {
        if (err) return done(err);

        // ...
      });
  });

chain your requests like you were promised:

return request(app)
  .get("/user")
  .expect(200)
  .then(function (res) {
    return request(app)
      .post("/kittens")
      .send({ userId: res})
      .expect(201);
  })
  .then(function (res) {
    // ...
  });

Usage

SuperTest as Promised operates just like normal SuperTest, except that the object returned by .get, .post, etc. is a proper thenable:

var express = require("express")
  , request = require("supertest-as-promised");

var app = express();

request(app)
  .get("/kittens")
  .expect(200)
  .then(function (res) {
    // ...
  });

If you use a promise-friendly test runner, you can just return your request chain from the test case rather than messing with a callback:

describe("GET /kittens", function () {
  it("should work", function () {
    return request(app).get("/kittens").expect(200);
  });
});

Upstream documentation

SuperTest as Promised is built on top of SuperTest, which is in turn built on top of SuperAgent. You'll want to be familiar with both of those packages' APIs.

Here's the quick rundown if you're unfamiliar. SuperAgent is a generic HTTP client that provides methods for fluently constructing HTTP requests (e.g., .get, .send, .query, .auth). See the SuperAgent docs for a full list of methods. SuperTest allows you to tack on assertions about e.g. response status (.expect(200)) or content (.expect(/^kitties are \w+$/)) to a SuperAgent request. See the .expect function API in the SuperTest documentation for details.

Agents

If you use a SuperTest agent to persist cookies, those are thenable too:

var agent = require("supertest-as-promised").agent(app);

agent
  .get("/ugly-kitteh")
  .expect(404)
  .then(function () {
    // ...
  })

Promisey goodness

To start, only the then and catch methods are exposed. But once you've called .then or .catch once, you've got a proper Bluebird promise that supports the whole gamut of promisey goodness:

request(app)
  .get("/kittens")
  .expect(201)
  .then(function (res) { /* ... */ })
  // I'm a real promise now!
  .catch(function (err) { /* ... */ })

See the Bluebird API for everything that's available.

You may find it cleaner to cast directly to a promise using the toPromise method:

request(app)
  .get("/kittens")
  .expect(201)
  .toPromise()
  // I'm a real promise now!
  .delay(10)
  .then(function (res) { /* ... */ })

BYOP: Bring your own Promise

You can supply own promise library so that the promises returned have your convenience methods of choice.

Simply call the SuperTest as Promised module with a ES6-compliant Promise constructor, and you'll get back a new module configured to return your custom promises. To swap in when.js, for example:

var when = require("when")
  , request;

request = require("supertest-as-promised")(when.Promise);
request(app)
  .get("/when.js")
  .then(function (res) { /* ... */ })
  // I'm a when.js promise! (instanceof when.Promise == true)
  .frobulate()

request = require("supertest-as-promised");
request(app)
  .get("/bluebird.js")
  .then(function (res) { /* .. */ })
  // I'm back to the default Bluebird promise!

Debugging

Suppose your snazzy test

it("should get kittens", function () {
  return request(app).get("/kittens").expect(200)
    .then(function (res) {
      return expect(res.body).to.equal("kittens r cute!");
    });
});

suddenly starts failing with a "400 Bad Request" error. It'd sure be handy if you could print out the response body to see if the server mentioned what, in particular, was bad about your test. Chain on a .catch and inspect err.response:

it("should get kittens", function () {
  return request(app).get("/kittens").expect(200)
    .then(function (res) {
      return expect(res.text).to.equal("kittens r cute!");
    })
    .catch(function (err) {
      console.log(err.response.text); // "You have viewed too many kittens today."
    });
});

Installation

Node

$ npm install supertest supertest-as-promised

SuperTest as Promised lists supertest as a peer dependency, so it'll wrap whatever version of SuperTest you've asked for in your own package.json.

In earlier versions of NPM, failing to list SuperTest as a dependency would get you the latest version. In NPM 3, failing to list SuperTest as a dependency will generate a warning and SuperTest will not be installed.

Do note that SuperTest as Promised is a well-behaved citizen and doesn't monkey-patch SuperTest directly:

// I return thenables!
var request = require("supertest-as-promised");

// I'm lame and force you to use callbacks
var request = require("supertest");

Versions

We follow semver: the major version number will be upgraded with any breaking change. Breaking changes in each major version are listed below. Consult the changelog for a list of meaningful new features in each version; consult the commit log for a complete list.

Breaking changes in 4.0

  • In .catch handlers, err.response is now marked as non-enumerable.

Breaking changes in 3.0

  • Bluebird has been upgraded to version 3.3.1.

Breaking changes in 2.0

  • Bluebird has been upgraded to version 2.9.24.