Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ladjs/supertest
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.2.4
Choose a base ref
...
head repository: ladjs/supertest
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.3.0
Choose a head ref

Commits on Mar 29, 2022

  1. Copy the full SHA
    b24da85 View commit details
  2. Copy the full SHA
    3dba4e9 View commit details

Commits on Apr 22, 2022

  1. Copy the full SHA
    5862fe6 View commit details

Commits on Sep 20, 2022

  1. Copy the full SHA
    6d9b9cb View commit details
  2. feat(TestAgent): decoupled TestAgent and superagent's Agent to suppor…

    …t more than `ca`, `key`, `cert`
    
    `options` object is now a direct passthrough, TestAgent can support whichever superagent's Agent is expecting
    i.e. `ca`, `key`, `cert`, `pfx`, `rejectUnauthorized`
    lamweili committed Sep 20, 2022
    Copy the full SHA
    5e23869 View commit details
  3. refactor(TestAgent): removed the host param when creating Test object

    `Test` constructor has already removed the host param in de056d2
    lamweili committed Sep 20, 2022
    Copy the full SHA
    1c8930d View commit details

Commits on Oct 3, 2022

  1. test: 100% test coverage

    lamweili committed Oct 3, 2022
    Copy the full SHA
    8bf4c14 View commit details
  2. Copy the full SHA
    c1c4402 View commit details
  3. Copy the full SHA
    8847310 View commit details
  4. ci: added ci

    lamweili committed Oct 3, 2022
    Copy the full SHA
    da1e842 View commit details
  5. Merge pull request #792 from lamweili/refactor/test

    test: 100% coverage
    titanism authored Oct 3, 2022
    2
    Copy the full SHA
    b8c2e29 View commit details
  6. Merge pull request #774 from jmccure/update-promise-example-readme

    Update promise example to work with Mocha 3.0.0 and newer
    titanism authored Oct 3, 2022
    Copy the full SHA
    ba4b43b View commit details
  7. Merge pull request #767 from alexandre-abrioux/expect-stacktrace

    fix: add stacktrace to failed expect function call
    titanism authored Oct 3, 2022
    Copy the full SHA
    e064b5a View commit details
  8. feat: supports http2

    lamweili committed Oct 3, 2022
    Copy the full SHA
    da57804 View commit details
  9. Copy the full SHA
    46e6feb View commit details
  10. Copy the full SHA
    9c5bd92 View commit details

Commits on Oct 4, 2022

  1. Merge pull request #794 from lamweili/migrate-cov

    ci: migrated code coverage from coveralls to codecov
    titanism authored Oct 4, 2022
    Copy the full SHA
    fa129dc View commit details
  2. Merge pull request #795 from lamweili/code-coverage

    test(#767): 100% code coverage
    titanism authored Oct 4, 2022
    Copy the full SHA
    a225e95 View commit details
  3. Merge pull request #793 from lamweili/feat/http2

    feat: supports http2
    titanism authored Oct 4, 2022
    Copy the full SHA
    22b89b6 View commit details
  4. Copy the full SHA
    20adbc1 View commit details
  5. 6.3.0

    titanism committed Oct 4, 2022
    Copy the full SHA
    6a95043 View commit details
Showing with 328 additions and 69 deletions.
  1. +42 −0 .github/workflows/node.js.yml
  2. +35 −6 README.md
  3. +22 −0 ci/remove-deps-4-old-node.js
  4. +22 −3 index.js
  5. +28 −12 lib/agent.js
  6. +7 −2 lib/test.js
  7. +32 −30 package.json
  8. +130 −16 test/supertest.js
  9. +10 −0 test/throwError.js
42 changes: 42 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
include:
- node-version: 10.x
test-on-old-node: 1
- node-version: 12.x
test-on-old-node: 1
- node-version: 14.x
- node-version: 16.x
- node-version: 18.x

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install Dependencies On Old Node ${{ matrix.node-version }}
if: ${{ matrix.test-on-old-node == '1' }}
run: node ci/remove-deps-4-old-node.js && yarn install --ignore-scripts
- name: Install Dependencies On Node ${{ matrix.node-version }}
if: ${{ matrix.test-on-old-node != '1' }}
run: yarn install
- run: npm test
- name: Coverage On Node ${{ matrix.node-version }}
run:
npm run coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
41 changes: 35 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SuperTest

[![Coveralls][coverage-badge]][coverage]
[![code coverage][coverage-badge]][coverage]
[![Build Status][travis-badge]][travis]
[![Dependencies][dependencies-badge]][dependencies]
[![PRs Welcome][prs-badge]][prs]
@@ -53,6 +53,37 @@ request(app)
});
```

To enable http2 protocol, simply append an options to `request` or `request.agent`:

```js
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:

