From 8c8f924ff9c6bedd0bf664209a17f6c52cd9d0e4 Mon Sep 17 00:00:00 2001 From: Brian Crowell Date: Sat, 15 May 2021 16:30:29 -0500 Subject: [PATCH] FIX: fetch-mock Response.body is not always a stream The WhatWG fetch spec requires that Body.body (and therefore Response.body) is always a readable stream, but it doesn't always happen that way in Node. This seems to be because ResponseBuilder tries to fetch the stream module from fetchMock, but it looks in the wrong place. Fixes wheresrhys/fetch-mock#609 --- src/lib/response-builder.js | 7 +++++-- test/server-specs/server-only.test.js | 22 ++++++++++++++++++++++ test/specs/config/constructors.test.js | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/lib/response-builder.js b/src/lib/response-builder.js index a274f526..cb53c91e 100644 --- a/src/lib/response-builder.js +++ b/src/lib/response-builder.js @@ -137,9 +137,12 @@ e.g. {"body": {"status: "registered"}}`); // On the server we need to manually construct the readable stream for the // Response object (on the client this done automatically) - if (this.Stream) { + if ( + this.fetchMock.Stream && + !(this.body instanceof this.fetchMock.Stream.Readable) + ) { this.debug('Creating response stream'); - const stream = new this.Stream.Readable(); + const stream = new this.fetchMock.Stream.Readable(); if (this.body != null) { //eslint-disable-line stream.push(this.body, 'utf-8'); } diff --git a/test/server-specs/server-only.test.js b/test/server-specs/server-only.test.js index a8822f2a..aa00066e 100644 --- a/test/server-specs/server-only.test.js +++ b/test/server-specs/server-only.test.js @@ -40,6 +40,28 @@ describe('nodejs only tests', () => { }); }); + it('always responds with a readable stream', (done) => { + const { Writable } = require('stream'); + const write = sinon.stub().callsFake((chunk, enc, cb) => { + cb(); + }); + const writable = new Writable({ + write, + }); + + fetchMock.mock(/a/, Buffer.from('response string', 'utf8'), { + sendAsJson: false, + }); + fetchMock.fetchHandler('http://a.com').then((res) => { + res.body.pipe(writable); + }); + + writable.on('finish', () => { + expect(write.args[0][0].toString('utf8')).to.equal('response string'); + done(); + }); + }); + // See https://github.com/wheresrhys/fetch-mock/issues/575 it('can respond with large bodies from the interweb', async () => { const fm = fetchMock.sandbox(); diff --git a/test/specs/config/constructors.test.js b/test/specs/config/constructors.test.js index 335d75a1..96de29fb 100644 --- a/test/specs/config/constructors.test.js +++ b/test/specs/config/constructors.test.js @@ -130,7 +130,7 @@ describe('custom implementations', () => { expect(res.isFake).to.be.true; expect(spiedReplacementResponse.callCount).to.equal(1); const lastCall = spiedReplacementResponse.lastCall.args; - expect(lastCall[0]).to.equal('hello'); + expect(lastCall[0]).to.have.property(Symbol.asyncIterator); expect(lastCall[1].status).to.equal(200); expect(defaultSpies.Response.callCount).to.equal(0); });