How to test superagent promise - javascript

I have a function that I use for HTTP requests:
export default {
getRequest: (url, params) => {
return new Promise((resolve, reject) => {
superagent.get(url)
.query(params)
.set('Accept', 'application/json')
.end((err, response) => {
if (!response) {
reject(new Error('Something went wrong...'));
return;
}
const payload = response.body || response.text;
if (err) {
reject(payload || err);
return;
}
resolve(payload);
});
});
}
};
I want to test this function when Promise resolves or rejects.
My test looks like this:
import superagent from 'superagent';
import HTTPAsync from '../HTTPAsync';
describe('HTTPAsync. test', () => {
describe('getRequest test', () => {
const url = '/url';
const params = { param: 'value' };
const result = HTTPAsync.getRequest(url, params);
it('Should be promise', () => {
expect(result).toBeInstanceOf(Promise);
});
it('Should be pfromise', () => {
expect(result.resolve()).toBe('');
});
});
});
But I dont know how to resolve returned promise in happy scenario or error and check results of function

I made another type of test, and that helped me:
import superagent from 'superagent';
import HTTPAsync from '../HTTPAsync';
describe('HTTPAsync. test', () => {
describe('getRequest test', () => {
superagent.get = jest.fn(url => {
return superagent;
});
superagent.query = jest.fn(query => {
return superagent;
});
superagent.set = jest.fn(args => {
return superagent;
});
superagent.end = jest.fn(cb => cb(null, { text: 'zaebis voda' }));
const url = 'localhost:5000/url';
const params = { param: 'value' };
const result = HTTPAsync.getRequest(url, params);
it('Should be promise', () => {
expect(result).toBeInstanceOf(Promise);
// HERE I WILL CHECK EXPECTED VALUES
return result.then(data => console.log(data));
});
});
});

What you could do is catch you request on sucess or Error, using superagent like this :
const request = require('superagent');
describe('HTTPAsync. test', () => {
it('Should be pfromise', done => {
request
.get('/your_url')
.then(res => {
// res.body, res.headers, res.status
//your own logic
done();
})
.catch(err => {
// err.message, err.response
//your own logic
done();
});
});
});

Related

Try catch unit test (jest) in javascript

I have following script employeeJobTransferServiceLive.js:
const createJobTrasferSetPayloadOutput = async (jobTransferSetPayload) => {
const file = './output/jobTransferSetPayload.json';
try {
await fs.writeFile(file, JSON.stringify(jobTransferSetPayload, null, 4), { overwrite: false });
return JSON.stringify(jobTransferSetPayload);
} catch (err) {
return err;
}
};
so I created following unit test employeeJobTransferServiceLive.test.js:
const empJobTransferSrvc = require('../../../libs/employeeJobTransferSet/employeeJobTransferServiceLive');
jest.mock('fs', () => ({
promises: {
writeFile: jest.fn(),
},
}));
describe('sendWFDRequest is called', () => {
afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
});
it('Create and Write to the file', async () => {
const result = await empJobTransferSrvc.createJobTrasferSetPayloadOutput(jobTransferSetPayload);
expect(JSON.parse(result)[0]).toEqual(jobTransferSetPayload[0]);
expect(result).not.toBeNull();
});
});
The problem the compiler complain about test coverage for line return err; after catch.
I don't know how to create unit test to cover it.
Maybe it is not best answer, but at least it works fine for me
const fs = require('fs').promises;
const empJobTransferSrvc = require('../../../libs/employeeJobTransferSet/employeeJobTransferServiceLive');
jest.mock('fs', () => ({
promises: {
writeFile: jest.fn(),
},
}));
describe('sendWFDRequest is called', () => {
afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
});
it('Create and Write to the file', async () => {
const result = await empJobTransferSrvc.createJobTrasferSetPayloadOutput(jobTransferSetPayload);
expect(JSON.parse(result)[0]).toEqual(jobTransferSetPayload[0]);
expect(result).not.toBeNull();
});
it('should handle a writeFile error', async () => {
jest.spyOn(fs, 'writeFile').mockRejectedValue(new Error('something went wrong'));
try {
await empJobTransferSrvc.createJobTrasferSetPayloadOutput(jobTransferSetPayload, logger);
} catch (error) {
expect(error.message).toEqual('Error: something went wrong');
}
});
});

How to mock https.get with Jest

