Introduction
Ok, I have Three functions. the first two generate data for the third.
Gets post data (email)
Gets API key
Uses API key, User_key and email and post them to the API
What I need
I need the third to print the following to my console providing the email is present.
else {
console.log("Login successful !");
console.log("API Key", api);
console.log("userKey", userkey);
console.log("useremail", login_email);
console.error("Third You have logged in !");
}
What I am getting
error null
I am getting this even though I post a email that exist. Dose anyone see where I am going wrong in my code ?
Node Code
var firstFunction = function () {
var promise = new Promise(function (resolve) { // may be redundant
setTimeout(function () {
app.post('/test.js', function (req, res) {
console.log(req.body);
// Get varibles from the post form
var login = req.body.LoginEmail;
// res.send(email_user);
res.send(login);
//resolve when get the response
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
return promise;
};
//---------------------------------- Function to get API key from Pardot (AUTHENTICATION) ------------------------------
//----------------------------------------------------------------------------------------------------------------------
var secondFunction = function () {
var promise = new Promise(function (resolve) {
setTimeout(function () {
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
DEBUG: false
}, function (err, client) {
if (err) {
// Authentication failed
console.error("Authentication Failed", err);
} else {
// Authentication successful
var api_key = client.apiKey;
console.log("Authentication successful !", api_key);
resolve({data_api: api_key});
}
});
console.error("Second done");
}, 2000);
});
return promise;
};
//---------------------------------- Function to post data to Pardot ---------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
function thirdFunction(result) {
var promise = new Promise(function () {
setTimeout(function () {
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
// Configure the request
var api = result[1].data_api;
var userEmail = result[0].data_login_email;
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/read',
method: 'POST',
headers: headers,
form: {
'email': userEmail,
'user_key': userkey,
'api_key': api
}
};
// Start the request
request(options, function (error, response) {
if (!error && response.statusCode == 200) {
console.log("error", error);
}
else {
console.log("Login successful !");
console.log("API Key", api);
console.log("userKey", userkey);
console.log("useremail", login_email);
console.error("Third You have logged in !");
}
});
}, 3000);
});
return promise;
}
// sequence of functions
Promise.all([firstFunction(), secondFunction()])
.then(thirdFunction);
Related
Ok, i'm done. Please someone help me :(
I don't know how js and lambda works
What i have to do:
Send GET request and get response.
Write data from response to DynamoDb
I can do it 1by1 but can't do everything by 1 lambda call.
My code:
const https = require('https');
const crypto = require("crypto");
const AWS = require('aws-sdk');
const DynamoDb = new AWS.DynamoDB({region: 'eu-central-1'});
exports.handler = async (event) => {
let response;
console.log("Start");
let steamTicket;
let steamId;
if(event.body){
const body = JSON.parse(event.body);
if(body.steamticket && body.steamid){
steamTicket = body.steamticket;
steamId = body.steamid;
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find steamid or steamticket in your request'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find request body'
})
};
return response;
}
await httprequest(steamTicket).then((data) =>{
if(data.response && data.response.params){
if(data.response.params.result == 'OK' && data.response.params.steamid == steamId){
console.log(JSON.stringify(data));
const sessionId = crypto.randomBytes(16).toString("hex");
console.log('Generated session id: ' + sessionId);
PutToDB(sessionId, steamId);
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'steam response is not OK or session != steamId'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'invalid response from steam: ' + JSON.stringify(data)
})
};
return response;
}
});
};
async function PutToDB(sessionId, steamId){
var WriteParams = {
RequestItems:{
SteamSessions: []
}
};
WriteParams.RequestItems.SteamSessions.push({
PutRequest:{
Item: {
SteamId: {S: steamId},
SessionId: {S: sessionId},
ttl: {N: (Math.floor(Date.now() / 1000) + 600).toString()}
}
}
});
console.log('SessionIdToWrite: ' + sessionId);
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
}
else{
console.log("Success write", JSON.stringify(data));
}
})
})
}
async function httprequest(steamTicket) {
return new Promise((resolve, reject) => {
const options = {
host: 'partner.steam-api.com',
path: '/ISteamUserAuth/AuthenticateUserTicket/v1/?key=somekey&appid=someid&ticket=' + steamTicket,
port: 443,
method: 'GET'
};
const req = https.request(options, (res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error('statusCode=' + res.statusCode));
}
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch(e) {
reject(e);
}
resolve(body);
});
});
req.on('error', (e) => {
reject(e.message);
});
// send the request
req.end();
});
}
I lost way already, i'm not even sure it should work like that.
And most confusing thing! This b give me this test results:
Run 1:
2021-03-05T13:28:47.741Z INFO Start
2021-03-05T13:28:48.612Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:28:48.650Z INFO Generated session id: 6a5633a5f862d8663d0fe546a9c89feb
2021-03-05T13:28:48.650Z INFO SessionIdToWrite: 6a5633a5f862d8663d0fe546a9c89feb
DynamoDb is empty, here we can't see log from DynamoDb.batchWriteItem result.
Run 2:
2021-03-05T13:29:53.308Z INFO Start
2021-03-05T13:29:53.674Z INFO Success write {"UnprocessedItems":{}}
2021-03-05T13:29:54.048Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:29:54.048Z INFO Generated session id: 05c62de782202fc100cea9d47e38242c
2021-03-05T13:29:54.048Z INFO SessionIdToWrite: 05c62de782202fc100cea9d47e38242c
And after second run i can see in DynamoDb sessionId from FIRST RUN (6a5633a5f862d8663d0fe546a9c89feb)
If i run it again, there will be id from 2nd run
I think it continues to run previous tasks on new run? Or what? I'm lost
Thank you for any help with it
You need to call reject / resolve in the DynamoDb.batchWriteItem call.
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
reject(err);
}
else{
console.log("Success write", JSON.stringify(data));
resolve();
}
})
})
I am trying to write a test case for jwt token validation in node js.I am able to cover failure cases but not successful case.
isValid: function (request, reply) {
if (request.query && request.query.token) {
var token = request.query.token;
validateTok(token)
.then(function (credentials) {
reply(true);
})
.catch(function (err) {
reply(false);
})
} else {
reply(false);
}
}
function validateT(jwt) {
return new Promise(function (resolve, reject) {
Security.validate(jwt, function (err, success, credentials) {
if (err || !success) {
reject(err)
} else {
resolve(credentials);
}
});
});
};
I want to mock Security.validate(jwt, function (err, success, credentials) to return success. Following is my test case.
it('should pass token validation', async () => {
const data = {
token: '1512598739676174ae69792b81583fd210c381c50f',
};
const request = generateRequest({query: data,});
const response = await awaitHandler(users.isValid, request);
(response).should.eql( true );
});
I am new to Promise concepts and trying to wrap my head around but now I`` am confused here
const request = require("request");
const cheerio = require("cheerio");
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var url = require("url");
module.exports = {
resturant: resturant,
};
var resturanttables = [];
function resturant(url, day) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, html) {
if (error) {
return reject(error);
} else if (response.statusCode !== 200) {
return reject("Something is wrong! CINEMA")
}
httplogin("zeke", "coys", url, day);
console.log(resturanttables, "i am here");
resolve(resturanttables);
});
});
}
function httpafterlogin(url, cookie, day) {
request.get({
headers: {
'content-type': 'text/html',
'Cookie': cookie
},
url: url,
},
function(error, response, body) {
console.log(day)
var $ = cheerio.load(body);
if (day === "Friday") {
$(".WordSection2 p span ").each(function(li) {
// console.log(day, $(this).text())
resturanttables.push($(this).text());
console.log(resturanttables, "nside");
});
} else if (day === "Saturday") {
$(".WordSection4 p span").each(function(li) {
resturanttables.push($(this).text())
});
} else {
$(".WordSection6 p span").each(function(li) {
resturanttables.push($(this).text())
});
}
});
}
function httplogin(username, password, urls, day) {
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: urls,
form: {
"username": username,
"password": password
}
}, function(error, response, body) {
var cookie = response.caseless.dict['set-cookie'][0];
var location = response;
console.log(response.statusCode);
cookie = cookie.substring(0, cookie.indexOf(';'));
// httpafterlogin('http://vhost3.lnu.se:20080/dinner/'+response.headers.location, cookie);
var newurls = url.resolve(urls, response.headers.location)
httpafterlogin(newurls, cookie, day);
// console.log(response.headers, "jdjdjjdjdjjdjdjdjjdjjdjdj")
});
}
and then I call the function
loadPage.resturant("http://vhost3.lnu.se:20080/dinner/login", "Friday").then(function(data) {
console.log(data, "did it work now ")
})
the problem is that it returns the empty array. But when i tried to check and console.log in the afterlogin function and i could see that the array was actually filled, but that code runs after the promise has been resolved.
IN SHORT: how can I bound the resolve in restaurant promise not to send the data until the login function is completed?
in other words how can i get the filled array with information from afterlogin funtion?
rewrite httplogin and httpafterlogin to return promises:
function httpafterlogin (url, cookie, day) {
return new Promise(function (resolve, reject) {
request.get({
headers: {
'content-type': 'text/html',
'Cookie': cookie
},
url: url
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
}).then(function (body) {
console.log(day);
var $ = cheerio.load(body);
if (day === "Friday") {
$(".WordSection2 p span").each(function (li) {
// console.log(day, $(this).text());
resturanttables.push($(this).text());
console.log(resturanttables, "nside");
});
} else if (day === "Saturday") {
$(".WordSection4 p span").each(function (li) {
resturanttables.push($(this).text());
});
} else {
$(".WordSection6 p span").each(function(li) {
resturanttables.push($(this).text());
});
}
});
}
function httplogin(username, password, urls, day) {
return new Promise(function (resolve, reject) {
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: urls,
form: {
"username": username,
"password": password
}
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(response);
}
});
}).then(function (response) {
var cookie = response.caseless.dict['set-cookie'][0];
var location = response;
console.log(response.statusCode);
cookie = cookie.substring(0, cookie.indexOf(';'));
var newurls = url.resolve(urls, response.headers.location)
return httpafterlogin(newurls, cookie, day);
});
}
then use .then like rsp suggested:
function resturant(url, day) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, html) {
if (error) {
return reject(error);
} else {
resolve(response);
}
})
}).then(function (response) {
if (response.statusCode !== 200) {
throw new Error("Something is wrong! CINEMA");
}
return httplogin("zeke", "coys", url, day)
}).then(function () {
console.log(resturanttables, "i am here");
return resturanttables;
});
}
this way, the block containing resolve(restautanttables) will not get called until httplogin completes
Use promises throughout your code - you can simplify your code using the request-promise package in place of the request package. All requests become promises and the code is easier to read and maintain.
const rp = require("request-promise");
const cheerio = require("cheerio");
const url = require("url");
function resturant(url, day) {
rp(url)
.then(function(){
// URL returned a 200 response
// so attempt to perform login
httplogin("zeke", "coys", url, day)
.then(function (data) {
// Promise is resolved here
return data;
});
})
.catch(function(error){
// just throwing the error
throw error;
});
}
function httplogin(username, password, urls, day) {
var options = {
headers: {
"content-type": "application/x-www-form-urlencoded"
},
uri: urls,
form: {
username: username,
password: password
},
method: "POST",
resolveWithFullResponse: true
};
rp(options)
.then(function (response) {
// POST succeeded
// grab the cookie
var cookie = response.caseless.dict['set-cookie'][0]
.substring(0, cookie.indexOf(';'));
// get new url string
var newurls = url.resolve(urls, response.headers.location);
httpafterlogin(newurls, cookie, day)
.then(function (tables) {
return tables;
})
.catch(function (error) {
// just throwing the error
throw error;
});
})
.catch(function (error) {
// Login failure
// just throwing the error
throw error;
});
}
function httpafterlogin(url, cookie, day) {
var options = {
headers: {
"content-type": "text/html",
"Cookie": cookie
},
uri: url,
transform: function (body) {
return cheerio.load(body);
}
};
rp(options)
.then(function ($) {
// body has been transformed and
// can now be processed with jQuery
// initialise the tables array
var tables = [];
// DRY code
// set default selector
var selector = ".WordSection6 p span";
// change the selector for Friday/Saturday
if (day === "Friday") {
selector = ".WordSection2 p span ";
} else if (day === "Saturday") {
selector = ".WordSection4 p span";
}
// process the selected section
$( selector ).each(function(li) {
tables.push($(this).text())
});
// crawling complete
return tables;
})
.catch(function (error) {
// Crawling failure
// just throwing the error
throw error;
});
}
If you don't want the promise to get resolved before the login is completed then you will either have to make your httplogin function take a callback and run it like this:
httplogin("zeke", "coys", url, day, function (err) {
if (err) {
reject(err);
} else {
resolve(resturanttables);
}
});
or make it return a promise and run it for example like this:
httplogin("zeke", "coys", url, day).then(function () {
resolve(resturanttables);
}).catch(function (err) {
reject(err);
});
There are more ways to do it with promises but this is the simplest way.
Either way you have to make your httplogin function signal its completion by either calling the callback that it takes as an argument or resolving the promise that it returns.
I am building a simple server with Koa and Node 0.11. I want an email to be sent to me when a user submits an inquiry from my site. Of course, I want to alert the users if the email fails to send for whatever reason, but I'm not sure of the best way to "wait" for that to happen.
My relevant server code is pretty simple:
app.put('/inquiry', function *() {
var status = yield sendEmail('test', "my message", "me#mysite" );
this.body = status;
});
function sendEmail(subject, message, to) {
var fromEmail = 'you#yoursite.com';
var tags = ['subject'];
var to = {email: to};
return function() {
mandrill('/messages/send',
{
message: {
"from_email":fromEmail,
"to":[to],
"text":message,
"tags":tags
}
},
function (error, response) {
if (error) {
console.log(JSON.stringify(error));
return error;
}
else {
console.log("Mandrill result: "+response);
return response;
}
};
);
};
};
The problem that I'm having is that the Mandrill.send() function doesn't return anything, and I'm not sure what the best thing to do is.
You just need to wrap it up in an anonymous function like this:
function sendEmail(subject, message) {
var fromEmail = 'test#elliottregan.com';
var tags = ['subject'];
var to = {email:'oatmealsnap#gmail.com'};
return function(callback) {
mandrill('/messages/send', {
message: {
"from_email":fromEmail,
"to":[to],
"text":message,
"tags":tags
}
},
function (error, response) {
if (error) {
console.log(JSON.stringify(error));
return error;
}
else {
console.log("Mandrill result: "+response);
callback(null, response);
}
}
)}
};
I want to test a asynchronous javascript function that runs in node.js and makes a simple request to a http api:
const HOST = 'localhost';
const PORT = 80;
http = require('http');
var options = {
host: HOST,
port: PORT,
path: '/api/getUser/?userCookieId=26cf7a34c0b91335fbb701f35d118c4c32566bce',
method: 'GET'
};
doRequest(options, myCallback);
function doRequest(options, callback) {
var protocol = options.port == 443 ? https : http;
var req = protocol.request(options, function(res) {
var output = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log(chunk);
output += chunk;
});
res.on('error', function(err) {
throw err;
});
res.on('end', function() {
var dataRes = JSON.parse(output);
if(res.statusCode != 200) {
throw new Error('error: ' + res.statusCode);
} else {
try {
callback(dataRes);
} catch(err) {
throw err;
}
}
});
});
req.on('error', function(err) {
throw err;
});
req.end();
}
function myCallback(dataRes) {
console.log(dataRes);
}
Executed this code works and the response will be displayed as expected.
If I execute this in a mocha test the request is not executed:
describe('api', function() {
it('should load a user', function() {
assert.doesNotThrow(function() {
doRequest(options, myCallback, function(err) {
if (err) throw err;
done();
});
});
assert.equal(res, '{Object ... }');
});
});
The Problem is, that no code after:
var req = protocol.request(options, function(res) {
is executed not even a simple console.log.
Can anybody help?
You have to specify the callback done as the argument to the function which is provided to mocha - in this case the it() function. Like so:
describe('api', function() {
it('should load a user', function(done) { // added "done" as parameter
assert.doesNotThrow(function() {
doRequest(options, function(res) {
assert.equal(res, '{Object ... }'); // will not fail assert.doesNotThrow
done(); // call "done()" the parameter
}, function(err) {
if (err) throw err; // will fail the assert.doesNotThrow
done(); // call "done()" the parameter
});
});
});
});
Also, the signature of doRequest(options, callback) specifies two arguments though when you call it in the test you provide three.
Mocha probably couldn't find the method doRequest(arg1,arg2,arg3).
Did it not provide some error output? Maybe you can change the mocha options to get more information.
EDIT :
andho is right, the second assert would be called in parallel to assert.doesNotThrow while it should only be called in the success callback.
I have fixed the example code.
EDIT 2:
Or, to simplify the error handling (see Dan M.'s comment):
describe('api', function() {
it('should load a user', function(done) { // added "done" as parameter
assert.doesNotThrow(function() {
doRequest(options, function(res) {
assert.equal(res, '{Object ... }'); // will not fail assert.doesNotThrow
done(); // call "done()" the parameter
}, done);
});
});
});
If you have an asynchronous function that does not support callbacks, or if you think using unnecessary callbacks is... unnecessary, then you can also just turn the test into an async test.
instead of:
it('should be able to do something', function () {});
simply do:
it('should be able to do something', async function () {});
^^^^^
Now you can await async functions:
it('should be able to do something', async function () {
this.timeout(40000);
var result = await someComplexFunction();
assert.isBelow(result, 3);
});
I've done a very similar test in my project for an http client. I paste the code here and hope is useful.
Here is the client (my nodejs server use express and I use promise for error handling):
var http = require('http');
var querystring = require('querystring');
module.exports = {
get: function(action, params, res, callback) {
doPromiseRequest(action, querystring.stringify(params), callback, 'GET', 'application/json')
.then((response) => callback(response))
.catch((error) => {
res.status(500);
res.render('error', {layout: false, message: error.message, code: 500});
});
},
}
function doPromiseRequest(action, params, callback, method, contentType) {
var options = {
hostname: 'localhost',
port: 3000,
path: '/api/v1/' + action.toString(),
method: method,
headers: {
'Content-Type': contentType,
'Content-Length': Buffer.byteLength(params)
}
};
return new Promise( (resolve, reject) => {
var req = http.request(options,
function(response) {
response.setEncoding('utf8');
var data = '';
response.on('data', function(chunk) {
data += chunk;
});
response.on('end', function() {
var parsedResponse;
try {
parsedResponse = JSON.parse(data);
} catch(err) {
reject({message: `Invalid response from hurricane for ${action}`});
return;
}
if (parsedResponse.error)
reject(parsedResponse.error);
else
resolve(parsedResponse);
});
response.on('error', function(err){
console.log(err.message);
reject(err);
});
});
req.on('error', function(err) {
console.log(err);
reject({message: err.message});
});
req.write(params);
req.end();
});
}
And here is the test:
var http = require('http');
var expect = require('chai').expect;
var sinon = require('sinon');
var PassThrough = require('stream').PassThrough;
describe('Hurricane Client tests', function() {
before(function() {
this.request = sinon.stub(http, 'request');
});
after(function() {
http.request.restore();
});
it('should convert get result to object', function(done) {
var expected = { hello: 'world' };
var response = new PassThrough();
response.statusCode = 200;
response.headers = {}
response.write(JSON.stringify(expected));
response.end();
var request = new PassThrough();
this.request.callsArgWith(1, response).returns(request);
client.get('any', {}, null, function(result) {
expect(result).to.eql(expected);
done();
});
});
});