I am having trouble getting access to a value in an object in my Express app after being successfully retrieved from a Mongo DB collection.
Here is the code.
app.post("/api/validate", async (req,res) => {
console.log('validating with id -> ', req.body.uid._id)
try {
User.findById(mongoose.Types.ObjectId(req.body.uid._id)).then(response => {
console.log('The response object -> ', response) // logs the object
console.log('Type ->', typeof(response)) // logs 'object'
console.log('Value -> ', response.isAdmin) // logs undefined
if(response.isAdmin === true) { // never triggered
res.json({ authorized: true, result: response, message: 'User Authorized' })
} else {
res.json({ authorized: false, message:'User not authorized' })
}
})
} catch (error) {
res.json({ message: 'User not found.', err: error })
}
})
Here is a simplified log of the response.
{
userName: 'Tom Smith',
userId: '0',
comment: 'New Admin test',
isAdmin: true,
}
The problem is the isAdmin value is always undefined so the if condition never gets triggered. If anyone can help me figure out what is going wrong here I'd much appreciate it.
Try with a callback instead of resolving the Promise with then:
app.post('/api/validate', async (req, res) => {
console.log('validating with id -> ', req.body.uid._id);
User.findById(
req.body.uid._id,
(err, user) => {
if (err) return res.json(err);
if (!user) return res.json({ message: 'User not found.' });
console.log('The response object -> ', user); // logs the object
console.log('Type ->', typeof user); // logs 'object'
console.log('Value -> ', user.isAdmin); // logs undefined
if (user.isAdmin === true) {
// never triggered
res.json({
authorized: true,
result: user,
message: 'User Authorized',
});
} else {
res.json({ authorized: false, message: 'User not authorized' });
}
}
);
});
Related
I have a function and I want to test it using Jest.
function handleRegister() {
return (req, res) => {
try {
const credentials = {
login: req.body.email,
password: req.body.password
}
res.status(201).send({ msg: 'User registration achieved successfully' }) //LINE 10
res.status(201).send({ msg: 'User registration achieved successfully' }) //LINE 11
auth.register(credentials, (err, result) => {
console.log('register', auth.getUsers())
if (result.status === 201) {
res.status(201).send({ msg: 'User registration achieved successfully' }) //LINE 17
console.log('User registration achieved successfully')
}
})
} catch(err) {
}
}}
My test code is:
test('should return status 201 and msg', done => {
try {
const fun = handlers.handleRegister()
const res = {
status: jest.fn().mockReturnThis(),
send: function () {
done()
}
}
fun({ body: { email: 'a', password: 'a' } }, res)
expect(res.status).toBeCalledWith(201)
} catch(err) {
done(err)
}
})
The problem is that function handlerRegister line 10 and 11 is correctly executed, but at line 17 I got an error:
/home/anna/Desktop/dev/exampleShop/backend/handlers.js:149
res.status(201).send({
^
TypeError: Cannot read property 'send' of undefined
at auth.register (/home/anna/Desktop/dev/exampleShop/backend/handlers.js:149:26)
at addAccountToDB (/home/anna/Desktop/dev/exampleShop/backend/auth.js:69:7)
at addAccountToDB (/home/anna/Desktop/dev/exampleShop/backend/auth.js:81:3)
at hashPassword (/home/anna/Desktop/dev/exampleShop/backend/auth.js:68:5)
at AsyncWrap.crypto.scrypt (/home/anna/Desktop/dev/exampleShop/backend/auth.js:87:5)
at AsyncWrap.wrap.ondone (internal/crypto/scrypt.js:43:48)
If I use js, not a mock in property res, like:
const res = {
status: function(){return this},
send: function () {
done()
}
}
}
then I don't have this error.
Can someone explain me what is wrong?
There is a scoping issue. res is not defined where you are calling res.send(), because res is being defined inside of the try block.
Either move your expect statement inside of the try like below, or define res in the same scope as your expect statement.
Also you can't call .toBeCalledWith on a function that is not a mocked function. So notice that I have defined res.send to be a mock function, and instead calling done() at the end of your expect statements.
test('should return status 201 and msg', done => {
try {
const fun = handlers.handleRegister()
// res only exists inside of the `try`
const res = {
status: jest.fn().mockReturnThis(),
send: jest.fn() // << is now a mock function
}
fun({ body: { email: 'a', password: 'a' } }, res)
expect(res.status).toBeCalledWith(201)
// here `res.send` is now defined, and you can use `toBeCalledWith`
expect(res.send).toBeCalledWith({ msg: 'User registration achieved successfully' })
done();
} catch(err) {
done(err)
}
})
Checking login id's are existing or not in couchbase database using node js.
getting error like TypeError: Cannot read property '$exists' of undefined
I tried with only one condition means IF condition it is working fine but i try else condition means it will through error kindly help some one.
exports.login = function (req, res) {
var socialdata = {socialId: req.body.socialId,logintype:req.body.logintype}
if (socialdata) {
users.find(socialdata, function (reqs, result) {
if (result.length > 0) {
jwt.sign(socialdata, process.env.secret, { expiresIn: '300000s' }, (err, token) => {
res.status(200).json({ status: 'success', msg: 'Login Successfully...!', resCode: 200, login_token: token, });
});
} else {
res.status(201).json({ status: 'success', msg: 'Welcome to Orange', resCode: 201 });
}
});
}else {
var userdata = {phonenumber: req.body.phonenumber,logintype: req.body.logintype}
users.find(userdata, function (reqs, results) {
if (results.length > 0) {
jwt.sign(userdata, process.env.secret, { expiresIn: '300000s' }, (err, token) => {
res.status(200).json({ status: 'success', msg: 'mobile Successfully...!', resCode: 200, login_token: token, });
});
} else {
res.status(201).json({ status: 'success', msg: 'Welcome to Orange', resCode: 201 });
}
});
}
if request comes from social means it will be checking if condition otherwise it will check else condition. kildly help i'm new to node js
I'm trying to validate a user email by decoding a JWT token given as parameter in a GET request.
In case the token is valid and the User is not verified yet, I want to update isVerified column to true.
Why is my Promise always rejected ?
const jwt = require('jsonwebtoken');
const request = require('request');
const models = require('../models');
/**
* GET /verify-email/:token
*/
exports.verifyEmail = function(req, res) {
jwt.verify(req.params.token, process.env.TOKEN_SECRET, function(err, decoded) {
if (err) {
res.send({
msg: 'Token is invalid or has expired'
})
}
models.User.findOne({
where: {
email: decoded.email,
id: decoded.id
}
}).then(record => {
if (!record) {
res.send({
msg: 'User not found'
})
} else if (record.isVerified) {
res.send({
msg: 'User already verified'
})
} else {
console.log('user mail ' + record.email + ' will be verified in db')
record.update({
isVerified: true,
})
.then(() => res.status(200).send({
msg: 'User has been verified'
}))
.catch((error) => res.status(400).send(error));
}
})
});
}
Problem solved, I had a beforeValidation hook in my model :
if (!user.changed('password')) {
return sequelize.Promise.reject("not modified");
}
I am running tests for signin controller, it keeps giving the wrong status code (401) instead of 200 as i programmed it to be.
I expect it to use the data stored when a user signs up and return it if the given input is correct.
It works perfectly in postman but as i am writing tests, it throws the 401 error.
It is like it does not find the user
This is test block for the sign in:
it('it should signin a new user', (done) => {
request(app)
.post('/api/users/signin')
.send({
username: "Charles",
password: "challenger",
})
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
done()
});
});
This is my controller for Logging in:
signin(req, res) {
const username = req.body.username.toLowerCase().trim();
// const email = req.body.email.trim();
if(!username) {
return res.status(401)
.send(
{status: false,
message: "Username cannot be empty"
});
}
else if (!req.body.password) {
return res.status(401)
.send({
status: false,
message: "Password field cannot be empty"
});
}
return User.findOne({
where: {
username,
}
})
.then((user) =>{
if(!user) {
return res.status(401).send({message: "User is not registered"})
}
else if(!user.validPassword(req.body.password)){
return res.status(401)
.send({
message: "The password is incorrect"
})
}
const token = user.generateAuthToken();
res.header('x-auth', token).status(200).send({
statusCode: 200,
message: `Welcome back, ${user.username}`,
user
});
})
.catch(error => {return res.status(400).send(error)})
},
This is the error i get:
1) Testing API routes POST /api/users/ it should signin a new user:
Error: expected 200 "OK", got 401 "Unauthorized"
at Test._assertStatus (node_modules\supertest\lib\test.js:266:12)
at Test._assertFunction (node_modules\supertest\lib\test.js:281:11)
at Test.assert (node_modules\supertest\lib\test.js:171:18)
at Server.assert (node_modules\supertest\lib\test.js:131:12)
at emitCloseNT (net.js:1552:8)
at _combinedTickCallback (internal/process/next_tick.js:77:11)
at process._tickCallback (internal/process/next_tick.js:104:9)
I would put a bunch of console.log() in there to see exactly which code is firing since you have 4 chances to fire the 401.
Here is some code for you to examine:
// I don't understand enough context, so I have to re-write this
// to show you how it could be an async function which will
// return a promise, but will also allow you to await.
// async function sign(req, res) {
const sign = async (req, res) => { // This is same as above line
const username = req.body.username.toLowerCase().trim();
// const email = req.body.email.trim();
if (!username) {
console.log('username was empty')
return res.status(401).send({
status: false,
message: "Username cannot be empty"
});
}
if (!req.body.password) {
console.log('password was empty')
return res.status(401).send({
status: false,
message: "Password field cannot be empty"
});
}
return await User.findOne({ where: { username } })
// I'm making this one async also to ensure user.generateAuthToken()
// has a value before it proceeds to res.send()
.then(async (user) => {
if (!user) {
console.log('couldnt find user')
return res.status(401).send({
message: "User is not registered"
})
}
else if (!user.validPassword(req.body.password)){
console.log('password was incorrect')
return res.status(401).send({
message: "The password is incorrect"
})
}
const token = await user.generateAuthToken();
// I added a return here
return res.header('x-auth', token).status(200).send({
statusCode: 200,
message: `Welcome back, ${user.username}`,
user
});
})
.catch((error) => {
console.log('lets put data in here: ' + error)
return res.status(400).send(error)
})
},
I notice the MongoDB search User.findOne({ where: { username } }). I can't remember if it needs to be $where. I think MongoDB syntax uses a $. That could be your problem, and it will fire that console.log('couldnt find user') if so. That might be only for native MongoDB driver. I just Googled and found that the syntax could also be: User.findOne({ username }) which is shorthand for User.findOne({ username: username }).
Some people will tell you it is redundant to do return await fn() and omit the await, but it will throw an unhandled promise rejection if the promise is rejected. It will be caught if await is there. This is part of the upper scope's error handling architecture.
I recommend watching some async/await tutorials, because I see you mixing in a little bit of callback sauce. Your code is pretty good, but I think you can take it to the next level. It looks like you're ready.
Fun fact, you can also omit { and } if your if statement only has one expression, ie:
if (err) {
throw err;
}
can be shorthand:
if (err) throw err;
This can go a long way to help clean up the code, but async/await syntax with try/catch blocks used properly along with throw will do incredible improvements to synchronous looking code with minimal nesting.
Here is how you could re-write some of this, because I want to show you how we can get rid of nesting that adds confusion to your flow control:
const sign = async (req, res) => {
try {
const username = req.body.username.toLowerCase().trim()
if (!username) throw 'noUsername'
if (!req.body.password) throw 'noPassword'
const foundUser = await User.findOne({ username })
if (!foundUser.username) throw 'notFound'
// I assume this returns Boolean
const validPassword = await user.validPassword(req.body.password)
if (!validPassword) throw 'invalidPassword'
// Alter generateAuthToken() to throw 'badToken' if it fails
const token = await user.generateAuthToken()
return res.header('x-auth', token).status(200).send({
statusCode: 200,
message: `Welcome back, ${user.username}`,
user
})
} catch (error) {
// errors are manually thrown into here, and rejected promises
// are automatically thrown into here
if (error === 'noUsername') return res.status(401).send({
status: false,
message: 'Username cannot be empty'
})
if (error === 'noPassword') return res.status(401).send({
status: false,
message: 'Password field cannot be empty'
})
if (error === 'notFound') return res.status(401).send({
message: 'User is not registered'
})
if (error === 'invalidPassword') return res.status(401).send({
message: 'The password is incorrect'
})
if (error === 'badToken') return res.status(403).send({
message: 'User is not authorized'
})
return res.status(400).send(error)
}
}
sign(req, res).then((response) => console.log(response))
Hopefully, this has been helpful :) and sorry I don't use semi-colons.
I have an async function
async function getPostAsync() {
const post = await Post.findById('id');
// if promise was successful,
// but post with specific id doesn't exist
if (!post) {
throw new Error('Post was not found');
}
return post;
}
I am calling the function with
app.get('/', (req, res) => {
getPostAsync().then(post => {
res.json({
status: 'success',
});
}).catch(err => {
res.status(400).json({
status: 'error',
err
});
})
});
but I just receive
{
"status": "error",
"err": {}
}
I would expect to either get the error Post was not found or some error with the connection or something like that, but the variable err is simply an empty object in my catch statement.
Consider the following:
let e = Error('foobar');
console.log( JSON.stringify(e) )
This outputs {}, much like in your case. That's because errors don't serialize to JSON very well.
Instead, try this:
res.status(400).json({
status : 'error',
err : err.message // `String(err)` would also work
});