I have a function that calls https.get inside a promise which I want to test with Jest.
The function is like this:
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if( chunk ) {
chunks.push(JSON.parse(chunk));
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
const data = doSomething(chunks);
resolve(data)
});
});
})
}
I want to test that when the function resolves on "end" and rejects on "error";
Currently I have a test like this but because .on("end") doesn't get called, the promise never resolves.
describe("request", () => {
it("Should resolve", async (done) => {
const response = await request("my-url");
expect(response).toEqual("some-data")
})
})
How can I mock events like .on("end") to be called and ensure the promise resolves?
You can do something like this.
// ./request.test.js
jest.mock('https', () => ({
methodToMock: {}
}));
const Stream = require('stream');
const request = require("./request");
const httpsMock = require("https");
describe("request", () => {
it("Should resolve", async () => {
var streamStream = new Stream()
httpsMock.get = jest.fn().mockImplementation((url, cb) => {
cb(streamStream)
streamStream.emit('data', 'some');
streamStream.emit('data', '-');
streamStream.emit('data', 'data');
streamStream.emit('end'); // this will trigger the promise resolve
})
const response = await request("my-url");
expect(response).toEqual("some-data");
})
})
const https = require("https");
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if (chunk) {
// chunks.push(JSON.parse(chunk));
chunks.push(chunk);
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
// const data = doSomething(chunks);
const data = chunks.join('');
resolve(data)
});
});
})
}
module.exports = request;
Note that jest.mock('https', ...) need to be called before const request = require("./request"); if you want https to be mocked.

How to make two api calls using Promise.all within Angular9?

I making an api call using Promise.all as below:
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
The above code is working fine.
Now I want to make another api call after the successful completion of this.serviceB.retry(oretry).
The second api is this.serviceB.createDbEntry(sentry) and sentry looks as below:
const sretry: SDInterface = {
hostName,
Id: this.Id.slice(0, this.Id.length),
reason: this.reason
};
And, I am doing it as below
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
const sretry: SDInterface = {
hostName,
Id: this.Id.slice(0, this.Id.length),
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
The above code is giving an error:
error: "SequelizeValidationError: string violation: Id cannot be an array or an object"
It is looks like it is not calling the second api for every Id
You may want to take a look a forkJoin
import { Observable, forkJoin } from 'rxjs';
And then
ngOnInit() {
let one = this.http.get('some/api/1') //some observable;
let two = this.http.get('some/api/2') // another observable;
forkJoin([one, tow]).subscribe(response => {
// results[0] is our one call
// results[1] is our second call
let var1 = response[1];
let var2 = response[0];
}/*, error => { in case error handler } */);
}
Wouldn't it be better to use Promise.all() once more?
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
})
.then(() => {
return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
return new Promise((resolve, reject) => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
})
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
And using toPromise() will make the code more concise.
Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
return this.serviceB.retry(oretry).toPromise();
})
.then(() => {
return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).toPromise();
})
});
}))
.then(() => {
this.dialog.close();
})
.catch(err => {
console.log(err);
});
Use combineLatest, in Angular we use RxJs not promises.
combineLatest(
[this.http.get('call1'), this.http.get('call2')]
).subscribe(([result1, result2]) => {
// do stuff with result1 and result2
});
promise.all takes input in an array and gives response in an array,
Create 2 functions each with your asynchronous logic returning a promise,
Say funcA and funcB, then use below to invoke them parellely
Promise.all([funcA(this.hostName), funcB(this.id)])
.then(respones => {
console.log(responses[0]); //return value for funcA
console.log(responses[1]); //return value for funcB
})
.catch(err => console.log(err));
I am assuming your logic of functions are correct, I just copy-pasted from your question and gave them structure
const funcA = (hostName) => {
hostName.slice(0, this.Id.length).map((hostName) => {
return this.serviceC.status(hostName)
.then(res => {
return new Promise((resolve, reject) => {
const oretry: ORInterface = {
oQid: res.rows[0].qid,
reason: this.reason
};
this.serviceB.retry(oretry).subscribe(resolve);
});
});
});
}
const funcB = (Id) => {
Id.slice(0, this.Id.length).map(id => {
return new Promise((resolve, reject) => {
const sretry: SDInterface = {
hostName,
Id: id,
reason: this.reason
};
this.serviceB.createDbEntry(sentry).subscribe(resolve);
});
})
}

How to test in JEST a request that downloads a file