```js
@@ -111,17 +142,15 @@ You can also use promises:

```js
describe('GET /users', function() {
it('responds with json', function(done) {
it('responds with json', function() {
return request(app)
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.then(response => {
assert(response.body.email, 'foo@bar.com')
done();
})
.catch(err => done(err))
});
});
```
@@ -298,8 +327,8 @@ Inspired by [api-easy](https://github.com/flatiron/api-easy) minus vows coupling

MIT

[coverage-badge]: https://coveralls.io/repos/github/visionmedia/supertest/badge.svg?branch=master
[coverage]: https://coveralls.io/github/visionmedia/supertest?branch=master
[coverage-badge]: https://img.shields.io/codecov/c/github/visionmedia/supertest.svg
[coverage]: https://codecov.io/gh/visionmedia/supertest
[travis-badge]: https://travis-ci.org/visionmedia/supertest.svg?branch=master
[travis]: https://travis-ci.org/visionmedia/supertest
[dependencies-badge]: https://david-dm.org/visionmedia/supertest/status.svg
22 changes: 22 additions & 0 deletions ci/remove-deps-4-old-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const fs = require('fs');
const path = require('path');
const package = require('../package.json');

const UNSUPPORT_DEPS_4_OLD = {
'eslint': undefined,
'mocha': '6.x'
};

const deps = Object.keys(UNSUPPORT_DEPS_4_OLD);
for (const item in package.devDependencies) {
if (deps.includes(item)) {
package.devDependencies[item] = UNSUPPORT_DEPS_4_OLD[item];
}
}

delete package.scripts.lint;

fs.writeFileSync(
path.join(__dirname, '../package.json'),
JSON.stringify(package, null, 2)
);
25 changes: 22 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,12 @@
*/
const methods = require('methods');
const http = require('http');
let http2;
try {
http2 = require('http2'); // eslint-disable-line global-require
} catch (_) {
// eslint-disable-line no-empty
}
const Test = require('./lib/test.js');
const agent = require('./lib/agent.js');

@@ -16,16 +22,29 @@ const agent = require('./lib/agent.js');
* @return {Test}
* @api public
*/
module.exports = function(app) {
module.exports = function(app, options = {}) {
const obj = {};

if (typeof app === 'function') {
app = http.createServer(app); // eslint-disable-line no-param-reassign
if (options.http2) {
if (!http2) {
throw new Error(
'supertest: this version of Node.js does not support http2'
);
}
app = http2.createServer(app); // eslint-disable-line no-param-reassign
} else {
app = http.createServer(app); // eslint-disable-line no-param-reassign
}
}

methods.forEach(function(method) {
obj[method] = function(url) {
return new Test(app, method, url);
var test = new Test(app, method, url);
if (options.http2) {
test.http2();
}
return test;
};
});

40 changes: 28 additions & 12 deletions lib/agent.js
Original file line number Diff line number Diff line change
@@ -7,6 +7,12 @@
const { agent: Agent } = require('superagent');
const methods = require('methods');
const http = require('http');
let http2;
try {
http2 = require('http2'); // eslint-disable-line global-require
} catch (_) {
// eslint-disable-line no-empty
}
const Test = require('./test.js');

/**
@@ -17,15 +23,24 @@ const Test = require('./test.js');
* @api public
*/

function TestAgent(app, options) {
function TestAgent(app, options = {}) {
if (!(this instanceof TestAgent)) return new TestAgent(app, options);
if (typeof app === 'function') app = http.createServer(app); // eslint-disable-line no-param-reassign
if (options) {
this._ca = options.ca;
this._key = options.key;
this._cert = options.cert;

Agent.call(this, options);
this._options = options;

if (typeof app === 'function') {
if (options.http2) {
if (!http2) {
throw new Error(
'supertest: this version of Node.js does not support http2'
);
}
app = http2.createServer(app); // eslint-disable-line no-param-reassign
} else {
app = http.createServer(app); // eslint-disable-line no-param-reassign
}
}
Agent.call(this);
this.app = app;
}

@@ -44,19 +59,20 @@ TestAgent.prototype.host = function(host) {
// override HTTP verb methods
methods.forEach(function(method) {
TestAgent.prototype[method] = function(url, fn) { // eslint-disable-line no-unused-vars
const req = new Test(this.app, method.toUpperCase(), url, this._host);
req.ca(this._ca);
req.cert(this._cert);
req.key(this._key);
const req = new Test(this.app, method.toUpperCase(), url);
if (this._options.http2) {
req.http2();
}

if (this._host) {
req.set('host', this._host);
}

req.on('response', this._saveCookies.bind(this));
req.on('redirect', this._saveCookies.bind(this));
req.on('redirect', this._attachCookies.bind(this, req));
this._attachCookies(req);
this._setDefaults(req);
this._attachCookies(req);

return req;
};
9 changes: 7 additions & 2 deletions lib/test.js
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@

const { inspect } = require('util');
const { STATUS_CODES } = require('http');
const { Server } = require('https');
const { Server } = require('tls');
const { deepStrictEqual } = require('assert');
const { Request } = require('superagent');

@@ -303,7 +303,12 @@ function wrapAssertFn(assertFn) {

return function(res) {
let badStack;
const err = assertFn(res);
let err;
try {
err = assertFn(res);
} catch (e) {
err = e;
}
if (err instanceof Error && err.stack) {
badStack = err.stack.replace(err.message, '').split('\n').slice(1);
err.stack = [err.toString()]
62 changes: 32 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
{
"name": "supertest",
"version": "6.2.4",
"description": "SuperAgent driven library for testing HTTP servers",
"main": "index.js",
"version": "6.3.0",
"author": "TJ Holowaychuk",
"contributors": [
"Dimitri DO BAIRRO <dimitri.dobairro@dimsolution.com>"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/supertest.git"
},
"engines": {
"node": ">=6.4.0"
},
"keywords": [
"superagent",
"request",
"tdd",
"bdd",
"http",
"test",
"testing"
],
"scripts": {
"lint": "eslint lib/**/*.js test/**/*.js index.js",
"lint:fix": "eslint --fix lib/**/*.js test/**/*.js index.js",
"pretest": "npm run lint",
"test": "nyc --reporter=html --reporter=text mocha --exit --require should --reporter spec --check-leaks",
"coverage": "nyc report --reporter=text-lcov | coveralls"
},
"contributors": [],
"dependencies": {
"methods": "^1.1.2",
"superagent": "^8.0.0"
},
"devDependencies": {
"body-parser": "^1.20.0",
"cookie-parser": "^1.4.6",
"coveralls": "^3.1.1",
"eslint": "^8.18.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.26.0",
"express": "^4.18.1",
"mocha": "^10.0.0",
"nock": "^13.2.8",
"nyc": "^15.1.0",
"proxyquire": "^2.1.3",
"should": "^13.2.3"
},
"engines": {
"node": ">=6.4.0"
},
"files": [
"index.js",
"lib"
],
"keywords": [
"bdd",
"http",
"request",
"superagent",
"tdd",
"test",
"testing"
],
"license": "MIT",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/supertest.git"
},
"scripts": {
"coverage": "nyc report --reporter=text-lcov > coverage.lcov",
"lint": "eslint lib/**/*.js test/**/*.js index.js",
"lint:fix": "eslint --fix lib/**/*.js test/**/*.js index.js",
"pretest": "npm run lint --if-present",
"test": "nyc --reporter=html --reporter=text mocha --exit --require should --reporter spec --check-leaks"
}
}
146 changes: 130 additions & 16 deletions test/supertest.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
'use strict';

const https = require('https');
let http2;
try {
http2 = require('http2'); // eslint-disable-line global-require
} catch (_) {
// eslint-disable-line no-empty
}
const fs = require('fs');
const path = require('path');
const should = require('should');
@@ -9,6 +15,7 @@ const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const nock = require('nock');
const request = require('../index.js');
const throwError = require('./throwError');

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

@@ -20,14 +27,14 @@ function shouldIncludeStackWithThisFile(err) {
describe('request(url)', function () {
it('should be supported', function (done) {
const app = express();
let s;
let server;

app.get('/', function (req, res) {
res.send('hello');
});

s = app.listen(function () {
const url = 'http://localhost:' + s.address().port;
server = app.listen(function () {
const url = 'http://localhost:' + server.address().port;
request(url)
.get('/')
.expect('hello', done);
@@ -37,14 +44,14 @@ describe('request(url)', function () {
describe('.end(cb)', function () {
it('should set `this` to the test object when calling cb', function (done) {
const app = express();
let s;
let server;

app.get('/', function (req, res) {
res.send('hello');
});

s = app.listen(function () {
const url = 'http://localhost:' + s.address().port;
server = app.listen(function () {
const url = 'http://localhost:' + server.address().port;
const test = request(url).get('/');
test.end(function (err, res) {
this.should.eql(test);
@@ -80,7 +87,7 @@ describe('request(app)', function () {
res.send('hey');
});

server = app.listen(4000, function () {
server = app.listen(function () {
request(server)
.get('/')
.end(function (err, res) {
@@ -93,13 +100,15 @@ describe('request(app)', function () {

it('should work with remote server', function (done) {
const app = express();
let server;

app.get('/', function (req, res) {
res.send('hey');
});

app.listen(4001, function () {
request('http://localhost:4001')
server = app.listen(function () {
const url = 'http://localhost:' + server.address().port;
request(url)
.get('/')
.end(function (err, res) {
res.status.should.equal(200);
@@ -748,16 +757,33 @@ describe('request(app)', function () {

it('reports errors', function (done) {
get
.expect(function (res) {
throw new Error('failed');
})
.expect(throwError('failed'))
.end(function (err) {
err.message.should.equal('failed');
shouldIncludeStackWithThisFile(err);
done();
});
});

// this scenario should never happen after https://github.com/visionmedia/supertest/pull/767
// meant for test coverage for lib/test.js#287
// https://github.com/visionmedia/supertest/blob/e064b5ae71e1dfa3e1a74745fda527ac542e1878/lib/test.js#L287
it('_assertFunction should catch and return error', function (done) {
const error = new Error('failed');
const returnedError = get
// private api
._assertFunction(function (res) {
throw error;
});
get
.end(function () {
returnedError.should.equal(error);
returnedError.message.should.equal('failed');
shouldIncludeStackWithThisFile(returnedError);
done();
});
});

it(
'ensures truthy non-errors returned from asserts are not promoted to errors',
function (done) {
@@ -774,9 +800,7 @@ describe('request(app)', function () {

it('ensures truthy errors returned from asserts are throw to end', function (done) {
get
.expect(function (res) {
return new Error('some descriptive error');
})
.expect(throwError('some descriptive error'))
.end(function (err) {
err.message.should.equal('some descriptive error');
shouldIncludeStackWithThisFile(err);
@@ -1269,7 +1293,7 @@ describe('request.get(url).query(vals) works as expected', function () {
});
});

it('handles unknown errors', function (done) {
it('handles unknown errors (err without res)', function (done) {
const app = express();

nock.disableNetConnect();
@@ -1285,6 +1309,8 @@ describe('request.get(url).query(vals) works as expected', function () {
// https://github.com/visionmedia/supertest/issues/352
.expect(200)
.end(function (err, res) {
should.exist(err);
should.not.exist(res);
err.should.be.an.instanceof(Error);
err.message.should.match(/Nock: Disallowed net connect/);
shouldIncludeStackWithThisFile(err);
@@ -1294,6 +1320,35 @@ describe('request.get(url).query(vals) works as expected', function () {
nock.restore();
});

// this scenario should never happen
// there shouldn't be any res if there is an err
// meant for test coverage for lib/test.js#169
// https://github.com/visionmedia/supertest/blob/5543d674cf9aa4547927ba6010d31d9474950dec/lib/test.js#L169
it('handles unknown errors (err with res)', function (done) {
const app = express();

app.get('/', function (req, res) {
res.status(200).send('OK');
});

const resError = new Error();
resError.status = 400;

const serverRes = { status: 200 };

request(app)
.get('/')
// private api
.assert(resError, serverRes, function (err, res) {
should.exist(err);
should.exist(res);
err.should.equal(resError);
res.should.equal(serverRes);
// close the server explicitly (as we are not using expect/end/then)
this.end(done);
});
});

it('should assert using promises', function (done) {
const app = express();

@@ -1310,3 +1365,62 @@ describe('request.get(url).query(vals) works as expected', function () {
});
});
});

const describeHttp2 = (http2) ? describe : describe.skip;
describeHttp2('http2', function() {
// eslint-disable-next-line global-require
const proxyquire = require('proxyquire');

const tests = [
{
title: 'request(app)',
api: request,
mockApi: proxyquire('../index.js', { http2: null })
},
{
title: 'request.agent(app)',
api: request.agent,
mockApi: proxyquire('../lib/agent.js', { http2: null })
}
];

tests.forEach(({ title, api, mockApi }) => {
describe(title, function () {
const app = function(req, res) {
res.end('hey');
};

it('should fire up the app on an ephemeral port', function (done) {
api(app, { http2: true })
.get('/')
.end(function (err, res) {
res.status.should.equal(200);
res.text.should.equal('hey');
done();
});
});

it('should work with an active server', function (done) {
const server = http2.createServer(app);

server.listen(function () {
api(server)
.get('/')
.http2()
.end(function (err, res) {
res.status.should.equal(200);
res.text.should.equal('hey');
// close the external server explictly
server.close(done);
});
});
});

it('should throw error if http2 is not supported', function() {
(function() {
mockApi(app, { http2: true });
}).should.throw('supertest: this version of Node.js does not support http2');
});
});
});
});
10 changes: 10 additions & 0 deletions test/throwError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

/**
* This method needs to reside in its own module in order to properly test stack trace handling.
*/
module.exports = function throwError(message) {
return function() {
throw new Error(message);
};
};