Here Hapi Lab why Test failed when all the tests are passed why the test is failed.
In this new question why I get The following leaks were detected:lr even if there is no global var in the code.
Running this simple test
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
lab.experiment('Users', function () {
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload:{
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var token = response.result.token;
var payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
done();
});
});
});
2 tests complete
Test duration: 363 ms
The following leaks were detected:lr
but I don't see any lr var !
and the strange is if I run this
payload.passdword
instead of
payload.password
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
lab.experiment('Users', function () {
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload:{
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
passdword: 'mysecret'
}
};
server.inject(options, function(response) {
var token = response.result.token;
var payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
done();
});
});
});
I've got
1 of 2 tests failed
Test duration: 73 ms
No global variable leaks detected
with no warning about lr var.
So I don't know which way to turn :(
Can help me, please ?
UPDATE
controller
'use strict';
/**
* Module dependencies.
*/
var BcryptUtil = require('../utils/bcrypt');
var JwtUtil = require('../utils/jwt');
var Models = require('../models');
var ReplyUtil = require('../utils/reply');
var User = Models.users;
exports.create = function create(request, reply) {
var params = request.payload;
params.password = BcryptUtil.generateHash(params.password);
params.roles =JSON.stringify(['user']);
User
.create(params)
.then(function(user) {
var token = JwtUtil.getUserToken(user);
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.set('user_'+user.userId, token);
return reply(ReplyUtil.ok(token)).created('/api/users/' + user.userId);
})
.catch(function(err){
if(err instanceof Models.Sequelize.ValidationError){
return reply(ReplyUtil.badData(err,params));
}
return reply(ReplyUtil.badImplementation(err));
});
};
exports.findAll = function (request, reply) {
User
.findAll({
order: [['createdAt','DESC']],
attributes: ['userId', 'firstname', 'lastname', 'username', 'email']
})
.then(function(users) {
return reply(ReplyUtil.ok(users));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.findById = function (request, reply) {
var userId = request.params.userId;
User
.findById(
userId,
{
attributes: ['userId', 'firstname', 'lastname', 'username', 'email']
})
.then(function(user) {
if(!user){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(user));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.update = function (request, reply) {
var userId = request.params.userId;
var params =request.payload;
User
.update(params,{
where: {
userId: userId
}
})
.then(function(rows) {
var affectedRows = rows.pop();
if(!affectedRows){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(affectedRows));
})
.catch(function(err){
if(err instanceof Models.Sequelize.ValidationError){
return reply(ReplyUtil.badData(err,params));
}
return reply(ReplyUtil.badImplementation(err));
});
};
exports.destroy = function (request, reply) {
var userId = request.params.userId;
User
.destroy({
where: {
userId: userId
}
})
.then(function(rows) {
if(!rows){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(rows));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.signIn = function (request, reply) {
var params = request.payload;
User
.findOne({
where: {
email: params.email
}
})
.then(function(user) {
if(!user){
return reply(ReplyUtil.invalidPassword());
}
if(BcryptUtil.authenticate(params.password, user.password)){
var token = JwtUtil.getUserToken(user);
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.set('user_'+user.userId, token);
return reply(ReplyUtil.ok(token));
}
return reply(ReplyUtil.invalidPassword());
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.logOut = function (request, reply) {
var userId = request.auth.credentials.jti;
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.del('user_'+userId);
return reply();
};
exports.methodNotAllowed = function (request, reply) {
return reply( ReplyUtil.methodNotAllowed() );
};
route
'use strict';
/**
* Module dependencies.
*/
var User = require('../controllers/users');
var Validator = require('../validations/users');
/**
* Resource configuration.
*/
var internals = {};
internals.resourcePath = '/users';
module.exports = function() {
return [
{
method: 'POST',
path: internals.resourcePath,
config : {
handler: User.create,
validate: Validator.create
}
},
{
method: 'GET',
path: internals.resourcePath,
config : {
handler : User.findAll,
auth: {
strategy: 'token',
scope: ['admin']
}
}
},
{
method: 'GET',
path: internals.resourcePath + '/{userId}',
config : {
handler : User.findById,
validate: Validator.findById,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'PUT',
path: internals.resourcePath + '/{userId}',
config : {
handler: User.update,
validate: Validator.update,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'DELETE',
path: internals.resourcePath + '/{userId}',
config : {
handler: User.destroy,
validate: Validator.destroy,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'POST',
path: internals.resourcePath + '/signin',
config : {
handler: User.signIn,
validate: Validator.signIn
}
},
{
method: 'GET',
path: internals.resourcePath + '/logout',
config : {
handler : User.logOut,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: '*',
path: internals.resourcePath + '/{somethingss*}',
config : {
handler: User.methodNotAllowed
}
}
];
}();
I no I am a little late, but just in case anyone else has this problem. It's a problem with bcrypt. I had a similar problem where whenever I used bcrypt-nodejs it would give me The following leaks were detected:lr, password, but when I changed to reqular bycrypt it worked with no leaks. Try updating your bycrypt version.
Just add all leakimg elements to ignore list
"test": "lab -c -L -I 'Reflect,core,_babelPolyfill,regeneratorRuntime,__core-js_shared__ css'",
Related
today i trying to get some file upload with Hapi Js, i follow all Google Result with similarity of code.
this the code :
server.route({
method: "POST",
path: `${PUBLIC_URL}${THEME_URL}/create`,
handler: async (request: any, reply: ResponseToolkit) => {
console.log(request.payload.file, 'payload')
return reply.response(request.payload)
},
options: {
payload: {
output: 'stream',
allow: 'multipart/form-data',
parse: false,
}
}
})
with thats code i cant get request.payload my file or data, this is my request with postman:
post file with postman
enter image description here
i got undifined at request.payload.file
if i turn payload :{parse:true} i get unsuported media types
thanks for attention
If you are using the below version then you must be using the following syntax
#hapi/hapi: 18.x.x +
payload: {
parse: true,
multipart: {
output: 'stream'
},
maxBytes: 1000 * 1000 * 5, // 5 Mb
}
Also, you can also try using Joi to validate your payload.
{
method: 'POST',
path: '/upload',
options: {
payload: {
maxBytes: 209715200,
output: 'stream',
parse: true,
allow: 'multipart/form-data',
multipart: true // <-- this fixed the media type error
},
handler: async (req, reply) => {
try {
// await importData(req.payload)
// return reply.response("IMPORT SUCCESSFULLY")
const data = await req.payload;
// let final = await importFile(data)
// return reply.response("final", final)
if (data.file) {
let name = await data.file.hapi.filename;
console.log("FIlename: " + name);
let path = await __dirname + "/uploads/" + name;
let file = await fs.createWriteStream(path);
await data.file.pipe(file);
await data.file.on('end', async function (err) {
// var ret = {
// filename: data.file.hapi.filename,
// headers: data.file.hapi.headers
// }
if (typeof require !== 'undefined')
XLSX = require('xlsx');
const workbook = await XLSX.readFile(path);
var sheetName = workbook.SheetNames;
console.log("row======>>>>");
await sheetName.forEach(async () => {
let xlData = await XLSX.utils.sheet_to_json(workbook.Sheets[sheetName[0]]);
console.log("xlData", xlData);
for (let i = 0; i < xlData.length; i++) {
console.log("if condition", xlData[i].phone)
const userCheck = await getUserIdService({ where: { phone: xlData[i].phone } });
console.log("userCheck", userCheck.data)
console.log("test", !(userCheck.data === null));
if (!(userCheck.data === null)) {
console.log("finally ", userCheck.data?.phone)
await uploadUpdateService(xlData[i], { where: { phone: userCheck.data?.phone } });
// return finalUpdate
// return reply.response("updated")
}
else if (!xlData[i].customerID) {
await uploadCreate(xlData[i]);
// return finalCreate
}
}
})
})
}
} catch (err) {
console.log('Err----------------------' + err);
// error handling
return reply.response(Boom.badRequest(err.message, err))
// return reply.response(Boom.badRequest(err.message, err));
}
}
}
}
Main objective:
On call to route I either get a new or update existing CartItem object.
The Object amount and total are passed in the middleware so the object total gets recalculated.
The Schema seems to properly apply its middleware properly on the first request (based on the console logs).
However I only get an object with the updated total if I make another http request.
This is beyond my understanding and I would appreciate some assistance.
Schema:
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Product = require('./Product');
const Cart = require('./Cart');
const refIsValid = require('../middleware/refIsValid');
const cartItemSchema = mongoose.Schema({
name: { type: String },
productRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
cartRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Cart', required: true },
price: { type: Number, default: 0 },
imgUrl: { type: String },
amount: { type: Number, required: true },
total: { type: Number, default: 0 },
active: { type: Boolean, default: true },
uniqueName: { type: String, unique: true },
});
cartItemSchema.path('productRef').validate((value, respond) => {
return refIsValid(value, respond, Product);
}, 'Invalid product ref.');
cartItemSchema.path('cartRef').validate((value, respond) => {
return refIsValid(value, respond, Cart);
}, 'Invalid cart ref.');
cartItemSchema.path('price').get(function(num) {
return num.toFixed(2);
});
cartItemSchema.pre('save', async function(next) {
const refCart = await Cart.findById(this.cartRef).lean().exec();
const refProduct = await Product.findById(this.productRef).lean().exec();
const uniqueName = `${refProduct._id}_${refCart._id}`;
this.name = refProduct.name;
this.price = refProduct.price;
this.imgUrl = refProduct.imgUrl;
this.total = (this.price * this.amount).toFixed(2);
this.uniqueName = uniqueName;
next();
});
cartItemSchema.post('findOneAndUpdate', async function(result) {
console.log('TCL: result', result);
await result.save(function(err) {
if (err) {
console.error('ERROR!');
}
});
console.log('TCL: docToUpdate', result);
});
cartItemSchema.plugin(uniqueValidator);
module.exports = mongoose.model('cartItem', cartItemSchema);
controller:
static async updateOrCreate(req, res, next) {
try {
let { cartRef, productRef, amount } = req.body;
let options = { upsert: true, new: true, setDefaultsOnInsert: true };
// const uniqueName = `${productRef._id}_${cartRef._id}`;
const updateOrCreate = await CartItem.findOneAndUpdate(
{ cartRef: cartRef, productRef: productRef },
{ amount: amount },
options,
);
if (updateOrCreate) {
const result = await CartItem.findById(updateOrCreate._id);
console.log('TCL: CartItemController -> updateOrCreate -> result', result);
res.status(200).json({
isNew: false,
message: 'item updated',
productItem: result,
});
return;
}
} catch (error) {
error.statusCode = 500;
next(error);
}
}
I am trying to create a model using Sequelize and mysql db.I am trying to post to '/students/register' it keeps giving me an error saying findOne is not a function. I tried requiring my sql but it's not working ..I also tried a different function like findAll and still not working.what seems to be the problem
const Sequelize = require('sequelize');
module.exports = function (sequelize, Sequelize) {
const Stundet = sequelize.define(
'student', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
created: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
}, {
timestamps: false
});
module.exports = Stundet;
}
routes
const Student_Info = require("../models/students")
student.post('/register', (req, res) => {
const dataToday = new Date()
const studentData = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
created: dataToday
}
Student_Info.findOne({
where: {
email: req.body.email
}
})
.then(student => {
if (!student) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
studentData.password = hash
Student_Info.create(studentData)
.then(student => {
res.json({
status: student.email + 'registered'
})
})
.catch(err => {
res.send('error' + err)
})
})
} else {
res.json({
error: 'Student already registered'
})
}
})
.catch(err => {
res.send('error' + err)
})
})
module.exports = student;
When you use module.exports, you should return Stundet. You already export the whole function. And I think you should pass DataTypes instead of Sequelize.
Something like this:
module.exports = function (sequelize, DataTypes) {
const Stundet = sequelize.define(
//...
return Stundet;
}
So in your route in order to use your model:
const Sequelize = require('sequelize');
const DataTypes = sequelize.DataTypes;
let sequelize = new Sequelize(...);
const Student = require('../models/students')(sequelize, DataTypes);
I suspect that your Student_Info is null. Does you application successfully connect to the database? It helps to log... e.g.
sequelizeDB
.authenticate()
.then(() => {
console.log('Yes! DB Connection);
...
})
.catch(err => {
console.error('No! Unable to connect to DB', err);
});
... and IMHO the code reads better when you name the DB instance something other than "sequelize".
sq.js:
var Sequelize = require('sequelize');
var sequelize = new Sequelize('postgres://chandan:duvarko315#localhost:5432/diary');
var User = sequelize.define('user', {
username: {
type: Sequelize.STRING,
field: 'username' // Will result in an attribute that is firstName when user facing but first_name in the database
},
password: {
type: Sequelize.STRING
}
},{
timestamps: false,
});
User.sync({force: true}).then(function () {
// Table created
});
module.exports = User;
app.js:
var seq = require('./routes/sq');
passport.use(new passportLocal.Strategy(function(username,password, done){
User.findOne({username: username}, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null,{ id:username, name:username});
});
}));
I am getting the error: ReferenceError: User is not defined
Its because you have declared the user model as seq in app.js. Change your declaration to:
var User = require('./routes/sq');
The variable Useronly lives in sq.js
So I made up the user domain
and I've done I think a good suite
test it's like this:
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
var Jwt = require('jsonwebtoken');
var Nconf = require('nconf');
var apiConfig = Nconf.get('api');
lab.experiment('Users', function () {
var userId, payload, decoded, token;
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
token = response.result.token;
payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
try {
decoded = Jwt.verify(token, apiConfig.secret);
}
catch(err) {
}
console.log(decoded.scope);
Code.expect(decoded.username).to.equal(payload.username);
Code.expect(decoded.scope).to.be.an.array();
userId = decoded.jti;
done();
});
});
lab.test('create sequelize unique', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(result.message).to.equal('username must be unique');
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update at least one required', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update no password', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId,
payload: {
password: 'mysecret_update'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update not owner', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId +1,
payload: {
firstname: 'Fabio_update'
}
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('update', function (done) {
var updatevalue = Math.random().toString(36).slice(2);
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId,
payload: {
firstname: 'Fabio_'+updatevalue,
lastname: 'Bedini_'+updatevalue,
username: 'whisher_'+updatevalue,
email: 'me_'+updatevalue+'#ilwebdifabio.it'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.equal(1);
done();
});
});
lab.test('findById not owner', function (done) {
var options = {
method: 'GET',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId +1,
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('findById', function (done) {
var options = {
method: 'GET',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.be.instanceof(Object);
Code.expect(Object.keys(result)).to.have.length(8);
done();
});
});
lab.test('destroy not owner', function (done) {
var options = {
method: 'DELETE',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId+1
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('destroy', function (done) {
var options = {
method: 'DELETE',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.equal(1);
done();
});
});
});
now I made up the product domain as well and there
is some routes needed access token.
How can I test the product domain using the 'globals'
var userId, payload, decoded, token;
or what's the way to turn in this case ?
Update
after #Matt Harrison answer
var getToken = function(){
var user = {id:1,username:'abcdefghijklmnopqrstuvwxyz'};
var token = JwtUtil.getUserToken(user).token;
return token;
}
lab.experiment('Product', function () {
lab.test('create', function (done) {
var token = getToken();
console.log(token);
var options = {
method: 'POST',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/products',
payload: {
title: 'myproduct'
}
};
server.inject(options, function(response) {
var result = response.result;
console.log(result);
Code.expect(response.statusCode).to.equal(200);
// Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
});
it workish I've an other problem
with
CONSTRAINT products_ibfk_1 FOREIGN KEY (userId) REFERENCES users
(id) ON UPDATE CASCADE) stack: Error: ER_NO_REFERENCED_ROW
Not sure I have understood your question correctly but I think you're asking:
How do I have shared state between lab experiments?
The simple answer is to move var userId, payload, decoded, token; into the upper "global" scope so they can be accessed everywhere.
However my advice is don't do this. Your test cases should be independent from each other. You should be able to add tests, reorder them and remove them without it affecting other test cases. Otherwise you're creating a maintenance nightmare for yourself.
If you need a resource in multiple test cases, just create a new one for each test:
lab.test('test the thing', function (done) {
var token = getToken();
expect(token).to.equal(...);
});
lab.test('test the other thing', function (done) {
var token = getToken();
expect(token).to.equal(...);
});
If you need to change a resource and then test something, that's a single test case:
lab.test('change something and then test it', function (done) {
var token = getToken();
token.prop = 'value';
expect(token.prop).to.equal('value');
});