I want to unit test the exported method in the code below. Trying to write unit tests for a function that is downloading a zip file from a localhost server.I will write my function bellow so you understand better:
export const downloadCdn = async (cdnUrl, out) => {
const download = (resolve, reject) => {
const req = request({
method: 'GET',
uri: cdnUrl
});
req.on('response', (data) => {
// do something
});
req.on('error', (data) => {
// do something
});
req.on('data', (chunk) => {
// do something
});
req.on('end', () => {
console.log('download done');
});
req.pipe(out);
out.on('close', () => {
resolve([null, 'done']);
});
};
const downloadSummary = new Promise(download);
return downloadSummary
.then(() => [null, 'Done'])
.catch(err => [err, null]);
};
Here are my test file, what I'm trying to achieve is to have unit test that validates the download of the zip file:
import request from 'request';
import * as Module from './downloadCdn';
jest.mock('request', () => {
const mockRequest = {
pipe: jest.fn(),
on: jest.fn(),
};
return function () {
return mockRequest;
};
});
describe('Downloading a file', () => {
it('Should find the module', () => {
expect(typeof Module.downloadCdn === 'function').toBeTruthy();
});
it('Should download the zip', async () => {
const [error, response] = await Module.downloadCdn(cdnUrl, out);
expect(response === 'Done').toBeTruthy();
expect(error === null).toBeTruthy();
});
});
The response from the Promise, I receive inside the test is null, no error catching. Here is the error received from jest:
expect(received).toBeTruthy()
Expected value to be truthy, instead received false
While mocking the request, you should resolve the promise. I think that promise is not resolving that's why it's not working. I hope that the below code will be fixed your problem.
jest.mock('request', () => {
const mockRequest = {
pipe: jest.fn(),
on: (parameter, callback) => {
callback();
},
};
return function () {
return mockRequest;
};
});

sinon.mock().expects().atLeast() ... expectation.verify() not working

I am newbie on node and sinon and I'm having trouble to test the component below. I would like to check if the res.status and res.send were called inside the component.
Component to be tested
module.exports = {
handle: function(promise, res, next, okHttpStatus) {
promise
.then(payload => res.status(okHttpStatus ? okHttpStatus : 200).send(payload))
.catch(exception => next(exception));
}
};
Unit test
const sinon = require("sinon");
const routerPromiseHandler =
require("../../../main/node/handler/PromiseHandler");
describe("Should handle promisse", () => {
it("should handle success promise return", () => {
const successMessage = {message: "Success"};
const promiseTest = new Promise((resolve, reject) => {
resolve(successMessage);
});
let res = {
status: function() {},
send: function() {}
};
const mockRes = sinon.mock(res);
const expectStatus = mockRes.expects("status").withExactArgs(200).atLeast(1)
const expectSend = mockRes.expects("send").withExactArgs(successMessage).atLeast(1)
const spyNext = sinon.spy();
routerPromiseHandler.handle(promiseTest, res, spyNext, 200);
expectStatus.verify();
expectSend.verify();
});
});
I managed to solve the problem. The sinon check wasn't work because the spys were been called inside a promise. To check if the spy were been called. I had to add the assertions inside the then and catch of the promises.
const sinon = require("sinon");
const { mockResponse } = require("mock-req-res");
const routerPromiseHandler = require("../../../main/node/handler/PromiseHandler");
describe("Should handle promisse", () => {
it("should handle success promise return", () => {
const successMessage = { message: "Success" };
const promiseTest = new Promise((resolve, reject) => {
resolve(successMessage);
});
const mockedRes = mockResponse();
const spyNext = {};
routerPromiseHandler.handle(promiseTest, mockedRes, spyNext, 200);
promiseTest.then(() => {
sinon.assert.calledWithMatch(mockedRes.status, 200);
sinon.assert.calledWithMatch(mockedRes.send, successMessage);
})
});
it("should handle error promise return", () => {
const errorMessage = { error: "error" };
const promiseError = new Promise((resolve, reject) => {
reject(errorMessage);
});
const mockedRes = mockResponse();
const nextSpy = sinon.spy();
routerPromiseHandler.handle(promiseError, mockedRes, nextSpy, 200);
promiseError
.then(() => {
// Promise always need the then
})
.catch(exception => {
sinon.assert.calledWithMatch(nextSpy, errorMessage);
})
});
});

Categories