How to test the function correctly - javascript

I have a function that makes an API request and receives data in json format.
async function getDataAboutWeather(url) {
return await new Promise(resolve => {
request(url, (err, res, body) => {
if (err) {
throw new Error(err);
};
const info = JSON.parse(body);
resolve(info);
});
});
};
I want to write a test for this function.
describe('getDataAboutWeather function', () => {
it('The request should success', () => {
const link = 'http://ip.jsontest.com';
expect(getDataAboutWeather(link)).to.eql({});
});
});
How to verify that my function works as it should?
Since at the moment I get an error.
AssertionError: expected {} to deeply equal {}

getDataAboutWeather is an asynchronous function which means it returns a Promise. I would change the test to:
it('The request should success', async () => {
const link = 'http://ip.jsontest.com';
expect(await getDataAboutWeather(link)).to.eql({});
});

To test your function, you need to check if the API JSON is equal to the expected JSON. You can use the function below.
_.isEqual(object, other);
More information on this: How to determine equality for two JavaScript objects?

Related

res.send() is running before async function call on express.js

Summary: creating my own API that returns epoch time, and it involves using an express.js server, but it's running res.send() before the function call. I referenced this page, but it didn't help. Here's what I have:
app.get('/timestampAPI', async (req, res,) => {
try {
let finalResult = await getTimeStamp();
res.send({ something: finalResult });
} catch (error) {
console.log(error);
}
});
It'll start to run the function getTimeStamp(), and before that function finishes, it runs the res.send() function which shows up as '{}' because finalResult doesn't have a value. getTimeStamp() is an async function. I'm unsure of what I'm doing wrong.
Edit:
getTimeStamp() function:
async function getTimeStamp() {
await axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
.then(response => {
// also used console.log(response.data.UnixTimeStamp), which returns the timestamp
return response.data;
})
.catch(error => {
var errorMessage = error.response.statusText;
console.log(errorMessage);
});
}
Another edit: yes, the API referenced above does return the current epoch time, but CORS is blocking my other site from accessing it directly, so I can't use it on that site, which is why I'm using node.js for it so that I can allow myself to access it through my node.js program. Couldn't think of another way
returning value of the then method does not return from getTimeStamp function you should write you code in resolve pattern or using await like below
try this, make sure you write correct field name in response object
async function getTimeStamp() {
try{
const res = await axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
return res.data
}catch(error){
throw error
}
As an alternative to Mohammad's answer you can also use returning getTimeStamp function's result as a promise and it can solve your problem.
async function getTimeStamp() {
return new Promise((resolve, reject) => {
axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
.then(response => {
// also used console.log(response.data.UnixTimeStamp), which returns the timestamp
resolve(response.data);
})
.catch(error => {
var errorMessage = error.response.statusText;
console.log(errorMessage);
reject(error);
});
})
}
Or you would also replace await with return in getTimeStamp function in your code if you don't want to return promise.(Which is not I recommend.). You should also throw the error in catch block which is generated in getTimeStamp function for catching the error in try-catch block that you use to call app.get(...).

Calling a Promise function inside Google Cloud Function

I am trying to issue an HTTP request to another web service, from a Google Cloud Function (GCF) that I have created. I need the HTTP request to complete and return that result inside of my GCF so that I can do something else with it.
My question is; What is the best way to use Promise inside a Google Cloud Function? Is what I am trying to do possible?
My code currently looks like this:
export const MyGCF = functions.https.onRequest((request, response) => {
let dayOfTheWeek: any;
const request1 = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request1(url, { json: true }, (err: any, res: any, body: any) => {
if (err) {
return reject(err);
}
resolve(body.dayOfTheWeek);
});
});
}
getDay().then((data) => {
dayOfTheWeek = data;
console.log(dayOfTheWeek);
});
});
In general your approach will work, and you can define additional functions inside of your MyGCF handler, in the same way that you have defined getDay(). One problem with you current code however is that you're forgetting to "write a response" for the request being processed by MyGCF.
You can write a response for the request by calling send() on the second res argument of your MyGCF request handler. A simple example would be:
/* Sends a response of "hello" for the request */
res.send("hello");
With respect to your code, you can use res.send() in your .then() callback to send a response back to the client after getDay() has completed (see code below). Note also to include a .catch() clause and callback for the error case (with an error status) to ensure the client receives an appropriate error response if the call to getDay() fails:
export const MyGCF = functions.https.onRequest((req, res) => {
const request = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request(url, {
json: true
}, (err: any, r: any, body: any) => {
if (err) {
reject(err);
} else {
resolve(body.dayOfTheWeek);
}
});
});
}
getDay().then((dayOfTheWeek) => {
/* Send a response once the getDay() request complete */
res.send(dayOfTheWeek);
})
.catch(err => {
/* Don't forget the error case */
res.status(500).send(err);
});
});

