How to stub https.request response.pipe with sinon.js?

余生长醉 提交于 2020-12-03 18:01:57

问题


Let's say, that I have this simple code:

var https = require('https');
var options = {
  host: 'openshift.redhat.com',
  port: 443,
  path: '/broker/rest/api',
  method: 'GET'
};
var req = https.request(options, function(response) {
  console.log(response.statusCode);
  response.pipe(save stream to file with fs)
});
req.on('error', function(e) {
  console.error(e);
});
req.end();

Well, I'm bit new with sinon.js and I'd like to ask: How to stub response.pipe()? Of course, I can make stub for https.request and return somethin with .on and .end and thats easy, but I have no idea, how to test if response.pipe() was called with proper arguments... (nodejs documentation says that response is callback) Documentation is not helpful in this case! ofc testing env is mocha, and can use chai too Please give me some advices or examples. Thanks, Matt


回答1:


I wrapped your code into a function that accepts a callback because in current implementation we don't actually know when the piping is actually finished. So assuming we have a function like this:

const downloadToFile = function (options, callback) {
	let req = https.request(options, function (err, stream) {
		let writeStream = fs.createWriteStream('./output.json');
		stream.pipe(writeStream);

		//Notify that the content was successfully writtent into a file
		stream.on('end', () => callback(null));
		//Notify the caller that error happened.
		stream.on('error', err => callback(err));
	});

	req.end();
};

There are 3 problems to solve:

  1. As response is a readable stream. We want to mock the data it emits.
  2. We want to mock .pipe method check if we are piping to the right stream.
  3. We also need to mock https.request method not to make actual call

Here is how we can achieve this:

const {PassThrough} = require('stream');

describe('#downloadToFile', () => {
	it('should save the data to output.json', function (callback) {
		const mockResponse = `{"data": 123}`;
		//Using a built-in PassThrough stream to emit needed data.
		const mockStream = new PassThrough();
		mockStream.push(mockResponse);
		mockStream.end(); //Mark that we pushed all the data.

		//Patch the 'https' module not to make an actual call
		//but to return our stream instead
		sinon.stub(https, 'request', function (options, callback) {
			callback(null, mockStream);

			return {end: sinon.stub()}; //Stub end method btw
		});

		//Finally keep track of how 'pipe' is going to be called
		sinon.spy(mockStream, 'pipe');

		downloadToFile({url: 'http://google.com'}, (err) => {
			//Here you have the full control over what's happened
			sinon.assert.calledOnce(mockStream.pipe);
			//We can get the stream that we piped to.
			let writable = mockStream.pipe.getCall(0).args[0];
			assert.equal(writable.path, './output.json');

			//Tell mocha that the test is finished. Pass an error if any.
			callback(err);
		});
	});
});

Later you could make separate functions like: createMockedStream. Or even extract all these preparations into a separate method and keep only asserts in a test.




回答2:


From Sinon documentation, this has been removed from v3.0.0:

var stub = sinon.stub(object, "method", func);`

Instead you should use:

stub(obj, 'meth').callsFake(fn)


来源:https://stackoverflow.com/questions/42399877/how-to-stub-https-request-response-pipe-with-sinon-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!