I want to test the response in nodejs using request, I tried doing some unit test but I cannot get inside the request function
let request = require('request');
function doRequest() {
new Promise((resolve, reject) => {
request(options, (error, response, body) => {
if(!err) {
// Test error
} else {
// Test success
}
})
});
}
I think u can use nock instead of request, but since you need to use request module here is an example
const request = require('request');
const requestCB = (resolve, reject) => async (error, response, body) => {
if (!error) {
// Test success
console.log(response);
resolve();
} else {
// Test error
console.error(error);
// reject();
}
};
function doRequest(options) {
new Promise((resolve, reject) => {
request(options, requestCB(resolve, reject));
})
.then(() => {})
.catch((err) => {});
}
const options = {
/* you can use this url if you want to test
* https://api.github.com/repos/request/request
*/
url: 'https://restcountries.eu/rest/v2/all',
headers: {
'User-Agent': 'request',
},
};
// call doRequest
doRequest(options);
Related
I would like both resolve() to return {valid_to: cert.valid_to, statusCode, statusMessage} and reject() should return {error: -1, statusCode, statusMessage}.
Question
How can I do that, when statusCode, statusMessage are in a different scope?
const https = require('https');
(async () => {
const options = {
hostname: "github.com",
port: 443,
path: '/',
method: 'GET',
timeout: 1000
};
options.agent = new https.Agent(options);
let valid_to = await new Promise((resolve, reject) => {
const req = https.request({
...options, checkServerIdentity: function (host, cert) {
resolve(cert.valid_to);
}
}).on('error', error => {
reject(-2);
});
req.on("timeout", chunk => {
reject(-1);
});
req.on('response', response => {
console.log(response.statusCode);
console.log(response.statusMessage);
});
req.end();
}).catch(error => {
console.log(error);
return -3;
});
})();
I will do something like this.
Edit: You need to specify res.on('data') in the https.request Object. Otherwise, timeout will always emit because there is no activity from the stream.
You can resolve in res.on("data") or res.on("end") and it is up to your use case.
res is an IncomingMessage object is created by http.ClientRequest and passed as the first argument to the 'request' and 'response' event respectively.
req is A reference to the original http.ClientRequest.
Both streams can emit events and you may handle them separately.
Also, when you reject the Promise, you actually cannot get the statusCode and StatusMessage from the req because there is an error in the req and the .on("response") will not be emitted. So, you need to customize the statusCode and statusMessage yourself.
const https = require("https");
// {valid_to: cert.valid_to, statusCode, statusMessage}
// {error: -1, statusCode, statusMessage}.
(async () => {
const options = {
hostname: "githubasdfa.com",
port: 443,
path: "/",
method: "GET",
timeout: 1000,
};
options.agent = new https.Agent(options);
try {
const response = await new Promise((resolve, reject) => {
let valid_to;
let statusCode;
let statusMessage;
const req = https
.request(
{
...options,
checkServerIdentity: function (host, cert) {
valid_to = cert.valid_to;
},
},
res => {
res.on("data", chunk => {
resolve({
valid_to,
statusCode,
statusMessage,
});
});
res.on("end", () => {
console.log("No more data in response.");
});
}
)
.on("error", err => {
console.log(err);
reject({
error: -2,
statusCode: "custom code",
statusMessage: "unhandled error",
});
})
.on("timeout", chunk => {
reject({
error: -1,
statusCode: "custom code",
statusMessage: "unhandled error",
});
})
.on("response", response => {
statusCode = response.statusCode;
statusMessage = response.statusMessage;
})
.end();
});
console.log(response);
} catch (error) {
console.log(error);
}
})();
I have a problem with this piece of code:
async getDomains (req, res) {
try {
let domains = await Domain.findAll({ raw: true })
for(domain of domains) {
console.log('1')
var options = {
host: domain.name,
port: 443,
method: 'GET'
};
var request = https.request(options, (res) => {
console.log('2')
console.log('iam here')
domain.ssl = {
'valid_until': res.connection.getPeerCertificate().valid_from
}
});
console.log('3')
request.end();
}
console.log('4')
res.send(domains)
} catch(err) {
res.status(400).send({
error: err
})
}
},
The output should be 1, 2, 3, 4 but instead I got 1, 3, 4, 2.
Does anyone have an idea how to achieve that?
You've provided a callback to request, so it's going to send the request and move on, only logging 2 once a response is received. You'll want to use some sort of Promise or async/await to wait for the response from your request.
var request = await (new Promise((resolve, reject) => {
https.request(options, (res) => {
console.log('2');
console.log('i am here');
domain.ssl = { /* stuff */ };
resolve();
});
));
I'm trying to develop a function in VS Code that takes an url as input and returns the response after processing is complete. However, when this function is run, it returns nothing. I tried testing similar code in Webstorm and and confirm that it console.logs the results just fine. I'm new to node and promises so not sure what I'm doing wrong.
Edit - added return keyword before driver.get as per the suggestion from #hellikiam. Also added a simple log statement to confirm that the results available yet not being returned in body.
var AxeBuilder = require('#axe-core/webdriverjs'),
WebDriver = require('selenium-webdriver');
const chromedriver = require('chromedriver');
const chrome = require("selenium-webdriver/chrome");
const screen = {
width: 640,
height: 480
};
chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build());
var driver = new WebDriver.Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options().headless().windowSize(screen))
.build();
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
const url = (req.query.url || (req.body && req.body.url));
return driver.get(url).then(function () {
new AxeBuilder(driver).analyze(function (err, results) {
resultsJson = JSON.stringify(results);
console.log(resultsJson)
context.res = {
status: 200, /* Defaults to 200 */
body: resultsJson,
headers: {
'Content-Type': 'application/json'
}
};
if (err) {
// Handle error somehow
}
});
});
context.done();
}
you didn't returned anything from exported module.
return driver.get(url).then(function () {//add return statement in here.
new AxeBuilder(driver).analyze(function (err, results) {
resultsJson = JSON.stringify(results);
context.res = {
status: 200, /* Defaults to 200 */
body: resultsJson,
headers: {
'Content-Type': 'application/json'
}
};
if (err) {
// Handle error somehow
}
});
});
I found the other problem. What you want to return is inside callback function.
You should wrap the callback with promise to get the result outside of the callback. Try this out brother.
return new Promise((resolve, reject) =>{
driver.get(url).then(function () {//add return statement in here.
new AxeBuilder(driver).analyze(function (err, results) {
resultsJson = JSON.stringify(results);
context.res = {
status: 200, /* Defaults to 200 */
body: resultsJson,
headers: {
'Content-Type': 'application/json'
}
};
resolve(resultsJson)//Any value you want to return
if (err) reject(err)
});
});
})
Calling this function outside of module with await statement
const foo = require('./my/path/foo')
(async()=>{
const params = 'my param'
const bar = await foo(params)
console.log(bar)
})()
I have a node js with express application. I need to expose a rest endpoint that will return the response of a http call. Whatever I try it returns before the http request. Can you please help
app.all('/query', function(req, res){
// here i need to make a http call
let urlCall = new Promise((resolve, reject) => {
http.get('http://test.com', (response) => {
let sdata = '';
response.on('data', (fragments) => {
sdata += fragments;
});
response.on('end', () => {
let response_body = sdata;
resolve(response_body.toString());
});
response.on('error', (error) => {
// promise rejected on error
reject(error);
});
});
});
urlCall.then((response) => {
var responseData=response;
res.json(responseData);
res.end();
}).catch((error) => {
console.log(error);
res.end();
});
}
Your code should work, but I suspect a request error not being handled (the error event handler being missing on your request)
You can try moving the error handler from the response to the request
app.all("/query", function (req, res) {
// here i need to make a http call
let urlCall = new Promise((resolve, reject) => {
http
.get("http://test.com", (response) => {
let sdata = "";
response.on("data", (fragments) => {
sdata += fragments;
});
response.on("end", () => {
let response_body = sdata;
resolve(response_body.toString());
});
})
.on("error", (error) => { // handling request errors
console.error("error");
// promise rejected on error
reject(error);
});
});
urlCall.then(
(response) => {
res.json(response);
res.end();
},
(error) => {
console.log(error);
res.end();
}
);
});
I am a beginner to callback concept and looking for a solution to my problem.
I calling third party API using request package in node.js here is the code:
In reusable library file: auth.js
let getAuthToken = () => {
let authToken;
var options = {
'method': 'GET',
'url': 'https://<apiURL>/V1/auth_token',
'headers': {
'Authorization': 'Basic <token>'
}
};
request(options, (error, response) => {
if (error) {
throw new Error(error);
} else {
authToken = JSON.parse(response.body);
}
});
return authToken;
}
on my route: http://127.0.0.1:3000/api/v1/musics/authorize-account, I am calling my controller function named "getAuthorizationToken()"
controllerfile: music.controller.js
const auth = require('../middleware/auth');
let getAuthorizationToken = async (req, res, next) => {
let token = await auth.getAuthToken();
console.log(auth.getAuthToken());
res.send(token);
}
Problem is the controller function is getting executed completely and then the third party API is being called event I have added await to the function.
Do explain to me the problem I am facing and any workaround solution will be heartily helpful.
You have to return a promise to be able to await something and have it work as expected:
let getAuthToken = () => {
let authToken;
var options = {
'method': 'GET',
'url': 'https://<apiURL>/V1/auth_token',
'headers': {
'Authorization': 'Basic <token>'
}
};
return new Promise((resolve, reject) => {
request(options, (error, response) => {
if (error) {
reject(error);
} else {
authToken = JSON.parse(response.body);
resolve(authToken);
}
});
})
}
await is only useful on promises. In your case your getAuthToken does not return an promise. But you can change it.
let getAuthToken = () => {
return new Promise((res, rej) => {
let authToken;
var options = {
method: "GET",
url: "https://<apiURL>/V1/auth_token",
headers: {
Authorization: "Basic <token>"
}
};
request(options, (error, response) => {
if (error) {
rej(error);
} else {
authToken = JSON.parse(response.body);
res(authToken);
}
});
});
};
In addition you should also wrap your await in a try / catch
let getAuthorizationToken = async (req, res, next) => {
try {
let token = await auth.getAuthToken();
console.log(token);
return res.send(token);
} catch(err) {
console.log(err);
return res.status(500).send(err);
}
}
Instead of an 500 error you should send an different error code like:
400 Bad request: If there are some missing credentials like the token is missing
401 Unauthorized: If the token is wrong