express-user
Version:
Ressource Oriented Express Middleware to Manage Users.
532 lines (506 loc) • 33.3 kB
JavaScript
//Copyright (c) 2015 Eric Vallee <eric_vallee2003@yahoo.ca>
//MIT License: https://raw.githubusercontent.com/Magnitus-/ExpressUser/master/License.txt
var Nimble = require('nimble');
var Express = require('express');
var Http = require('http');
var ExpressUser = require('../lib/ExpressUser');
var UserProperties = require('user-properties');
var UserStore = require('user-store');
var MongoDB = require('mongodb');
var Session = require('express-session');
var SessionStore= require('express-session-mongodb');
var BodyParser = require('body-parser');
var Context = {};
var RandomIdentifier = 'ExpressUserTests'+Math.random().toString(36).slice(-8);
var SessionStoreOptions = {'TimeToLive': 300, 'IndexSessionID': true, 'DeleteFlags': true};
function In()
{
var InList = arguments[0];
var CheckList = Array.prototype.slice.call(arguments, 1);
return(CheckList.every(function(CheckItem) {
return(InList.some(function(RefItem) {
return RefItem===CheckItem;
}));
}));
}
function Middleware(Routes)
{
return(function(Router, Roles) {
Routes.forEach(function(Route) {
Router[Route['Method']](Route['Path'], Route['Call']);
});
});
}
function Setup(ValidationRoutes, ResponseRoutes, Callback)
{
var UserSchema = UserProperties({'Email': {'Required': true, 'Unique': true, 'Privacy': UserProperties.Privacy.Private},
'Username': {'Required': true, 'Unique': true, 'Privacy': UserProperties.Privacy.Public},
'Password': {'Required': true, 'Privacy': UserProperties.Privacy.Secret, 'Retrievable': false}});
MongoDB.MongoClient.connect("mongodb://localhost:27017/"+RandomIdentifier, {native_parser:true}, function(Err, DB) {
UserStore(DB, UserSchema, function(Err, UserStoreInst) {
SessionStore(DB, function(Err, SessionStoreInst) {
Context['DB'] = DB;
Context['UserStore'] = UserStoreInst;
var App = Context['App'] = Express();
App.use(Session({
'secret': 'qwerty!',
'resave': true,
'saveUninitialized': true,
'store': SessionStoreInst
}));
App.use(BodyParser.json());
var UserRouter = ExpressUser(UserStoreInst, {'Validator': Middleware(ValidationRoutes), 'Responder': Middleware(ResponseRoutes)});
App.use(ExpressUser.SessionRoute(UserStoreInst, '_id'));
App.put('/User/Self/Memberships/Admin', function(Req, Res, Next) {
if(Req.session.User)
{
UserStoreInst.AddMembership({'Email': Req.session.User.Email}, 'Admin', function(Err, Result) {
if(Err)
{
Next(Err);
}
else
{
if(Result>0)
{
Res.status(200).end();
}
else
{
Res.status(400).end();
}
}
});
}
else
{
Res.status(400).end();
}
});
App.get('/Session/Self/User', function(Req, Res, Next) {
if(Req.session.User)
{
Res.status(200).json(Req.session.User);
}
else
{
Res.status(400).end();
}
});
App.use(UserRouter);
App.use('/', function(Err, Req, Res, Next) {
if(Err.Type)
{
Res.status(400).json({'ErrType': Err.Type, 'ErrSource': Err.Source});
}
else
{
Next(Err);
}
});
Context['Server'] = Http.createServer(Context['App']);
Context['Server'].listen(8080, function() {
Callback();
});
}, SessionStoreOptions);
});
});
}
function TearDown(Callback)
{
Context.Server.close(function() {
Context.DB.dropDatabase(function(Err, Result) {
Context.DB.close();
Callback();
});
});
}
function RequestHandler()
{
this.SessionID = null;
if(!RequestHandler.prototype.SetSessionID)
{
RequestHandler.prototype.SetSessionID = function(Headers) {
if(Headers["set-cookie"])
{
var SessionCookie = Headers["set-cookie"][0];
SessionCookie = SessionCookie.slice(String("connect.sid=").length, SessionCookie.indexOf(';'));
this.SessionID = SessionCookie;
}
};
RequestHandler.prototype.Request = function(Method, Path, Callback, ReqBody, GetBody) {
var Self = this;
var RequestObject = {'hostname': 'localhost', 'port': 8080, 'method': Method, 'path': Path, 'headers': {'Accept': 'application/json'}};
if(this.SessionID)
{
RequestObject['headers']['cookie'] = 'connect.sid='+this.SessionID;
}
if(ReqBody)
{
RequestObject.headers['Content-Type']='application/json';
RequestObject.headers['Content-Length']=(JSON.stringify(ReqBody)).length;
}
var Req = Http.request(RequestObject, function(Res) {
Res.setEncoding('utf8');
var Body = "";
if(!GetBody)
{
Res.resume();
}
else
{
Res.on('data', function (Chunk) {
Body+=Chunk;
});
}
Res.on('end', function() {
Self.SetSessionID(Res.headers);
Body = GetBody && Body ? JSON.parse(Body) : null;
Callback(Res.statusCode, Body);
});
});
if(ReqBody)
{
Req.write(JSON.stringify(ReqBody), function() {
Req.end();
});
}
else
{
Req.end();
}
};
}
}
var BodyRoute = {'Method': 'use', 'Path': '/', 'Call': function(Req, Res, Next) {
if(Req.body.User||Req.body.Update||Req.body.Membership)
{
Res.locals.ExpressUser = {};
if(Req.body.User)
{
Res.locals.ExpressUser.User = Req.body.User;
}
if(Req.body.Update)
{
Res.locals.ExpressUser.Update = Req.body.Update;
}
if(Req.body.Membership)
{
Res.locals.ExpressUser.Membership = Req.body.Membership;
}
if(Req.body.Memberships)
{
Res.locals.ExpressUser.Memberships = Req.body.Memberships;
}
if(Req.body.GetUpdatedUser)
{
Res.locals.ExpressUser.GetUpdatedUser = Req.body.GetUpdatedUser;
}
}
Next();
}};
var SuccessRoute = {'Method': 'use', 'Path': '/', 'Call': function(Req, Res, Next) {
if(!(Res.locals.ExpressUser && Res.locals.ExpressUser.Result !== undefined))
{
Res.status(200).end();
}
else
{
if(typeof(Res.locals.ExpressUser.Result) === typeof(0))
{
Res.status(200).json({'Count': Res.locals.ExpressUser.Result});
}
else
{
Res.status(200).json(Res.locals.ExpressUser.Result);
}
}
}};
exports.Main = {
'setUp': function(Callback) {
Setup([BodyRoute], [SuccessRoute], Callback);
},
'tearDown': function(Callback) {
TearDown(Callback);
},
'UserCreation': function(Test) {
Test.expect(2);
var Requester = new RequestHandler();
Requester.Request('POST', '/Users', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(User && Status===200, "Confirming that POST /Users route generate users");
Requester.Request('POST', '/Users', function(Status, Body) {
Test.ok(Body && Body.ErrType && Body.ErrSource && Body.ErrType === 'StoreConstraint' && Body.ErrSource === 'UserStore', "Confirming that constraint violation get properly routed on POST /Users route.");
Test.done();
}, {'User': {'Username': 'SomeName'}}, true);
});
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
},
'LoginLogout': function(Test) { //Good insert and good delete left
Test.expect(4);
var Requester = new RequestHandler();
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('PUT', '/Session/Self/User', function(Status, Body) {
Test.ok(Status===400 && Body && Body.ErrType && Body.ErrType === "NoUser", "Confirming that passing credentials of non-existent user on PUT /Session/Self/User routes triggers the right error.");
Requester.Request('DELETE', '/Session/Self/User', function(Status, Body) {
Test.ok(Status===400 && Body && Body.ErrType && Body.ErrType === "NoSessionUser", "Confirming that trying to delete a non-existent session on DELETE /Session/Self/User routes triggers the right error.");
Requester.Request('PUT', '/Session/Self/User', function(LoginStatus, Body) {
Requester.Request('GET', '/Session/Self/User', function(Status, Body) {
Test.ok(LoginStatus===200 && Body && Body.Email === 'SomeEmail@Email.com', "Confirming that PUT /Session/Self/User route logins the user.");
Requester.Request('DELETE', '/Session/Self/User', function(LogoutStatus, Body) {
Requester.Request('GET', '/Session/Self/User', function(GetSessionStatus, Body) {
Test.ok(LogoutStatus===200 && GetSessionStatus===400, "Confirming that DELETE /Session/Self/User route logs out the user.");
Test.done();
}, null, false);
}, {'User': {}}, false);
}, null, true);
}, {'User':{'Username': 'SomeName'}}, false);
}, {'User': {}}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty2!'}}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
},
'UserDeletion': function(Test) {
Test.expect(4);
var Requester = new RequestHandler();
Requester.Request('DELETE', '/User/Self', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoDelete", "Confirming that trying to delete a non-existent user on route DELETE /User/Self triggers the right error.");
Requester.Request('DELETE', '/User/Username/SomeName', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoDelete", "Confirming that trying to delete a non-existent user on route DELETE /User/:Field/:ID triggers the right error.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('DELETE', '/User/Self', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200 && (!User), "Confirming that user deletion with route DELETE /User/Self works.");
Requester.Request('DELETE', '/User/Username/SomeName2', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName2'}, function(Err, User) {
Test.ok(Status===200 && (!User), "Confirming that user deletion with route DELETE /User/:Field/:ID works.");
Test.done();
});
}, {'User': {'Username': 'SomeName2'}}, false);
});
}, {'User': {'Username': 'SomeName'}}, false);
}, {'User': {'Username': 'SomeName2', 'Email': 'SomeEmail2@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'SomeName'}}, true);
},
'UserModification': function(Test) {
Test.expect(6);
var Requester = new RequestHandler();
Requester.Request('PATCH', '/User/Self', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoUpdate", "Confirming that trying to update a non-existent user on route PATCH /User/Self triggers the right error.");
Requester.Request('PATCH', '/User/Username/SomeName', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoUpdate", "Confirming that trying to update a non-existent user on route PATCH /User/:Field/:ID triggers the right error.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('PATCH', '/User/Self', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200 && User && User.Email === "AnotherEmail@Email.com", "Confirming that updating works with the PATCH /User/Self route.");
Requester.Request('PATCH', '/User/Username/SomeName', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200 && User && User.Email === "YetAnotherEmail@Email.com", "Confirming that updating works with the PATCH /User/:Field/:ID route.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('PATCH', '/User/Self', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="StoreConstraint", "Confirming that trying that violating user store constraints triggers the right error for the PATCH /User/Self route.");
Requester.Request('PATCH', '/User/Username/SomeName', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="StoreConstraint", "Confirming that trying that violating user store constraints triggers the right error for the PATCH /User/:Field/:ID route.");
Test.done();
}, {'User': {'Username': 'AnotherName'}, 'Update': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'AnotherName'}, 'Update': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'AnotherName', 'Email': 'Unimportant@Email.com', 'Password': 'Qwerty!'}}, false);
});
}, {'User': {'Username': 'SomeName'}, 'Update': {'Email': 'YetAnotherEmail@Email.com'}}, true);
});
}, {'User': {'Username': 'SomeName'}, 'Update': {'Email': 'AnotherEmail@Email.com'}}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName'}, 'Update': {'Username': 'SomeName2'}}, true);
}, {'User': {'Username': 'SomeName'}, 'Update': {'Username': 'SomeName2'}}, true);
},
'UserGet': function(Test) {
Test.expect(4);
var Requester = new RequestHandler();
Requester.Request('GET', '/User/Self', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType === "NoUser", "Confirming that fetching a non-existent user on route GET /User/Self triggers the right error.");
Requester.Request('GET', '/User/Username/SomeName', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType === "NoUser", "Confirming that fetching a non-existent user on route GET /User/:Field/:ID triggers the right error.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('GET', '/User/Self', function(Status, Body) {
Test.ok(Status === 200 && Body.Username === 'SomeName' && Body.Email === 'SomeEmail@Email.com', "Confirming that fetching a user on route GET /User/Self works.");
Requester.Request('GET', '/User/Username/SomeName', function(Status, Body) {
Test.ok(Status === 200 && Body.Username === 'SomeName' && Body.Email === 'SomeEmail@Email.com', "Confirming that fetching a user on route GET /User/:Field/:ID works.");
Test.done();
}, {'User': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'SomeName'}}, true);
},
'UserCount': function(Test) {
Test.expect(2);
var Requester = new RequestHandler();
Requester.Request('GET', '/Users/Username/SomeName/Count', function(Status, Body) {
Test.ok(Status === 200 && Body.Count===0, "Confirming that couting on route GET /Users/:Field/:ID/Count works, case 1.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('GET', '/Users/Username/SomeName/Count', function(Status, Body) {
Test.ok(Status === 200 && Body.Count===1, "Confirming that couting on route GET /Users/:Field/:ID/Count works, case 2.");
Test.done();
}, {'User': {'Username': 'SomeName'}}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName'}}, true);
},
'Memberships': function(Test) {
Test.expect(10);
var Requester = new RequestHandler();
Requester.Request('PUT', '/User/Self/Memberships/Banned', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoInsertion", "Confirming that adding membership to non-existent user on route PUT /User/Self/Memberships/:Membership triggers the right error.");
Requester.Request('PUT', '/User/Username/SomeName/Memberships/Banned', function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType==="NoInsertion", "Confirming that adding membership to non-existent user on route PUT /User/:Field/:ID/Memberships/:Membership triggers the right error.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('DELETE', '/User/Self/Memberships/Banned', function(Status, Body) {
//Might eventually want to change it to report an error like NoMembership
Test.ok(Status===200, "Confirming that deleting non-existent membership on route DELETE /User/Self/Memberships/:Membership works as expected.");
Requester.Request('DELETE', '/User/Username/SomeName/Memberships/Banned', function(Status, Body) {
//Might eventually want to change it to report an error like NoMembership
Test.ok(Status===200, "Confirming that deleting non-existent membership on route DELETE /User/:Field/:ID/Memberships/:Membership works as expected.");
Requester.Request('PUT', '/User/Self/Memberships/Banned1', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200&&User.Memberships.some(function(Item) {
return Item==="Banned1";
}), "Confirming that route PUT /User/Self/Memberships/:Membership works for adding memberships");
Requester.Request('PUT', '/User/Username/SomeName/Memberships/Banned2', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200&&User.Memberships.some(function(Item) {
return Item==="Banned2";
}), "Confirming that route PUT /User/:Field/:ID/Memberships/:Membership works for adding memberships");
Requester.Request('PUT', '/User/Self/Memberships/Banned1', function(Status, Body) {
//Might eventually want to change it to report an error like MembershipExists
Test.ok(Status===200, "Confirming that inserting an already existing membership in route PUT /User/Self/Memberships/:Membership behaves as expected.");
Requester.Request('PUT', '/User/Username/SomeName/Memberships/Banned1', function(Status, Body) {
//Might eventually want to change it to report an error like MembershipExists
Test.ok(Status===200, "Confirming that inserting an already existing membership in route PUT /User/:Field/:ID/Memberships/:Membership behaves as expected.");
Requester.Request('DELETE', '/User/Self/Memberships/Banned1', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200&&User.Memberships.every(function(Item) {
return Item!=="Banned1";
}), "Confirming that route DELETE /User/Self/Memberships/:Membership works for deleting memberships");
Requester.Request('DELETE', '/User/Username/SomeName/Memberships/Banned2', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName'}, function(Err, User) {
Test.ok(Status===200&&User.Memberships.every(function(Item) {
return Item!=="Banned2";
}), "Confirming that route DELETE /User/:Field/:ID/Memberships/:Membership works for deleting memberships");
Test.done();
});
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned2'}, true);
});
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned1'}, true);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned1'}, true);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned1'}, true);
});
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned2'}, true);
});
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned1'}, true);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned'}, true);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned'}, true);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned'}, true);
}, {'User': {'Username': 'SomeName'}, 'Membership': 'Banned'}, true);
},
'UserModification + Memberships': function(Test) {
Test.expect(2);
var Requester = new RequestHandler();
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('PATCH', '/User/Self', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName2'}, function(Err, User) {
Test.ok(User && User.Memberships && User.Memberships.length === 2 && In(User.Memberships, 'Test1', 'Test2'), "Confirming that PATCH requests with Memberships manipulations work, part 1.");
Requester.Request('PATCH', '/User/Self', function(Status, Body) {
Context['UserStore'].Get({'Username': 'SomeName3'}, function(Err, User) {
Test.ok(User && User.Memberships && User.Memberships.length === 1 && In(User.Memberships, 'Test1'), "Confirming that PATCH requests with Memberships manipulations work, part 2.");
Test.done();
});
}, {'User': {'Username': 'SomeName2'}, 'Update': {'Username': 'SomeName3'}, 'Memberships': {'Remove': 'Test2'}});
});
}, {'User': {'Username': 'SomeName'}, 'Update': {'Username': 'SomeName2'}, 'Memberships': {'Add': ['Test1', 'Test2']}});
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, true);
},
'SessionSync': function(Test) {
Test.expect(2);
var Requester = new RequestHandler();
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request('PUT', '/Session/Self/User', function(Status, Body) {
Requester.Request('PATCH', '/User/Username/SomeName', function(Status, Body) {
Requester.Request('GET', '/Session/Self/User', function(Status, Body) {
Test.ok(Status===200 && Body.Username && Body.Username === 'SomeName2' && Body.Email && Body.Email === 'SomeEmail2@Email.com', "Confirming that sessions are kept in sync during profile updates");
Requester.Request('DELETE', '/User/Username/SomeName', function(Status, Body) {
Requester.Request('GET', '/Session/Self/User', function(Status, Body) {
Test.ok(Status===400, "Confirming that sessions are kept in sync during profile deletions");
Test.done();
}, null, true);
}, {'User': {'Username': 'SomeName2'}}, false);
}, null, true);
}, {'User': {'Username': 'SomeName'}, 'Update': {'Username': 'SomeName2', 'Email': 'SomeEmail2@Email.com'}}, false);
}, {'User': {'Username': 'SomeName'}}, false);
}, {'User': {'Username': 'SomeName', 'Email': 'SomeEmail@Email.com', 'Password': 'Qwerty!'}}, false);
},
'ValidationCheck': function(Test) {
var Routes = [['POST', '/Users'],
['PATCH', '/User/Self'],
['DELETE', '/User/Self'],
['GET', '/User/Self'],
['PATCH', '/User/Username/Test'],
['DELETE', '/User/Username/Test'],
['GET', '/User/Username/Test'],
['PUT', '/User/Self/Memberships/Test'],
['DELETE', '/User/Self/Memberships/Test'],
['PUT', '/User/Username/Test/Memberships/Test'],
['DELETE', '/User/Username/Test/Memberships/Test'],
['POST', '/User/Self/Recovery/Test'],
['POST', '/User/Username/Test/Recovery/Test'],
['PUT', '/Session/Self/User'],
['DELETE', '/Session/Self/User'],
['GET', '/Users/Username/SomeName/Count']];
Test.expect(Routes.length);
var Requester = new RequestHandler();
var Calls = [];
Routes.forEach(function(Route) {
Calls.push(function(Callback) {
Requester.Request(Route[0], Route[1], function(Status, Body) {
Test.ok(Status===400 && Body.ErrType && Body.ErrType === "NotValidated", "Confirming validation check is performed on route "+Route[0]+" "+Route[1]+".");
Callback();
}, null, true);
});
});
Nimble.series(Calls, function(Err) {Test.done();});
},
'GetUpdatedUser': function(Test) {
Test.expect(16);
var Requester = new RequestHandler();
function TestRoute(Method, URL, Name, Callback)
{
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request(Method, URL, function(Status, Body) {
Test.ok(Body && Body.Username === (Name+2) && Body.Email === (Name+2+'@Email.com'), "Confirming that User is retrieved when GetUpdatedUser is true for "+Method+" "+URL+" route.");
Requester.Request(Method, URL, function(Status, Body) {
Test.ok(Body && Body.ErrType && Body.ErrType === 'NoUpdate', "Confirming that proper error mechanism is triggered for updating non-existent user when GetUpdatedUser is true for "+Method+" "+URL+" route.");
Requester.Request(Method, URL, function(Status, Body) {
Test.ok(Status === 200 && Body === null, "Confirming that User is not retrieved when GetUpdatedUser is falsey "+Method+" "+URL+" route.");
Requester.Request('POST', '/Users', function(Status, Body) {
Requester.Request(Method, URL, function(Status, Body) {
Test.ok(Body && Body.ErrSource === 'UserStore' && Body.ErrType === 'StoreConstraint', "Confirming that proper error mechanism is triggered for violating user store constraint when GetUpdatedUser is true for "+Method+" "+URL+" route.");
Callback();
}, {'User': {'Username': Name+3}, 'Update': {'Username': Name+100, 'Email': Name+100+'@Email.com'}, 'GetUpdatedUser': true}, true);
}, {'User': {'Username': Name+100, 'Email': Name+100+'@Email.com', 'Password': 'Qwerty!'}}, true);
}, {'User': {'Username': Name+2}, 'Update': {'Username': Name+3, 'Email': Name+3+'@Email.com'}, 'GetUpdatedUser': false}, true);
}, {'User': {'Username': Name}, 'Update': {'Username': Name+2, 'Email': Name+2+'@Email.com'}, 'GetUpdatedUser': true}, true);
}, {'User': {'Username': Name}, 'Update': {'Username': Name+2, 'Email': Name+2+'@Email.com'}, 'GetUpdatedUser': true}, true);
}, {'User': {'Username': Name, 'Email': Name+'@Email.com', 'Password': 'Qwerty!'}}, true);
}
TestRoute('PATCH', '/User/Username/SomeName', 'SomeName', function() {
TestRoute('PATCH', '/User/Self', 'DoNotCare', function() {
TestRoute('POST', '/User/Self/Recovery/Password', 'HahaHaha', function() {
TestRoute('POST', '/User/Self/Recovery/Password', 'HihiHihi', function() {
Test.done();
});
});
});
});
}
};