JWT test case mocking in nodejs - javascript

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 );
});

Related

Catching Error with Nested Promise confusion

I have been working on my first node.js backend and I am trying to refactor the login function, but i am not understanding something about promise chaining and error handling. I am hoping someone can help point out what I am missing here.
I have read about promise chaining and I understand that one catch should be able to handle any error in the chain, but I cant seem to get it to work without having an individual .catch for every .then
Here is my userLogin function.
const loginUser = handleAsync(async (req, res, next) => {
let userEmail = req.body.email;
let submittedPassword = req.body.password;
userLogin(userEmail, submittedPassword)
.then((userObject) => {
res.json(userObject);
})
.catch((err) => {
res.status(401).send(err);
console.log("any error inside userLogin: " + err);
});
});
async function userLogin(email, submittedPassword) {
console.log("in user login");
return new Promise(function (resolve, reject) {
getUserAccountByEmail(email)
.then((userAccountResults) => {
let email = userAccountResults[0].email;
let storedPassword = userAccountResults[0].password;
//the user exists check the password
//the user exists. Now Check password.
checkUserPassword(submittedPassword, storedPassword)
.then((passwordIsAMatch) => {
//The password is a match. Now Generate JWT Token.
generateJWTToken(email)
.then((tokens) => {
//build json object with user information and tokens.
createUserDataObject(tokens, userAccountResults)
.then((userObject) => {
//send the user object to the front end.
resolve(userObject);
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
});
}
And here is one of the functions that is a part of the chain
function getUserAccountByEmail(email) {
return new Promise(function (resolve, reject) {
logger.info("Looking up user email");
const users = User.findAll({
where: {
email: email,
},
limit: 1,
attributes: [
"email",
"password",
"userId",
"stripeConnectAccountId",
"isStripeAccountSet",
"stripeCustomerId",
],
})
.then((userResults) => {
if (doesUserExist(userResults)) {
resolve(userResults);
} else {
console.log("user doesnt exist in getuseraccount");
reject("User Email Does Not Exist In Database");
}
})
.catch((error) => {
console.log("Error Accessing Database: UserAccountByEmail");
logger.error("Error in getUserAccountByEmail: " + error);
});
});
}
Any help would be appreciated. Thanks
I took jfriend00 's advice and refactored using await instead of nesting.
async function userLogin(email, submittedPassword) {
return new Promise(async function (resolve, reject) {
try {
//Get User Account Information
const userAccountResults = await getUserAccountByEmail(email);
//Password Authentication
let storedPassword = userAccountResults[0].password;
const passwordIsAMatch = await checkUserPassword(
submittedPassword,
storedPassword
);
//Generate JWT Tokens
const tokens = await generateJWTToken(email);
//Prepare user data JSON for sending to the frontend.
const userData = await createUserDataObject(tokens, userAccountResults);
resolve(userData);
} catch (error) {
reject(error);
}
});
}

How to solve : SyntaxError: await is only valid in async function in nodejs

I want to call a function in usercontroller which is placed in another controller. I have used async function but still receiving
SyntaxError: await is only valid in async function
My code is as follow.
UserController.js
exports.adduser = async function (req, pic, type, res) {
await adduser(req, pic, type)
.then(data => { result = data; res(result) })
.catch(err => {
result.success = false;
if (err.status != undefined) {
result.status = err.status
result.message = err.message
} else {
result.status = 500
result.message = "Server Error " + String(err)
}
res(result)
});
};
async function adduser(req, pic, type) {
await schoolController.checkSchool(req.body)
.then(resp => {}).catch((err)=>{
..................
})
})
SchoolController.js
exports.checkSchool = async function (formdata) {
return new Promise(async (resolve, reject) => {
finder = { _id: formdata.school_id, is_deleted: false, is_blocked: false }
School.findOne(finder, function (err, res) {
if (res != null) {
reject({ status: false, message: "School" })
}
else {
resolve({ status: true, cityId: res.cityId })
}
})
});
}

How to test callback of function in Chai?

I am using Slack API and I want to test does it work fine with response status code. Here is sending function :
sendMsg(msg) {
return this.slack.webhook({text: msg}, (err, res) => {
if (err) {
throw err;
}
console.log(res.statusCode) // = 200
return res.statusCode;
});
}
And my test:
it('Checks connection with Slack', (() => {
let slack = new Slack();
let res = slack.sendMsg('test');
expect(res).to.equal(200);
}));
But ofc. it's giving me request object to slack. I want to wait for response object from slack API. Thanks in advance.
It looks like slack.webhook takes in a callback, which is how you retrieve the status. The problem is that the caller of sendMsg has no way of getting that status.
One way to solve this is to have sendMsg take in a callback:
sendMsg(msg, onStatusReceived) {
this.slack.webhook({text: msg}, (err, res) => {
if (err) {
throw err;
}
console.log(res.statusCode) // = 200
onStatusReceived(res.statusCode);
});
}
Then in your test, use done to end the test when the callback is invoked:
it('Checks connection with Slack', (done) => {
let slack = new Slack();
slack.sendMsg('message', status => {
expect(status).to.equal(200);
done();
});
});
Another way is to have sendMsg wrap slack.webhook in a promise, so the caller can do sendMsg().then(...).
one of the ways I handled a returning callback to test is as follows:
it('receives successful response', async () => {
nock('https://localhost')
.persist()
.log(console.log)
.post(‘/getData’, (unitData, callback) => {
return true;
})
.delayBody(1000)
.reply(200, {statusCode: 'Some Status'});
const getSomeData = await getResponse(unitData, function callBack(unitData, error, data){
expect(data.statusCode).to.be.equal(200);
}) })
getResponse Function (returning callback):
getResponse(unitData, function callBack(unitData, error, data){
try {
return request.post(unitData, function (err, resp) {
if (!err && resp.statusCode === 200) {
if (resp.body.error) {
return callback(obj, JSON.stringify(resp.body.error), null);
}
return callback(obj, null, resp);
} else {
if (err == null) {
err = { statusCode: resp.statusCode, error: 'Error occured.' };
}
return callback(obj, err, null);
}
});
} catch (err) {
return callback(obj, err, null);
}
}

Check that email exists with Node within API

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);

How to force a function to execute first in Jasmine test?

I have a route in Node that gets an auth key. I want to use this auth key in all my jasmine tests as a parameter in the URL request. I want SetUp function to run, set a global var, then allow me to use this variable in all the rest of the test cases.
SetUp Function
var global_key = request({
uri : 'http://localhost:3000/grabToken',
method : 'GET'
},
function (err, body, res) {
if (err) { console.log(err);}
else {
return body['auth_key'];
}
});
Test Suite
function testCases() {
describe(TEST_SUITE, function() {
describe("GET /retrieveSecret/VALID_UUID", function() {
it('Requests the secret - Successful response', function(done) {
// ...
}
}
}
}
You could use asynchronous version of beforeAll function:
describe(TEST_SUITE, function() {
let key;
beforeAll(function (done) {
const params = { uri: 'http://localhost:3000/grabToken', method: 'GET' };
request(params, function (err, body, res) {
if (err) {
console.log(err);
done.fail();
} else {
key = body['auth_key'];
done();
}
});
})
describe("GET /retrieveSecret/VALID_UUID", function() {
it('Requests the secret - Successful response', function(done) {
// `key` is available here
}
});
})

Categories