forwardemail / forwardemail/supertest

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

Open
#672 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
14.4k
Forks
782
PR merge metrics
No merged PRs in 30d

Description

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 `await`s 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"
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.