Skip to content

Commit e82bdd4

Browse files
committed
test: add test for res.destroyed handler
I had to use node's `http` module for this because I could not get `supertest`s `abort` method to work properly. With the raw `http` module I was able to use `req.destroy()` to cancel the request early. We now see the error from a premature closure, but are still able to make extra requests afterwards
1 parent 3fb6771 commit e82bdd4

3 files changed

Lines changed: 55 additions & 0 deletions

File tree

integration/send-files/e2e/express.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
import { Test } from '@nestjs/testing';
66
import { expect } from 'chai';
77
import { readFileSync } from 'fs';
8+
import * as http from 'http';
89
import { join } from 'path';
910
import * as request from 'supertest';
1011
import { AppModule } from '../src/app.module';
@@ -68,4 +69,44 @@ describe('Express FileSend', () => {
6869
it('should return an error if the file does not exist', async () => {
6970
return request(app.getHttpServer()).get('/file/not/exist').expect(400);
7071
});
72+
it('should allow for the client to end the response and be able to make another', async () => {
73+
await app.listen(0);
74+
const url = await app.getUrl();
75+
const [protocol, host, port] = url.replace('[::1]', 'localhost').split(':');
76+
const httpOptions = {
77+
host: host.replace('//', ''),
78+
protocol: `${protocol}:`,
79+
port,
80+
path: '/file/slow',
81+
method: 'GET',
82+
};
83+
await new Promise<void>(resolve => {
84+
const req = http.request(httpOptions, res => {
85+
res.on('data', () => {
86+
req.destroy();
87+
});
88+
/* no op */
89+
res.on('close', resolve);
90+
});
91+
req.end();
92+
});
93+
await new Promise<void>((resolve, reject) => {
94+
const req = http.request(
95+
{ ...httpOptions, path: '/file/stream' },
96+
res => {
97+
res.on('data', chunk => {
98+
/* no op */
99+
});
100+
res.on('error', err => {
101+
reject(err);
102+
});
103+
res.on('end', () => {
104+
expect(res.statusCode).to.be.eq(200);
105+
resolve();
106+
});
107+
},
108+
);
109+
req.end();
110+
});
111+
}).timeout(5000);
71112
});

integration/send-files/src/app.controller.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ export class AppController {
3636
getNonExistantFile(): StreamableFile {
3737
return this.appService.getFileThatDoesNotExist();
3838
}
39+
40+
@Get('/file/slow')
41+
getSlowFile(): StreamableFile {
42+
return this.appService.getSlowStream();
43+
}
3944
}

integration/send-files/src/app.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Injectable, StreamableFile } from '@nestjs/common';
2+
import { randomBytes } from 'crypto';
23
import { createReadStream, readFileSync } from 'fs';
34
import { join } from 'path';
45
import { Observable, of } from 'rxjs';
6+
import { Readable } from 'stream';
57
import { NonFile } from './non-file';
68

79
@Injectable()
@@ -39,4 +41,11 @@ export class AppService {
3941
getFileThatDoesNotExist(): StreamableFile {
4042
return new StreamableFile(createReadStream('does-not-exist.txt'));
4143
}
44+
45+
getSlowStream(): StreamableFile {
46+
const stream = new Readable();
47+
stream.push(Buffer.from(randomBytes(Math.pow(2, 31) - 1)));
48+
stream._read = () => {};
49+
return new StreamableFile(stream);
50+
}
4251
}

0 commit comments

Comments
 (0)