diff --git a/README.md b/README.md index 2aae46f..4bd6309 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ Injects a fake request into an HTTP server. - `rawPayload` - the raw payload as a Buffer. - `trailers` - an object containing the response trailers. - `json` - a function that parses a json response payload and returns an object. + - `stream` - a function that provides a `Readable` stream of the response payload. - `cookies` - a getter that parses the `set-cookie` response header and returns an array with all the cookies and their metadata. Notes: diff --git a/lib/response.js b/lib/response.js index 430d9b8..4daacc0 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1,7 +1,7 @@ 'use strict' const http = require('node:http') -const { Writable } = require('node:stream') +const { Writable, Readable } = require('node:stream') const util = require('node:util') const setCookie = require('set-cookie-parser') @@ -143,6 +143,11 @@ function generatePayload (response) { return JSON.parse(res.payload) } + // Provide stream Readable for advanced user + res.stream = function streamPayload () { + return Readable.from(response._lightMyRequest.payloadChunks) + } + return res } diff --git a/test/index.test.js b/test/index.test.js index 3739971..54889d3 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1421,6 +1421,38 @@ test('Response.json() should throw an error if the payload is not of valid JSON }) }) +test('Response.stream() should provide a Readable stream', (t) => { + const lines = [ + JSON.stringify({ foo: 'bar' }), + JSON.stringify({ hello: 'world' }) + ] + + t.plan(2 + lines.length) + + const dispatch = function (req, res) { + res.writeHead(200, { 'Content-Type': 'multiple/json' }) + for (const line of lines) { + res.write(line) + } + res.end() + } + + inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { + t.error(err) + const readable = res.stream() + const payload = [] + t.equal(readable instanceof Readable, true) + readable.on('data', function (chunk) { + payload.push(chunk) + }) + readable.on('end', function () { + for (let i = 0; i < lines.length; i++) { + t.equal(lines[i], payload[i].toString()) + } + }) + }) +}) + test('promise api should auto start (fire and forget)', (t) => { t.plan(1) diff --git a/types/index.d.ts b/types/index.d.ts index f6cb849..273869b 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,5 @@ import * as http from 'http' +import { Readable } from 'stream' type HTTPMethods = 'DELETE' | 'delete' | 'GET' | 'get' | @@ -87,6 +88,7 @@ declare namespace inject { payload: string body: string json: () => T + stream: () => Readable cookies: Array } diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 4223a3c..581446a 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -1,6 +1,7 @@ import * as http from 'http' import { inject, isInjection, Response, DispatchFunc, InjectOptions, Chain } from '..' import { expectType, expectAssignable, expectNotAssignable } from 'tsd' +import { Readable } from 'stream' expectAssignable({ url: '/' }) expectAssignable({ autoStart: true }) @@ -26,8 +27,10 @@ const expectResponse = function (res: Response | undefined) { expectType(res) console.log(res.payload) expectAssignable(res.json) + expectAssignable(res.stream) expectAssignable(res.raw.res) expectAssignable(res.raw.req) + expectType(res.stream()) expectType(res.payload) expectType(res.body) expectAssignable>(res.cookies)