supertest icon indicating copy to clipboard operation
supertest copied to clipboard

Request works with when I do server.listen() myself, but not when I pass Express app directly to supertest.

Open cakoose opened this issue 3 years ago • 0 comments

I have a server with a "/hang" endpoint. Requests will hang until the test calls the "release()" function to complete the request. My test initiates two requests to "/hang", then calls "release()" and awaits their completion.

My problem is that the await doesn't ever return. I noticed two changes I can make to cause it to return:

  1. Call expressApp.listen(...) myself instead of doing supertest.agent(expressApp). See the CALL_LISTEN_OURSELVES flag.
  2. Call release() on both requests before calling await. See the RELEASE_ALL_THEN_AWAIT flag.

I don't understand why those two things should make a difference.

const express = require('express');
const supertest = require('supertest');

async function mainAsync() {
    const expressApp = express();

    // Server definition.

    const resById = new Map();
    expressApp.get('/hang', (req, res) => {
        const id = req.query.id;
        if (id === undefined) {
            res.status(400).send('Missing "id" parameter.');
            return;
        }
        console.log(`server: GET /hang, id=${JSON.stringify(id)}`);
        req.on('end', () => {
            console.log(`server: GET /hang, id=${JSON.stringify(id)}, 'end' event`);
        });
        resById.set(id, res);
    });

    const release = (id) => {
        const res = resById.get(id);
        if (res === undefined) {
            throw u.spawnError(`unknown id: ${JSON.stringify(id)}`);
        }
        res.status(200).send('released');
    };

    // Create supertest agent.

    let agent;
    const CALL_LISTEN_OURSELVES = false;
    if (CALL_LISTEN_OURSELVES) {
        let server;
        await new Promise(resolve => {
            server = expressApp.listen(0, resolve);
        });
        agent = supertest.agent(`http://127.0.0.1:${server.address().port}`);
    } else {
        agent = supertest.agent(expressApp);
    }

    // Start two "/hang" requests

    const requests = [];
    for (let i = 0; i < 2; i++) {
        const id = `${i}`;
        console.log(`client: GET /hang, id=${JSON.stringify(id)}`);
        requests.push(agent.get(`/hang?id=${i}`).then(r => r));  // The '.then' is to force the request to start.
    }

    // Wait until both "/hang" Response objects are in 'resById'...

    console.log(`client: waiting until resById.size === ${requests.length}`);
    while (resById.size !== requests.length) {
        await setTimeoutAsync(10);
    }
    console.log(`client: resById.size === ${requests.length}`);

    // Call release() to end the hanging requests.

    const RELEASE_ALL_THEN_AWAIT = false;
    if (RELEASE_ALL_THEN_AWAIT) {
        for (let i = 0; i < requests.length; i++) {
            const id = `${i}`;
            console.log(`client: release(${JSON.stringify(id)})`);
            release(id);
        }
        for (let i = 0; i < requests.length; i++) {
            const id = `${i}`;
            console.log(`client: awaiting ${JSON.stringify(id)}...`);
            const r = await requests[i];
            console.log(`client: got response: ${JSON.stringify(r.body)}`);
        }
    } else {
        for (let i = 0; i < requests.length; i++) {
            const id = `${i}`;
            console.log(`client: release(${JSON.stringify(id)})`);
            release(id);
            console.log(`client: awaiting ${JSON.stringify(id)}...`);
            const r = await requests[i];
            console.log(`client: got response: ${JSON.stringify(r.body)}`);
        }
    }

    console.log('client: done');
}

function setTimeoutAsync(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

if (require.main === module) {
    mainAsync().catch(err => console.log(err));
}

package.json

{
    "name": "supertest-hang-release",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "express": "4.17.1",
        "supertest": "4.0.2"
    }
}

cakoose avatar Sep 22 '20 10:09 cakoose