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
To stub a dependency (imported module) of a module under test you have to import it explicitly in your test and stub the desired method. For the stubbing to work, the stubbed method cannot be destructured, neither in the module under test nor in the test.
The sinon. stub() substitutes the real function and returns a stub object that you can configure using methods like callsFake() . Stubs also have a callCount property that tells you how many times the stub was called. For example, the below code stubs out axios.
In Sinon, a fake is a Function that records arguments, return value, the value of this and exception thrown (if any) for all of its calls. A fake is immutable: once created, the behavior will not change. Unlike sinon. spy and sinon. stub methods, the sinon.
What is a Stub? In testing land, a stub replaces real behavior with a fixed version. In the case of HTTP requests, instead of making the actual call, a stub fakes the call and provides a canned response that can be used to test against.
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:
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With