below is my Accounts.js Module.
var Accounts = function(){
return{
registerNewUser : function(req,res){
console.log(req.body);
var email = req.body.email;
var password = req.body.password;
if(email === undefined || password === undefined){
res.status(400).end('Required Fields Missing');
}
else{
email = email.trim();
password = password.trim();
console.log('lengths = ', email.length, ' password length = ', password.length);
if(email.length <= 0 || password.length <= 0){
res.status(400).end('Bad Request');
}
else{
res.status(200).end('ok');
}
}
}
}
}
module.exports = new Accounts();
Mocha UnitTests.js
var request = require('supertest');
var app = require('../express-app');
describe('Testing Route to Register New User', function(){
var server;
beforeEach(function(){
server = app.startServer();
});
afterEach(function(done){
server.close();
done();
});
it('Missing required fields test', function(done){
request(app).post('/register',{
}).expect(400).end(done);
}) ;
it('Empty field test',function(done){
request(app).post('/register',{
email:"",
password:" "
}).expect(400).end(done);
});
it('Should accept the correct email and password',function(done){
request(app).post('/register',{
email:"email",
password:"alskdjfs"
}).expect(200).end(done);
});
});
Mocha Output:
Testing Route to Register New User
API Server listening on port 3000
{}
✓ Missing required fields test
API Server listening on port 3000
{}
✓ Empty field test
API Server listening on port 3000
{}
1) Should accept the correct email and password
2 passing (65ms)
1 failing
1) Testing Route to Register New User Should accept the correct email and password:
Error: expected 200 "OK", got 400 "Bad Request"
at Test._assertStatus (node_modules/supertest/lib/test.js:232:12)
at Test._assertFunction (node_modules/supertest/lib/test.js:247:11)
at Test.assert (node_modules/supertest/lib/test.js:148:18)
at Server.assert (node_modules/supertest/lib/test.js:127:12)
at emitCloseNT (net.js:1521:8)
I have tested the above route using curl cli and it works as expected , similarly it works as expected from the browser form post , i do not know why mocha fails it ?
Can some one please throw light where i am doing wrong to fix this issue.
Regards
You are probably sending the data in a wrong way. Try this
it('Should accept the correct email and password',function(done){
var data = {
email:"email",
password:"alskdjfs"
};
request(app).post('/register').send(data).expect(200).end(done);
});
Related
My backend gets a request to get records from an Azure SQL db. To manage this requests I'm using Express in Nodejs, and Tedious (to connect to DB). When the request to the appropriate route comes in, Tedious opens the connection with db, queries it, and it should send the response back to frontend.
However, the code responds before I have an answer with from the db, and thus when I go to send the real (the actually desired) response, Express tells me it already sent headers back (the dreaded: 'Cannot set headers after they are sent to the client').
After debugging quite a bit (using several console.log(JSON.stringify(resp.headersSent)); ) to see when was the response actually sent, I noticed that it's sent the moment I connect with Azure (see below).
I'm not sure if I'm missing something (though I already checked the documentation for all those programs quite a bit), but how can I control when the response is sent? Or, is there another way of doing this.
I omitted several of the other routes for brevity. Other routes work fine and thus I know code connects well to Azure db, and frontend does query backend correctly. Help is appreciated. Thank you.
const express = require('express');
const cors = require('cors');
const Connection = require('tedious').Connection;
const Request = require('tedious').Request;
const config = {
authentication: {
options: {
userName: "xxxx",
password: "xxxx"
},
type: 'default'
},
server: "xxxx",
options: {
database: "xxxx",
encrypt: true
}
};
const app = express();
app.use(express.json({type: '*/*'}));
app.use(cors({ origin: '*' }));
app.get("/allproj/", function (req, resp) {
const q = `select Title, Report_Date, Project_Number, Phase_Code, Items_No, PId from projec order by PId desc`;
let ansf = [];
const connection = new Connection(config);
connection.on('connect', (err, connection) => {
if (err) {
console.log(err);
} else { //this is the moment the headers are sent,
//seemingly with positive response from connection
queryItems(q);
}
});
queryItems = (q) => {
request = new Request(q, function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows pulled');
connection.close();
}
});
request.on('row', function(columns) {
let ans = [];
columns.forEach(function(column) {
ans.push(column.value);
if (ans.length === 6) { // I know each row is 6 cols long
ansf.push(ans);
ans = [];
}
});
console.log('ansf length: ' + ansf.length);
resp.send({ ansf }); // This is the response I would like to return
});
request.on('done', function(rowCount) {
console.log(rowCount + ' rows returned');
connection.close();
});
connection.execSql(request);
};
resp.redirect("/");
});
app.listen(3000, process.env.IP, function() {
console.log("Started OK...");
});
Remove resp.redirect("/");
As it is already transferring your request to "/" and when control come at resp.send({ansf}), It gives you error.
I have an angular app and a nodejs backend server. I want to get data from my backend but when I try to connect to it with Angular HTTPClient, it says: POST http://localhost:3000/login/aa/aa 404 (Not Found).However, when I put the link manually into the browser, it works perfectly fine. Here is some code:
service.ts
addUser(user: IUser): Observable<IUser> {
return this.httpClient.post<IUser>(`http://localhost:3000/login/${user.email}/${user.passwort}`, user, {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
})
.pipe(catchError(this.handleError));
}
index.js
var mysql = require('mysql');
var express = require('express');
var app = express();
const port = process.env.PORT || 3000;
[...]
app.get('/login/:email/:pw',function(req,res) {
res.setHeader('Content-Type', 'application/json');
var passwort = new Passwort(''+req.params.pw);
passwort.comparePasswort();
con.query("SELECT u.Email, u.Hash FROM User u WHERE u.Email LIKE "+ "'" + req.params.email+ "'", function(err, result ){
if(err) throw err;
console.log(result)
res.send("test")
})
});
Thanks for every answer and for your time!
Your route in your backend is set as a get request and not a post request.
You should either convert your request to a get in your service with this.httpClient.get... or convert to a post request in your backend with app.post.
The reason it works in your browser is that the browser performs a GET request when acessing something using the address bar.
In backed you declared a get method and from frontend you are calling post. your code in service should be :-
addUser(user: IUser): Observable<IUser> {
return this.httpClient.get<IUser>(`http://localhost:3000/login/${user.email}/${user.passwort}`, {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
})
.pipe(catchError(this.handleError));
}
before using /:email you need to subscribe this particular element
const mongoose = require("mongoose");
const User = mongoose.model("User");
const userParams = (req, res, next, email) => {
User.findOne({email:email})
.then((user)=> {
if (!user) {
return res.sendStatus(404);
}
req.user = user;
return next();
})
.catch(next);
};
module.exports = userParams;
then use that in express router by typing
router.param("email", userParams);
this way your router will get to know what the params you are trying to send
In your index.js file, you are creating a handler for a GET request (which is the default request sent by your browser while accessing your webpage)
But in your service.ts file you are trying to send a post request to the server which is not handled, so the simple solution would be to replace the line
return this.httpClient.post<IUser> `http://localhost:3000/login/${user.email}/${user.passwort}`, user, {
with:
return this.httpClient.get<IUser> `http://localhost:3000/login/${user.email}/${user.passwort}`, user, {
For more info you can read this: https://angular.io/guide/http
My tests gives random results on Travis. Here are the logs where my tests did fail on Travis:
https://travis-ci.org/superzaky/node-portfolio-zaky/builds/149718369
And here are the logs where my tests did pass on Travis:
https://travis-ci.org/superzaky/node-portfolio-zaky/builds/149560005
Both branches contain the exact same code.
And on my computer I can also make the tests pass link to screenshot: http://i.imgur.com/zXOINsD.png
I had also cloned my repository on my laptop. And there the tests also pass.. I suspect it has something to do with the way I had written
my tests in 100-Login.js:
require('../utils');
require('events').EventEmitter.prototype._maxListeners = 100;
var supertest = require("supertest");
var should = require("should");
var assert = require('chai').assert;
var app = require('../../app');
// This agent refers to PORT where our program is running.
var server = supertest.agent(app);
// UNIT test begin
describe("A user logs in", function () {
it('should create a SINGLE session on /api/auth/login POST', function (done) {
//calling LOGIN api
server
.post('/api/auth/login')
.send({
username: "jimmy",
password: "open"
})
.expect("Content-type", /json/)
.expect(200)
.end(function (err, res) {
var data = {
_id: "000000000000000000000001",
name: "Jimmy Doe",
username: "jimmy",
admin: false
};
res.status.should.equal(200);
assert.deepEqual(res.body, data);
done();
});
});
it('should display a SINGLE session on /api/auth/ GET', function (done) {
//We check if a session is created by sending a GET request to /api/auth
server
.get('/api/auth/')
.expect("Content-type", /json/)
.expect(200)
.end(function (err, res) {
var data = {
_id: "000000000000000000000001",
name: "Jimmy Doe",
username: "jimmy",
admin: false
};
res.status.should.equal(200);
assert.deepEqual(res.body, data);
done();
});
});
it('should delete a SINGLE session on /api/auth/logout GET', function (done) {
//We check if a session is created by sending a GET request to /api/auth
server
.get('/api/auth/logout')
.expect("Content-type", /json/)
.expect(200)
.end(function (err, res) {
var data = "Successfully logged out";
res.status.should.equal(200);
assert.deepEqual(res.body, data);
done();
});
});
it('should NOT display a SINGLE session on /api/auth/ GET', function (done) {
//We check if a session is created by sending a GET request to /api/auth
server
.get('/api/auth/')
.expect("Content-type", /json/)
.expect(404)
.end(function (err, res) {
var data = "Session not found";
res.status.should.equal(404);
assert.deepEqual(res.body, data);
done();
});
});
});
require('events').EventEmitter.prototype._maxListeners = 0;
And here is the actual code that made the tests pass link: https://github.com/superzaky/node-portfolio-zaky/blob/travis/controllers/AuthController.js
But that looks fine to me. Anyone that maybe has a clue on how to fix this problem?
You should check what's in your local database.
Based on your other tests, which initially register a user with username = john (see this test, line 20), there will be no user with username = jimmy, which is what you use as the username credential when POSTing to /api/auth/login in the test that fails (see this test, line 18).
The tests that pass on your local machine probably pass because you also have a user named "jimmy" in your local db.
As far as why the second test fails, it fails because the session creation test fails right before it and it is expecting a session to exist for "jimmy".
I am following this tutorial to host a Rest API at my openshift account:
Day 27: Restify–Build Correct REST Web Services in Node.js
As per my requirements I made few changes, below is the code:
server.js
var restify = require('restify');
var mongojs = require('mongojs');
var ip_addr = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
var port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var server = restify.createServer({name: 'bemeta'});
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.use(restify.CORS());
server.listen(port, ip_addr, function(){
console.log(server.name + ' listening at url ' + server.url);
});
var connectionString = '127.0.0.1:27017/bemeta';
if(process.env.OPENSHIFT_MONGODB_DB_PASSWORD){
connectionString = process.env.OPENSHIFT_MONGODB_DB_USERNAME + ':' +
process.env.OPENSHIFT_MONGODB_DB_PASSWORD + '#' +
process.env.OPENSHIFT_MONGODB_DB_HOST + ':' +
process.env.OPENSHIFT_MONGODB_DB_PORT + '/' +
process.env.OPENSHIFT_APP_NAME;
}
var db = mongojs(connectionString, ['bemeta']);
var beRecords = db.collection("be_records");
var PATH = '/be_records';
// get all records
server.get({path: PATH, version:'0.0.1'}, findAllRecords);
// create new record
server.post({path: PATH, version:'0.0.1'}, createRecord);
// defining call backs
function findAllRecords(req, res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
beRecords.find(function(err, docs){
console.log('Response docs ' + docs);
console.log('Error '+ err);
if(docs){
res.send(200, docs);
return next();
}
return next(err);
});
}
function createRecord(req, res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
var beRecord = {};
beRecord.be_id = req.params.be_id;
beRecord.item_title = req.params.item_title;
beRecord.item_description = req.params.item_description;
beRecord.item_link = req.params.item_link;
beRecords.save(beRecord, function(err, docs){
console.log('Response docs ' + docs);
console.log('Error '+ err);
if(docs){
res.send(201, beRecord);
return next();
}
else {
next(err);
}
});
}
When I run it at local and fire a get request via postman by typing below url:
http://127.0.0.1:8080/be_records
I get response as: [], which is correct since I have not inserted any document in respective collection.
But when I run it at my openshift account and fire a get request via postman by typing below url:
http://bemeta-{domain-name}.rhcloud.com/be_records
I get response as:
{
"code": "InternalError",
"message": "auth fails"
}
In my rhc console I see below messages:
==> app-root/logs/mongodb.log <==
Wed Feb 24 01:32:23.543 [conn3] authenticate db: bemeta { authenticate: 1, user: "admin", nonce: "some nonce", key: "some key" }
Wed Feb 24 01:32:23.544 [conn3] auth: couldn't find user admin#bemeta, bemeta.system.users
I am not sure why is it trying to find user - admin#bemeta, might be I am missing something over here, I do not have any such user but I do have an admin user which is used to connect to mongodb.
Here is the snapshot of my db (as shown in RockMongo):
Any ideas?
The auth error was caused by not having the admin user authenticated for accessing the bemeta database (see question comments above for details).
Users can be authenticated using the RockMongo interface as follows:
Select a DB -> More -> Authentication -> Add user.
I'd like permit any socket connection to my server but in the case the client connects without specifying a 'username' in socket.handshake.query, I want to just let him create a new account and then the server should automatically disconnect him.
The only way I could achieve it was validating socket.handshake.query on every event except the signUp event -this means runing validateQuery() on almost every event!-. I feel that this may be a very rough way. I have also tryed to implement this with middleware but I was not able to achieve the desired behaviour (I'm pretty new to Node).
This is my code, please tell me if you know a better way to implement this :)
NOTE: A session handler is not mandatory for this case.
'use strict';
/*** BASE SETUP: Main objects & Dependencies */
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io');
// Set port in which the server will listen
var port = process.env.PORT || 3000;
// Start servers (HTTP is temporal and just for personal tests...)
var io = io.listen(server);
server.listen(port, function() {
console.log('>> Express server listening on port ' + port + ' <<');
});
/*
* A dummy socket validation function.
*/
var validateQuery = function(socket, next) {
console.log("> Verifying username...");
if ( typeof socket.handshake.query.username === 'undefined' || socket.handshake.query.username === "" ) {
console.log("-> Authentification failed!");
socket.disconnect();
return next(new Error("{ code: 403, description: 'You must specify a username in your query' }"));
}
};
/*** SOCKET IO Events */
io.sockets.on('connection', function(socket) {
console.log("> New connection stablished: "+ socket.id);
// # Disconnect
//
socket.on('disconnect', function() {
// clients.splice(clients.indexOf(socket.id), 1);
console.log("> Triggered 'Disconnect' # " + socket.id);
});
// # SignUp - Creates new users
//
socket.on('signUp', function( requestData ) {
console.log("> Triggered 'signUp' # " + socket.id);
socket.emit('onSignUp', { username : requestData.username, dsp : requestData.dsp });
socket.disconnect();
});
// # getUserList - Gets a list of all registered users
//
socket.on('getUserList', function( requestData ) {
// Validate query
validateQuery(socket);
// Send the user's list
socket.emit( 'onGetUserList', userList );
});
// # getUserProfile - Gets a user's profile. Will return the requester's profile if none specified
//
socket.on('getUserProfile', function( requestData ) {
// Validate username
validateQuery(socket);
var userProfile = { username : "User1", dsp : "Ron" };
socket.emit('onGetUserProfile', userProfile);
});
});
If you want to allow the connection without the auth, but then only allow some events to be processed if they are not authenticated, then you will have to check validation on every event that requires auth. There's no other way around it if you're going to allow some events through without auth.
You could make the auth check a little simpler though. When the socket first connects, you couuld do the validation and then set a custom flag on the socket object. From then on, you can just check that flag if an event requires auth (which should be a little more efficient).
If any follow on events might change the auth status, you can then update the flag.
You could also make some shortcuts for your event handlers that require auth.
function addAuthEventListener(sock, event, fn) {
sock.on(event, function (data) {
if ( typeof sock.handshake.query.username === 'undefined' || sock.handshake.query.username === "" ) {
sock.disconnect();
} else {
return fn.apply(this, arguments)
}
});
}
So, then any event handler that requires auth could just be installed like this:
addAuthEventListener(socket, 'onGetUserList', function(requestData) {
// Send the user's list
socket.emit( 'onGetUserList', userList );
});
And the auth checks would happen automatically.