Skip to content

Commit

Permalink
feat(node-request): close connections after request
Browse files Browse the repository at this point in the history
This automatically closes server connections after making a request; so
that test runners (like mocha 4) aren't left hanging after the test
execution. If someone really needs to keep the server open,
`.keepOpen()` can be used.

Fixes #178

BREAKING CHANGE:

This change closes servers down after every request. If you want to use
the server for reasons at the same time as your test suite or for some
other reason you dont want the server to automatically be shut-down,
then you'll need to change any `chai.request` callsites to also use the
`keepOpen` comand, like so:

```js
chai.request(server).keepOpen()
```
  • Loading branch information
keithamus committed Oct 31, 2017
1 parent d3d9ec6 commit 3d7ab70
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 5 deletions.
18 changes: 18 additions & 0 deletions README.md
Expand Up @@ -61,6 +61,24 @@ chai.request(app)
.get('/')
```

When passing an `app` to `request`; it will automatically open the server for
incoming requests (by calling `listen()`) and, once a request has been made
the server will automatically shut down (by calling `.close()`). If you want to
keep the server open, perhaps if you're making multiple requests, you must call
`.keepOpen()` after `.request()`, and manually close the server down:

```js
var requester = chai.request(app).keepOpen()

Promise.all([
requester.get('/a'),
requester.get('/b'),
])
.then(responses => ....)
.then(() => requester.close())
```


#### URL

You may also use a base url as the foundation of your request.
Expand Down
38 changes: 34 additions & 4 deletions lib/request.js
Expand Up @@ -214,13 +214,31 @@ module.exports = function (app) {
: app
, obj = {};

var keepOpen = false
if (typeof server !== 'string' && server && server.listen && server.address) {
if (!server.address()) {
server = server.listen(0)
}
}
obj.keepOpen = function() {
keepOpen = true
return this
}
obj.close = function(callback) {
if (server && server.close && keepOpen === false) {
server.close(callback);
}
return this
}
methods.forEach(function (method) {
obj[method] = function (path) {
return new Test(server, method, path);
return new Test(server, method, path)
.on('end', function() {
obj.close();
});
};
});
obj.del = obj.delete;

return obj;
};

Expand Down Expand Up @@ -257,8 +275,7 @@ function serverAddress (app, path) {
}
var addr = app.address();
if (!addr) {
app.listen(0);
addr = app.address();
throw new Error('Server is not listening')
}
var protocol = (app instanceof https.Server) ? 'https' : 'http';
// If address is "unroutable" IPv4/6 address, then set to localhost
Expand Down Expand Up @@ -286,9 +303,22 @@ function TestAgent(app) {
if (typeof app === 'function') app = http.createServer(app);
(Agent || Request).call(this);
this.app = app;
if (typeof app !== 'string' && app && app.listen && app.address && !app.address()) {
this.app = app.listen(0)
}
}
util.inherits(TestAgent, Agent || Request);

TestAgent.prototype.close = function close(callback) {
if (this.app && this.app.close) {
this.app.close(callback)
}
return this
}
TestAgent.prototype.keepOpen = function keepOpen() {
return this
}

// override HTTP verb methods
methods.forEach(function(method){
TestAgent.prototype[method] = function(url){
Expand Down
35 changes: 34 additions & 1 deletion test/request.js
Expand Up @@ -123,9 +123,10 @@ describe('request', function () {
request(app).get('/')
.set('X-API-Key', 'testing')
.end(function (err, res) {
if (err) return done(err)
res.should.have.status(200);
res.text.should.equal('hello universe');
done(err);
done();
});
});

Expand Down Expand Up @@ -169,9 +170,41 @@ describe('request', function () {
})
.then(function (res) {
res.text.should.equal('your cookie: mycookie=test');
agent.close()
})
.then(done, done);
});

it('automatically closes the server down once done with it', function (done) {
var server = require('http').createServer(function (req, res) {
res.writeHeader(200, { 'content-type' : 'text/plain' });
res.end('hello world');
});

request(server)
.get('/')
.end(function (err, res) {
res.should.have.status(200);
res.text.should.equal('hello world');
should.not.exist(server.address())
done(err)
});
});

it('can use keepOpen() to not close the server', function (done) {
var server = require('http').createServer(function (req, res) {
res.writeHeader(200, { 'content-type' : 'text/plain' });
res.end('hello world');
});
var cachedRequest = request(server).keepOpen();
server.listen = function () { throw new Error('listen was called when it shouldnt have been') }
cachedRequest.get('/') .end(function (err, res) {
cachedRequest.get('/').end(function (err2, res) {
server.close(function () { done(err || err2) })
})
});
});

});

isBrowser && describe('Browser', function () {
Expand Down

0 comments on commit 3d7ab70

Please sign in to comment.