Search code examples
javascriptnode.jsmocha.jskoasupertest

koa/supertest hangs on multiple post requests


As mentioned im trying to do multiple post requests on a koa server with supertest. As you can see in the code below. When the script is executed via

DEBUG=koa* mocha --harmony_destructuring --sort --require co-mocha --timeout 0 "test.js"

it just hangs when dispatching for the second post request. The second connection to the server is somehow kept open forever (see leaked-handles debug output). GET requests handle fine. I found out that it somehow works if I do either one of those:

  • do not send post data i.e disable ".send(data)" (which is not an option obviously)
  • remove "yield next" in the post route (I don't want that)
  • introduce a middleware after the routes are attached that does not yield (see "<--- HERE" in the code)

I would really like to understand why that is and what I am doing wrong here, since i think introducing that whacky do-not-yield-middleware-workaround is just bad.

    'use strict';

    require('leaked-handles').set({
        fullStack: true,
        timeout: 5000,
        debugSockets: true
    });

    var http = require('http');
    var app = require('koa')();
    var router = require('koa-router');
    var body = require('koa-body')();
    var compose = require('koa-compose');

    var www = function () {
        var r = router();
        r.get('/test', function * (next) {
            this.body = 200;
            yield next;
        });
        r.post('/test', body, function * (next) {
            console.log(this.request.body);
            this.body = {status: 200};
            yield next;
        });

        app.use(compose([
            r.routes(),
            r.allowedMethods()
        ]));

        // app.use(function * last (next) {/* do not yield */}); // <----

        var server = http.createServer(app.callback());
        return server;
    };


    var supertest = require('supertest');
    var expect = require('chai').expect;

    describe('testing server', () => {

        var agent, server;
        var data = {test: 123};

        beforeEach(function () {
            server = www();
            agent = supertest(server.listen());
        });

        afterEach(function (done) {
            server.close(done);
        });

        describe('get', () => {
            it('returns ok', (done) => {
                agent.get('/test').expect(200, done);
            });
            it('returns ok', (done) => {
                agent.get('/test').expect(200, done);
            });
        });

        describe('post 1', () => {
            it('returns ok', (done) => {
                agent.post('/test')
                     .send(data)
                     .expect(200, done);
            });
        });

        describe('post 2', () => {
            it('returns ok', (done) => {
                agent.post('/test')
                     .send(data)
                     .expect(200, done);
            });
        });

    });

Solution

  • Ok, as mentioned in the comment above, i found out whats the problem. its basically this line:

        var app = require('koa')();
    

    koa itself has to be instantiated within the www function i.e.

        var koa = require('koa');
        ...
        var www = function () {
            var app = koa();
            ...
        }
        ...
    

    Although I'm still not sure what actually causes the behavior, this fixes it properly.