Async http-request, node.js modules and variables

I'm currently struggling to get variable values from one node.js module into another. This is my current problem:
I am fetching data from a REST API via https-request:
// customrequest.js
sendRequest( url, function( data, err ) {
if(err) {
console.log('--- Error ---');
console.log( err );
}
else {
console.log('--- Response ---');
console.log(data);
// output: data
return data;
}
module.exports = { sendRequest }
And my index.js file:
// index.js
let sendRequest = require('./customrequest');
let req;
req = sendRequest('google.com');
console.log(req);
// output: undefined
// how can I get the variable set, when request is getting data in response?
I totally understand, that the request to an API takes some time for the response. One solution is, that I just put everything into one js file. But as my project will get bigger over time, the modular approach is my goto-solution. Any suggestions on how to solve this?
Node uses callbacks for this situation. Try something like this:
// customrequest.js
sendRequest(url, callback)
module.exports = { sendRequest }
// index.js
let sendRequest = require('./customrequest');
let req = sendRequest('google.com', function (data, err) {
if (err) {
//handle error here
}
console.log(data);
};
// output: undefined
// how can I get the variable set, when request is getting data in response?
Thanks. The problem I encounter is somewhat different. I solved it with this code snippets … using async and await.
// request.js
const fetch = require('node-fetch')
async function myRequest (somestring) {
try {
let res = await fetch('https://api.domain.com/?endpoint='+somestring)
if (res.ok) {
if (res.ok) return res.json()
return new Error (res.status)
}
} catch (err) {
console.error('An error occurred', err)
}
}
module.exports = { myRequest }
// index.js
const request = require('./requests')
const myRequest = request.myRequest
let myVar;
myRequest('somestring')
.then(res => myVar = res.result)
setInterval(() => {
myRequest('somestring')
.then(res => myVar = res.result)
console.log(myVar)
}, 1000)
The async function and awaits return a promise. This promise is, when resolved, assigned to a variable.

Mocha: how to test this async method that returns a callback?

I'd like to run a unit-test for a method like below.
returnsCallback (callback) {
return callback(null, false)
}
The callback arguments being passed in are, I believe, (error, response). I can't figure out how to test this or if it's even appropriate to test. Do I mock the callback argument to test it? I have below so far, and it seems to work, but I'm not sure. Any ideas?
describe('returnsCallback ()', function () {
let myObj = new MyObject()
it ('should always return false', function (done) {
myObj.returnsCallback(function (error, response) {
if (!error && response === false) {
done(false)
} else {
done(true)
}
})
})
})
You should test not that callback returns false, but that it's called with correct parameters. In your case they are null and false. I don't know what assertion library do you use, I show an example with using should module:
describe('returnsCallback ()', () => {
let myObj = new MyObject();
it ('should call callback with error is null and response is false', done => {
myObj.returnsCallback((error, response) => {
should(error).be.exactly(null);
should(response).be.equal(true);
done();
});
});
});

Response issue with callback

I think I'm missing something simple here but think that I've been looking at this too long.
I originally had what you see here in the function inline, but would like to pull it out and use it in other aspects of my app, but I can't seem to get the intended information into the POST response.
Here's my function:
let lookUpUserId = (x) => {
mongo.connect(url, (err,db) => {
assert.equal(null,err);
db.collection('data').findOne({"email": {'$eq' : x }},{"_id":1}, (err,result) => {
console.log(result); // I'm getting the correct response here.
assert.equal(null,err);
db.close();
return result; // This seems to be returning empty
});
});
};
And now here's where I'm calling it (simplified):
router.post('/test1', (req,res,next) => {
console.log('Hit on POST /test1');
let obj = 'email#email.com';
let a = lookUpUserId(obj);
res.send(a);
});
Now in the server's console I'm getting the expected info:
{_id:someIdHere }
However, I'm getting an empty body in response to my POST on the client side.
Can anyone point me in the right direction here.
lookUpUserId works asynchronously. Since you're not using promises, you can pass a callback as a second argument of lookUpUserId function:
let lookUpUserId = (x, callback) => {
mongo.connect(url, (err,db) => {
assert.equal(null,err);
db.collection('data').findOne({"email": {'$eq' : x }},{"_id":1}, (err,result) => {
console.log(result);
assert.equal(null,err);
db.close();
callback(result);
});
});
};
and call it with:
lookUpUserId(obj, (result) => res.send(result));
or even:
lookUpUserId(obj, res.send);

Categories