mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-07-05 23:58:48 +02:00
Adding client test coverage.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,6 +14,7 @@ public/lib/
|
||||
app/tests/coverage/
|
||||
.bower-*/
|
||||
.idea/
|
||||
coverage/
|
||||
|
||||
# MEAN.js app and assets
|
||||
# ======================
|
||||
@@ -68,4 +69,3 @@ mongod
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"angular-bootstrap": "~0.13",
|
||||
"angular-ui-utils": "bower",
|
||||
"angular-ui-router": "~0.2",
|
||||
"angular-file-upload": "~1.1.5"
|
||||
"angular-file-upload": "1.1.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"angular": "~1.3"
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
$httpBackend,
|
||||
$stateParams,
|
||||
$location,
|
||||
Authentication;
|
||||
Authentication,
|
||||
Articles,
|
||||
mockArticle;
|
||||
|
||||
// The $resource service augments the response object with methods for updating and deleting the resource.
|
||||
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
|
||||
@@ -36,7 +38,7 @@
|
||||
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
|
||||
// This allows us to inject a service but then attach it to a variable
|
||||
// with the same name as the service.
|
||||
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_, _Authentication_) {
|
||||
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_, _Authentication_, _Articles_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
@@ -45,6 +47,14 @@
|
||||
$httpBackend = _$httpBackend_;
|
||||
$location = _$location_;
|
||||
Authentication = _Authentication_;
|
||||
Articles = _Articles_;
|
||||
|
||||
// create mock article
|
||||
mockArticle = new Articles({
|
||||
_id: '525a8422f6d0f87f0e407a33',
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
});
|
||||
|
||||
// Mock logged in user
|
||||
Authentication.user = {
|
||||
@@ -58,14 +68,8 @@
|
||||
}));
|
||||
|
||||
it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Articles) {
|
||||
// Create sample article using the Articles service
|
||||
var sampleArticle = new Articles({
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
});
|
||||
|
||||
// Create a sample articles array that includes the new article
|
||||
var sampleArticles = [sampleArticle];
|
||||
var sampleArticles = [mockArticle];
|
||||
|
||||
// Set GET response
|
||||
$httpBackend.expectGET('api/articles').respond(sampleArticles);
|
||||
@@ -79,99 +83,128 @@
|
||||
}));
|
||||
|
||||
it('$scope.findOne() should create an array with one article object fetched from XHR using a articleId URL parameter', inject(function(Articles) {
|
||||
// Define a sample article object
|
||||
var sampleArticle = new Articles({
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
});
|
||||
|
||||
// Set the URL parameter
|
||||
$stateParams.articleId = '525a8422f6d0f87f0e407a33';
|
||||
$stateParams.articleId = mockArticle._id;
|
||||
|
||||
// Set GET response
|
||||
$httpBackend.expectGET(/api\/articles\/([0-9a-fA-F]{24})$/).respond(sampleArticle);
|
||||
$httpBackend.expectGET(/api\/articles\/([0-9a-fA-F]{24})$/).respond(mockArticle);
|
||||
|
||||
// Run controller functionality
|
||||
scope.findOne();
|
||||
$httpBackend.flush();
|
||||
|
||||
// Test scope value
|
||||
expect(scope.article).toEqualData(sampleArticle);
|
||||
expect(scope.article).toEqualData(mockArticle);
|
||||
}));
|
||||
|
||||
it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Articles) {
|
||||
// Create a sample article object
|
||||
var sampleArticlePostData = new Articles({
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
describe('$scope.craete()', function() {
|
||||
var sampleArticlePostData;
|
||||
|
||||
beforeEach(function() {
|
||||
// Create a sample article object
|
||||
sampleArticlePostData = new Articles({
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
});
|
||||
|
||||
// Fixture mock form input values
|
||||
scope.title = 'An Article about MEAN';
|
||||
scope.content = 'MEAN rocks!';
|
||||
|
||||
spyOn($location, 'path');
|
||||
});
|
||||
|
||||
// Create a sample article response
|
||||
var sampleArticleResponse = new Articles({
|
||||
_id: '525cf20451979dea2c000001',
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN rocks!'
|
||||
it('should send a POST request with the form input values and then locate to new object URL', inject(function(Articles) {
|
||||
// Set POST response
|
||||
$httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(mockArticle);
|
||||
|
||||
// Run controller functionality
|
||||
scope.create();
|
||||
$httpBackend.flush();
|
||||
|
||||
// Test form inputs are reset
|
||||
expect(scope.title).toEqual('');
|
||||
expect(scope.content).toEqual('');
|
||||
|
||||
// Test URL redirection after the article was created
|
||||
expect($location.path.calls.mostRecent().args[0]).toBe('articles/' + mockArticle._id);
|
||||
}));
|
||||
|
||||
it('should set scope.error if save error', function() {
|
||||
var errorMessage = 'this is an error message';
|
||||
$httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(400, {
|
||||
message: errorMessage
|
||||
});
|
||||
|
||||
scope.create();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(scope.error).toBe(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
describe('$scope.update()', function() {
|
||||
beforeEach(function() {
|
||||
// Mock article in scope
|
||||
scope.article = mockArticle;
|
||||
});
|
||||
|
||||
// Fixture mock form input values
|
||||
scope.title = 'An Article about MEAN';
|
||||
scope.content = 'MEAN rocks!';
|
||||
it('should update a valid article', inject(function(Articles) {
|
||||
// Set PUT response
|
||||
$httpBackend.expectPUT(/api\/articles\/([0-9a-fA-F]{24})$/).respond();
|
||||
|
||||
// Set POST response
|
||||
$httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(sampleArticleResponse);
|
||||
// Run controller functionality
|
||||
scope.update();
|
||||
$httpBackend.flush();
|
||||
|
||||
// Run controller functionality
|
||||
scope.create();
|
||||
$httpBackend.flush();
|
||||
// Test URL location to new object
|
||||
expect($location.path()).toBe('/articles/' + mockArticle._id);
|
||||
}));
|
||||
|
||||
// Test form inputs are reset
|
||||
expect(scope.title).toEqual('');
|
||||
expect(scope.content).toEqual('');
|
||||
it('should set scope.error to error response message', inject(function(Articles) {
|
||||
var errorMessage = 'error';
|
||||
$httpBackend.expectPUT(/api\/articles\/([0-9a-fA-F]{24})$/).respond(400, {
|
||||
message: errorMessage
|
||||
});
|
||||
|
||||
// Test URL redirection after the article was created
|
||||
expect($location.path()).toBe('/articles/' + sampleArticleResponse._id);
|
||||
}));
|
||||
scope.update();
|
||||
$httpBackend.flush();
|
||||
|
||||
it('$scope.update() should update a valid article', inject(function(Articles) {
|
||||
// Define a sample article put data
|
||||
var sampleArticlePutData = new Articles({
|
||||
_id: '525cf20451979dea2c000001',
|
||||
title: 'An Article about MEAN',
|
||||
content: 'MEAN Rocks!'
|
||||
expect(scope.error).toBe(errorMessage);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('$scope.remove(article)', function() {
|
||||
beforeEach(function() {
|
||||
// Create new articles array and include the article
|
||||
scope.articles = [mockArticle, {}];
|
||||
|
||||
// Set expected DELETE response
|
||||
$httpBackend.expectDELETE(/api\/articles\/([0-9a-fA-F]{24})$/).respond(204);
|
||||
|
||||
// Run controller functionality
|
||||
scope.remove(mockArticle);
|
||||
});
|
||||
|
||||
// Mock article in scope
|
||||
scope.article = sampleArticlePutData;
|
||||
it('should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Articles) {
|
||||
expect(scope.articles.length).toBe(1);
|
||||
}));
|
||||
});
|
||||
|
||||
// Set PUT response
|
||||
$httpBackend.expectPUT(/api\/articles\/([0-9a-fA-F]{24})$/).respond();
|
||||
describe('scope.remove()', function() {
|
||||
beforeEach(function() {
|
||||
spyOn($location, 'path');
|
||||
scope.article = mockArticle;
|
||||
|
||||
// Run controller functionality
|
||||
scope.update();
|
||||
$httpBackend.flush();
|
||||
$httpBackend.expectDELETE(/api\/articles\/([0-9a-fA-F]{24})$/).respond(204);
|
||||
|
||||
// Test URL location to new object
|
||||
expect($location.path()).toBe('/articles/' + sampleArticlePutData._id);
|
||||
}));
|
||||
|
||||
it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Articles) {
|
||||
// Create new article object
|
||||
var sampleArticle = new Articles({
|
||||
_id: '525a8422f6d0f87f0e407a33'
|
||||
scope.remove();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
// Create new articles array and include the article
|
||||
scope.articles = [sampleArticle];
|
||||
|
||||
// Set expected DELETE response
|
||||
$httpBackend.expectDELETE(/api\/articles\/([0-9a-fA-F]{24})$/).respond(204);
|
||||
|
||||
// Run controller functionality
|
||||
scope.remove(sampleArticle);
|
||||
$httpBackend.flush();
|
||||
|
||||
// Test array after successful delete
|
||||
expect(scope.articles.length).toBe(0);
|
||||
}));
|
||||
it('should redirect to articles', function() {
|
||||
expect($location.path).toHaveBeenCalledWith('articles');
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
@@ -4,7 +4,91 @@
|
||||
* Chat client controller tests
|
||||
*/
|
||||
(function() {
|
||||
describe('ChatController', function() {
|
||||
// TODO: Add chat client controller tests
|
||||
});
|
||||
describe('ChatController', function() {
|
||||
//Initialize global variables
|
||||
var scope,
|
||||
Socket,
|
||||
ChatController,
|
||||
$timeout,
|
||||
$location,
|
||||
Authentication;
|
||||
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function($controller, $rootScope, _Socket_, _Authentication_, _$timeout_, _$location_) {
|
||||
scope = $rootScope.$new();
|
||||
Socket = _Socket_;
|
||||
$timeout = _$timeout_;
|
||||
$location = _$location_;
|
||||
Authentication = _Authentication_;
|
||||
}));
|
||||
|
||||
describe('when user logged out', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _Socket_, _Authentication_, _$timeout_, _$location_) {
|
||||
Authentication.user = undefined;
|
||||
spyOn($location, 'path');
|
||||
ChatController = $controller('ChatController', {
|
||||
$scope: scope,
|
||||
});
|
||||
}));
|
||||
|
||||
it('should redirect logged out user to /', function() {
|
||||
expect($location.path).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user logged in', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _Socket_, _Authentication_, _$timeout_, _$location_) {
|
||||
Authentication.user = {
|
||||
name: 'user',
|
||||
roles: ['user']
|
||||
};
|
||||
|
||||
ChatController = $controller('ChatController', {
|
||||
$scope: scope,
|
||||
});
|
||||
}));
|
||||
|
||||
it('should make sure socket is connected', function() {
|
||||
expect(Socket.socket).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should define messages array', function() {
|
||||
expect(scope.messages).toBeDefined();
|
||||
expect(scope.messages.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('sendMessage', function() {
|
||||
var text = 'hello world!';
|
||||
beforeEach(function() {
|
||||
scope.messageText = text;
|
||||
scope.sendMessage();
|
||||
$timeout.flush();
|
||||
});
|
||||
|
||||
it('should add message to messages', function() {
|
||||
expect(scope.messages.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should add message with proper text attribute set', function() {
|
||||
expect(scope.messages[0].text).toBe(text);
|
||||
});
|
||||
|
||||
it('should clear messageText', function() {
|
||||
expect(scope.messageText).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('$destroy()', function() {
|
||||
beforeEach(function() {
|
||||
scope.$destroy();
|
||||
});
|
||||
|
||||
it('should remove chatMessage listener', function() {
|
||||
expect(Socket.socket.cbs.chatMessage).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
@@ -3,177 +3,175 @@
|
||||
//Menu service used for managing menus
|
||||
angular.module('core').service('Menus', [
|
||||
|
||||
function() {
|
||||
// Define a set of default roles
|
||||
this.defaultRoles = ['*'];
|
||||
function() {
|
||||
// Define a set of default roles
|
||||
this.defaultRoles = ['*'];
|
||||
|
||||
// Define the menus object
|
||||
this.menus = {};
|
||||
// Define the menus object
|
||||
this.menus = {};
|
||||
|
||||
// A private function for rendering decision
|
||||
var shouldRender = function(user) {
|
||||
if (user) {
|
||||
if (!!~this.roles.indexOf('*')) {
|
||||
return true;
|
||||
} else {
|
||||
for (var userRoleIndex in user.roles) {
|
||||
for (var roleIndex in this.roles) {
|
||||
if (this.roles[roleIndex] === user.roles[userRoleIndex]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.isPublic;
|
||||
// A private function for rendering decision
|
||||
var shouldRender = function(user) {
|
||||
if (user) {
|
||||
if (!!~this.roles.indexOf('*')) {
|
||||
return true;
|
||||
} else {
|
||||
for (var userRoleIndex in user.roles) {
|
||||
for (var roleIndex in this.roles) {
|
||||
if (this.roles[roleIndex] === user.roles[userRoleIndex]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.isPublic;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// Validate menu existance
|
||||
this.validateMenuExistance = function(menuId) {
|
||||
if (menuId && menuId.length) {
|
||||
if (this.menus[menuId]) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error('Menu does not exists');
|
||||
}
|
||||
} else {
|
||||
throw new Error('MenuId was not provided');
|
||||
}
|
||||
// Validate menu existance
|
||||
this.validateMenuExistance = function(menuId) {
|
||||
if (menuId && menuId.length) {
|
||||
if (this.menus[menuId]) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error('Menu does not exist');
|
||||
}
|
||||
} else {
|
||||
throw new Error('MenuId was not provided');
|
||||
}
|
||||
};
|
||||
|
||||
return false;
|
||||
};
|
||||
// Get the menu object by menu id
|
||||
this.getMenu = function(menuId) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Get the menu object by menu id
|
||||
this.getMenu = function(menuId) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
// Add new menu object by menu id
|
||||
this.addMenu = function(menuId, options) {
|
||||
options = options || {};
|
||||
|
||||
// Add new menu object by menu id
|
||||
this.addMenu = function(menuId, options) {
|
||||
options = options || {};
|
||||
// Create the new menu
|
||||
this.menus[menuId] = {
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? true : options.isPublic),
|
||||
roles: options.roles || this.defaultRoles,
|
||||
items: options.items || [],
|
||||
shouldRender: shouldRender
|
||||
};
|
||||
|
||||
// Create the new menu
|
||||
this.menus[menuId] = {
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? true : options.isPublic),
|
||||
roles: options.roles || this.defaultRoles,
|
||||
items: options.items || [],
|
||||
shouldRender: shouldRender
|
||||
};
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
// Remove existing menu object by menu id
|
||||
this.removeMenu = function(menuId) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Remove existing menu object by menu id
|
||||
this.removeMenu = function(menuId) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Return the menu object
|
||||
delete this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
delete this.menus[menuId];
|
||||
};
|
||||
// Add menu item object
|
||||
this.addMenuItem = function(menuId, options) {
|
||||
options = options || {};
|
||||
|
||||
// Add menu item object
|
||||
this.addMenuItem = function(menuId, options) {
|
||||
options = options || {};
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Push new menu item
|
||||
this.menus[menuId].items.push({
|
||||
title: options.title || '',
|
||||
state: options.state || '',
|
||||
type: options.type || 'item',
|
||||
class: options.class,
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? this.menus[menuId].isPublic : options.isPublic),
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.menus[menuId].roles : options.roles),
|
||||
position: options.position || 0,
|
||||
items: [],
|
||||
shouldRender: shouldRender
|
||||
});
|
||||
|
||||
// Push new menu item
|
||||
this.menus[menuId].items.push({
|
||||
title: options.title || '',
|
||||
state: options.state || '',
|
||||
type: options.type || 'item',
|
||||
class: options.class,
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? this.menus[menuId].isPublic : options.isPublic),
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.menus[menuId].roles : options.roles),
|
||||
position: options.position || 0,
|
||||
items: [],
|
||||
shouldRender: shouldRender
|
||||
});
|
||||
// Add submenu items
|
||||
if (options.items) {
|
||||
for (var i in options.items) {
|
||||
this.addSubMenuItem(menuId, options.link, options.items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add submenu items
|
||||
if (options.items) {
|
||||
for (var i in options.items) {
|
||||
this.addSubMenuItem(menuId, options.link, options.items[i]);
|
||||
}
|
||||
}
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
// Add submenu item object
|
||||
this.addSubMenuItem = function(menuId, parentItemState, options) {
|
||||
options = options || {};
|
||||
|
||||
// Add submenu item object
|
||||
this.addSubMenuItem = function(menuId, parentItemState, options) {
|
||||
options = options || {};
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Search for menu item
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
if (this.menus[menuId].items[itemIndex].state === parentItemState) {
|
||||
// Push new submenu item
|
||||
this.menus[menuId].items[itemIndex].items.push({
|
||||
title: options.title || '',
|
||||
state: options.state || '',
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? this.menus[menuId].items[itemIndex].isPublic : options.isPublic),
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.menus[menuId].items[itemIndex].roles : options.roles),
|
||||
position: options.position || 0,
|
||||
shouldRender: shouldRender
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Search for menu item
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
if (this.menus[menuId].items[itemIndex].state === parentItemState) {
|
||||
// Push new submenu item
|
||||
this.menus[menuId].items[itemIndex].items.push({
|
||||
title: options.title || '',
|
||||
state: options.state|| '',
|
||||
isPublic: ((options.isPublic === null || typeof options.isPublic === 'undefined') ? this.menus[menuId].items[itemIndex].isPublic : options.isPublic),
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.menus[menuId].items[itemIndex].roles : options.roles),
|
||||
position: options.position || 0,
|
||||
shouldRender: shouldRender
|
||||
});
|
||||
}
|
||||
}
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
// Remove existing menu object by menu id
|
||||
this.removeMenuItem = function(menuId, menuItemURL) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Remove existing menu object by menu id
|
||||
this.removeMenuItem = function(menuId, menuItemURL) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
if (this.menus[menuId].items[itemIndex].link === menuItemURL) {
|
||||
this.menus[menuId].items.splice(itemIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
if (this.menus[menuId].items[itemIndex].link === menuItemURL) {
|
||||
this.menus[menuId].items.splice(itemIndex, 1);
|
||||
}
|
||||
}
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
// Remove existing menu object by menu id
|
||||
this.removeSubMenuItem = function(menuId, submenuItemURL) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
|
||||
// Remove existing menu object by menu id
|
||||
this.removeSubMenuItem = function(menuId, submenuItemURL) {
|
||||
// Validate that the menu exists
|
||||
this.validateMenuExistance(menuId);
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
for (var subitemIndex in this.menus[menuId].items[itemIndex].items) {
|
||||
if (this.menus[menuId].items[itemIndex].items[subitemIndex].link === submenuItemURL) {
|
||||
this.menus[menuId].items[itemIndex].items.splice(subitemIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in this.menus[menuId].items) {
|
||||
for (var subitemIndex in this.menus[menuId].items[itemIndex].items) {
|
||||
if (this.menus[menuId].items[itemIndex].items[subitemIndex].link === submenuItemURL) {
|
||||
this.menus[menuId].items[itemIndex].items.splice(subitemIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
// Return the menu object
|
||||
return this.menus[menuId];
|
||||
};
|
||||
|
||||
//Adding the topbar menu
|
||||
this.addMenu('topbar', {
|
||||
isPublic: false
|
||||
});
|
||||
}
|
||||
//Adding the topbar menu
|
||||
this.addMenu('topbar', {
|
||||
isPublic: false
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1,24 +1,64 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
describe('HeaderController', function() {
|
||||
//Initialize global variables
|
||||
var scope,
|
||||
HeaderController;
|
||||
describe('HeaderController', function() {
|
||||
//Initialize global variables
|
||||
var scope,
|
||||
HeaderController,
|
||||
$state,
|
||||
Authentication;
|
||||
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function($controller, $rootScope) {
|
||||
scope = $rootScope.$new();
|
||||
beforeEach(inject(function($controller, $rootScope, _$state_, _Authentication_) {
|
||||
scope = $rootScope.$new();
|
||||
$state = _$state_;
|
||||
Authentication = _Authentication_;
|
||||
|
||||
HeaderController = $controller('HeaderController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
HeaderController = $controller('HeaderController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
|
||||
it('should expose the authentication service', function() {
|
||||
expect(scope.authentication).toBeTruthy();
|
||||
});
|
||||
});
|
||||
it('should expose the authentication service', function() {
|
||||
expect(scope.authentication).toBe(Authentication);
|
||||
});
|
||||
|
||||
it('should expose the $state service', function() {
|
||||
expect(scope.$state).toBe($state);
|
||||
});
|
||||
|
||||
it('should default menu to collapsed', function() {
|
||||
expect(scope.isCollapsed).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('when toggleCollapsibleMenu', function() {
|
||||
var defaultCollapse;
|
||||
beforeEach(function() {
|
||||
defaultCollapse = scope.isCollapsed;
|
||||
scope.toggleCollapsibleMenu();
|
||||
});
|
||||
|
||||
it('should toggle isCollapsed to non default value', function() {
|
||||
expect(scope.isCollapsed).not.toBe(defaultCollapse);
|
||||
});
|
||||
|
||||
it('should then toggle isCollapsed back to default value', function() {
|
||||
scope.toggleCollapsibleMenu();
|
||||
expect(scope.isCollapsed).toBe(defaultCollapse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when view state changes', function() {
|
||||
beforeEach(function() {
|
||||
scope.isCollapsed = true;
|
||||
scope.$broadcast('$stateChangeSuccess');
|
||||
});
|
||||
|
||||
it('should set isCollapsed to false', function() {
|
||||
expect(scope.isCollapsed).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
489
modules/core/tests/client/menus.client.service.tests.js
Normal file
489
modules/core/tests/client/menus.client.service.tests.js
Normal file
@@ -0,0 +1,489 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
describe('Menus', function() {
|
||||
//Initialize global variables
|
||||
var scope,
|
||||
Menus;
|
||||
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function(_Menus_) {
|
||||
Menus = _Menus_;
|
||||
}));
|
||||
|
||||
it('should have topbar added', function() {
|
||||
expect(Menus.menus.topbar).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have private topbar', function() {
|
||||
expect(Menus.menus.topbar.isPublic).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should have default roles to *', function() {
|
||||
expect(Menus.defaultRoles).toEqual(['*']);
|
||||
});
|
||||
|
||||
describe('addMenu', function() {
|
||||
describe('with no options', function() {
|
||||
var menuId = 'menu1',
|
||||
menu;
|
||||
beforeEach(function() {
|
||||
menu = Menus.addMenu(menuId);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
expect(menu).toBeDefined();
|
||||
});
|
||||
|
||||
it('should default roles', function() {
|
||||
expect(menu.roles).toEqual(Menus.defaultRoles);
|
||||
});
|
||||
|
||||
it('should have empty items', function() {
|
||||
expect(menu.items).toEqual([]);
|
||||
});
|
||||
|
||||
it('should be public by default', function() {
|
||||
expect(menu.isPublic).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set shouldRender to shouldRender function handle', function() {
|
||||
expect(menu.shouldRender()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with options', function() {
|
||||
var menu,
|
||||
options = {
|
||||
roles: ['a', 'b', 'c'],
|
||||
items: ['d', 'e', 'f']
|
||||
};
|
||||
beforeEach(function() {
|
||||
menu = Menus.addMenu('menu1', options);
|
||||
});
|
||||
|
||||
it('should set isPublic to true if options.isPublic equal to null', function() {
|
||||
var menu = Menus.addMenu('menu1', {
|
||||
isPublic: null
|
||||
});
|
||||
expect(menu.isPublic).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set isPublic to true if options.isPublic equal to undefined', function() {
|
||||
expect(menu.isPublic).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set items to options.items list', function() {
|
||||
expect(menu.items).toBe(options.items);
|
||||
});
|
||||
|
||||
it('should set roles to options.roles list', function() {
|
||||
expect(menu.roles).toBe(options.roles);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRender', function() {
|
||||
var menuOptions = {
|
||||
roles: ['*', 'menurole']
|
||||
},
|
||||
menu;
|
||||
beforeEach(function() {
|
||||
menu = Menus.addMenu('menu1', menuOptions);
|
||||
});
|
||||
|
||||
describe('when logged out', function() {
|
||||
it('should render if menu is public', function() {
|
||||
expect(menu.shouldRender()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render if menu is private', function() {
|
||||
menu = Menus.addMenu('menu1', {
|
||||
isPublic: false
|
||||
});
|
||||
expect(menu.shouldRender()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when logged in', function() {
|
||||
var user = {
|
||||
roles: ['1', 'menurole', '2']
|
||||
};
|
||||
describe('menu with * role', function() {
|
||||
it('should render', function() {
|
||||
expect(menu.shouldRender(user)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('menu without * role', function() {
|
||||
beforeEach(function() {
|
||||
menu = Menus.addMenu('menu1', {
|
||||
roles: ['b', 'menurole', 'c']
|
||||
});
|
||||
});
|
||||
|
||||
it('should render if user has same role as menu', function() {
|
||||
expect(menu.shouldRender(user)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render if user has different roles', function() {
|
||||
user = {
|
||||
roles: ['1', '2', '3']
|
||||
};
|
||||
expect(menu.shouldRender(user)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateMenuExistance', function() {
|
||||
describe('when menuId not provided', function() {
|
||||
it('should throw menuId error', function() {
|
||||
expect(Menus.validateMenuExistance).toThrowError('MenuId was not provided');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when menu does not exist', function() {
|
||||
it('should throw no menu error', function() {
|
||||
var target = function() {
|
||||
Menus.validateMenuExistance('noMenuId');
|
||||
};
|
||||
expect(target).toThrowError('Menu does not exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when menu exists', function() {
|
||||
var menuId = 'menuId';
|
||||
beforeEach(function() {
|
||||
Menus.menus[menuId] = {};
|
||||
});
|
||||
|
||||
it('should return truthy', function() {
|
||||
expect(Menus.validateMenuExistance(menuId)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMenu', function() {
|
||||
var menu = {
|
||||
id: 'menuId'
|
||||
};
|
||||
beforeEach(function() {
|
||||
Menus.menus[menu.id] = menu;
|
||||
Menus.validateMenuExistance = jasmine.createSpy();
|
||||
Menus.removeMenu(menu.id);
|
||||
});
|
||||
|
||||
it('should remove existing menu from menus', function() {
|
||||
expect(Menus.menus).not.toContain(menu.id);
|
||||
});
|
||||
|
||||
it('validates menu existance before removing', function() {
|
||||
expect(Menus.validateMenuExistance).toHaveBeenCalledWith(menu.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMenuItem', function() {
|
||||
var menuId = 'menu1',
|
||||
subMenuItem1 = {
|
||||
title: 'sub1'
|
||||
},
|
||||
subMenuItem2 = {
|
||||
title: 'sub2'
|
||||
},
|
||||
menuItemOptions = {
|
||||
title: 'title',
|
||||
state: 'state',
|
||||
type: 'type',
|
||||
class: 'class',
|
||||
isPublic: false,
|
||||
roles: ['a', 'b'],
|
||||
link: 'link',
|
||||
position: 2,
|
||||
items: [subMenuItem1, subMenuItem2]
|
||||
},
|
||||
menu,
|
||||
menuItem;
|
||||
|
||||
beforeEach(function() {
|
||||
Menus.validateMenuExistance = jasmine.createSpy();
|
||||
Menus.addSubMenuItem = jasmine.createSpy();
|
||||
Menus.addMenu(menuId, {
|
||||
roles: ['a', 'b']
|
||||
});
|
||||
menu = Menus.addMenuItem(menuId, menuItemOptions);
|
||||
menuItem = menu.items[0];
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
expect(Menus.validateMenuExistance).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should return the menu', function() {
|
||||
expect(menu).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set menu item shouldRender function', function() {
|
||||
expect(menuItem.shouldRender).toBeDefined();
|
||||
});
|
||||
|
||||
describe('with options set', function() {
|
||||
it('should add menu item to menu', function() {
|
||||
expect(menu.items.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should set menu item title to options title', function() {
|
||||
expect(menuItem.title).toBe(menuItemOptions.title);
|
||||
});
|
||||
|
||||
it('should set menu item state to options state', function() {
|
||||
expect(menuItem.state).toBe(menuItemOptions.state);
|
||||
});
|
||||
|
||||
it('should set menu item type to options type', function() {
|
||||
expect(menuItem.type).toBe(menuItemOptions.type);
|
||||
});
|
||||
|
||||
it('should set menu item class to options class', function() {
|
||||
expect(menuItem.class).toBe(menuItemOptions.class);
|
||||
});
|
||||
|
||||
it('should set menu item isPublic to options isPublic', function() {
|
||||
expect(menuItem.isPublic).toBe(menuItemOptions.isPublic);
|
||||
});
|
||||
|
||||
it('should set menu item position to options position', function() {
|
||||
expect(menuItem.position).toBe(menuItemOptions.position);
|
||||
});
|
||||
|
||||
it('should call addSubMenuItem for each item in options', function() {
|
||||
expect(Menus.addSubMenuItem).toHaveBeenCalledWith(menuId, menuItemOptions.link, subMenuItem1);
|
||||
expect(Menus.addSubMenuItem).toHaveBeenCalledWith(menuId, menuItemOptions.link, subMenuItem2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without options set', function() {
|
||||
beforeEach(function() {
|
||||
menu = Menus.addMenuItem(menuId);
|
||||
menuItem = menu.items[1];
|
||||
});
|
||||
|
||||
it('should set menu item type to item', function() {
|
||||
expect(menuItem.type).toBe('item');
|
||||
});
|
||||
|
||||
it('should set menu item title to empty', function() {
|
||||
expect(menuItem.title).toBe('');
|
||||
});
|
||||
|
||||
it('should set menu item isPublic to menu.isPublic', function() {
|
||||
expect(menuItem.isPublic).toBe(menu.isPublic);
|
||||
});
|
||||
|
||||
it('should set menu item roles to menu roles', function() {
|
||||
expect(menuItem.roles).toEqual(menu.roles);
|
||||
});
|
||||
|
||||
it('should set menu item position to 0', function() {
|
||||
expect(menuItem.position).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMenuItem', function() {
|
||||
var menuId = 'menuId',
|
||||
menuItemURL = 'url',
|
||||
menuItem1 = {
|
||||
link: menuItemURL
|
||||
},
|
||||
menuItem2 = {
|
||||
link: ''
|
||||
},
|
||||
newMenu = {
|
||||
items: [menuItem1, menuItem2]
|
||||
},
|
||||
menu = null;
|
||||
|
||||
beforeEach(function() {
|
||||
Menus.menus.menuId = newMenu;
|
||||
Menus.validateMenuExistance = jasmine.createSpy();
|
||||
menu = Menus.removeMenuItem(menuId, menuItemURL);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
expect(menu).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
expect(Menus.validateMenuExistance).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should remove sub menu items with same link', function() {
|
||||
expect(menu.items.length).toBe(1);
|
||||
expect(menu.items[0]).toBe(menuItem2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addSubMenuItem', function() {
|
||||
var subItemOptions = {
|
||||
title: 'title',
|
||||
state: 'state',
|
||||
isPublic: false,
|
||||
roles: ['a', 'b'],
|
||||
position: 4
|
||||
};
|
||||
var menuId = 'menu1',
|
||||
menuItem1 = {
|
||||
state: 'state',
|
||||
items: [],
|
||||
isPublic: false
|
||||
},
|
||||
menuItem2 = {
|
||||
state: 'state2',
|
||||
items: [],
|
||||
isPublic: true,
|
||||
roles: ['a']
|
||||
},
|
||||
menuItem3 = {
|
||||
state: 'state3',
|
||||
items: []
|
||||
},
|
||||
newMenu = {
|
||||
items: [menuItem1, menuItem2, menuItem3]
|
||||
},
|
||||
menu;
|
||||
|
||||
beforeEach(function() {
|
||||
Menus.validateMenuExistance = jasmine.createSpy();
|
||||
Menus.menus[menuId] = newMenu;
|
||||
Menus.addSubMenuItem(menuId, menuItem1.state, subItemOptions);
|
||||
menu = Menus.addSubMenuItem(menuId, menuItem2.state);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
menuItem1.items = [];
|
||||
menuItem2.items = [];
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
expect(menu).toEqual(newMenu);
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
expect(Menus.validateMenuExistance).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should not add sub menu item to menu item of different state', function() {
|
||||
expect(menuItem3.items.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should set shouldRender', function() {
|
||||
expect(menuItem1.items[0].shouldRender).toBeDefined();
|
||||
});
|
||||
|
||||
describe('with options set', function() {
|
||||
var subMenuItem;
|
||||
beforeEach(function() {
|
||||
subMenuItem = menuItem1.items[0];
|
||||
});
|
||||
|
||||
it('should add sub menu item to menu item', function() {
|
||||
expect(menuItem1.items.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should set isPublic to options isPublic', function() {
|
||||
expect(subMenuItem.isPublic).toBe(subItemOptions.isPublic);
|
||||
});
|
||||
|
||||
it('should set title to options title', function() {
|
||||
expect(subMenuItem.title).toBe(subItemOptions.title);
|
||||
});
|
||||
|
||||
it('should set state to options state', function() {
|
||||
expect(subMenuItem.state).toBe(subItemOptions.state);
|
||||
});
|
||||
|
||||
it('should set roles to options roles', function() {
|
||||
expect(subMenuItem.roles).toEqual(subItemOptions.roles);
|
||||
});
|
||||
|
||||
it('should set position to options position', function() {
|
||||
expect(subMenuItem.position).toEqual(subItemOptions.position);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without optoins set', function() {
|
||||
var subMenuItem;
|
||||
beforeEach(function() {
|
||||
subMenuItem = menuItem2.items[0];
|
||||
});
|
||||
|
||||
it('should add sub menu item to menu item', function() {
|
||||
expect(menuItem2.items.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should set isPublic to parent isPublic', function() {
|
||||
expect(subMenuItem.isPublic).toBe(menuItem2.isPublic);
|
||||
});
|
||||
|
||||
it('should set title to blank', function() {
|
||||
expect(subMenuItem.title).toBe('');
|
||||
});
|
||||
|
||||
it('should set state to blank', function() {
|
||||
expect(subMenuItem.state).toBe('');
|
||||
});
|
||||
|
||||
it('should set roles to parent roles', function() {
|
||||
expect(subMenuItem.roles).toEqual(menuItem2.roles);
|
||||
});
|
||||
|
||||
it('should set position to 0', function() {
|
||||
expect(subMenuItem.position).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeSubMenuItem', function() {
|
||||
var menuId = 'menu1',
|
||||
subMenuItem1 = {
|
||||
link: 'link1'
|
||||
},
|
||||
subMenuItem2 = {
|
||||
link: 'link2'
|
||||
},
|
||||
menuItem1 = {
|
||||
state: 'state',
|
||||
items: [subMenuItem1, subMenuItem2],
|
||||
},
|
||||
menuItem2 = {
|
||||
state: 'state2',
|
||||
items: [],
|
||||
},
|
||||
newMenu = {
|
||||
items: [menuItem1, menuItem2]
|
||||
},
|
||||
menu;
|
||||
beforeEach(function() {
|
||||
Menus.validateMenuExistance = jasmine.createSpy();
|
||||
Menus.menus[menuId] = newMenu;
|
||||
menu = Menus.removeSubMenuItem(menuId, subMenuItem1.link);
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
expect(Menus.validateMenuExistance).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
expect(menu).toEqual(newMenu);
|
||||
});
|
||||
|
||||
it('should remove sub menu item', function() {
|
||||
expect(menuItem1.items.length).toBe(1);
|
||||
expect(menuItem1.items[0]).toEqual(subMenuItem2);
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
24
modules/core/tests/client/socket.io.client.service.tests.js
Normal file
24
modules/core/tests/client/socket.io.client.service.tests.js
Normal file
@@ -0,0 +1,24 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/* Creates a mock of socket.io for the browser.
|
||||
* Functionality of the service is tested through
|
||||
* the chat controller tests.
|
||||
*/
|
||||
window.io = function() {
|
||||
this.cbs = {};
|
||||
this.on = function(msg, cb) {
|
||||
this.cbs[msg] = cb;
|
||||
};
|
||||
this.emit = function(msg, data) {
|
||||
this.cbs[msg](data);
|
||||
};
|
||||
this.removeListener = function(msg) {
|
||||
delete this.cbs[msg];
|
||||
};
|
||||
this.connect = function() {
|
||||
this.socket = {};
|
||||
};
|
||||
return this;
|
||||
};
|
||||
})();
|
||||
@@ -74,6 +74,12 @@ exports.list = function (req, res) {
|
||||
* User middleware
|
||||
*/
|
||||
exports.userByID = function (req, res, next, id) {
|
||||
if (!mongoose.Types.ObjectId.isValid(id)) {
|
||||
return res.status(400).send({
|
||||
message: 'User is invalid'
|
||||
});
|
||||
}
|
||||
|
||||
User.findById(id, '-salt -password').exec(function (err, user) {
|
||||
if (err) return next(err);
|
||||
if (!user) return next(new Error('Failed to load user ' + id));
|
||||
|
||||
@@ -10,10 +10,16 @@ var _ = require('lodash'),
|
||||
/**
|
||||
* User middleware
|
||||
*/
|
||||
exports.userByID = function(req, res, next, id) {
|
||||
exports.userByID = function (req, res, next, id) {
|
||||
if (!mongoose.Types.ObjectId.isValid(id)) {
|
||||
return res.status(400).send({
|
||||
message: 'User is invalid'
|
||||
});
|
||||
}
|
||||
|
||||
User.findOne({
|
||||
_id: id
|
||||
}).exec(function(err, user) {
|
||||
}).exec(function (err, user) {
|
||||
if (err) return next(err);
|
||||
if (!user) return next(new Error('Failed to load User ' + id));
|
||||
req.profile = user;
|
||||
|
||||
@@ -9,7 +9,7 @@ var acl = require('acl');
|
||||
acl = new acl(new acl.memoryBackend());
|
||||
|
||||
/**
|
||||
* Invoke Articles Permissions
|
||||
* Invoke Admin Permissions
|
||||
*/
|
||||
exports.invokeRolesPolicies = function () {
|
||||
acl.allow([{
|
||||
@@ -3,19 +3,22 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var adminPolicy = require('../policies/admin.server.policies'),
|
||||
var adminPolicy = require('../policies/admin.server.policy'),
|
||||
admin = require('../controllers/admin.server.controller');
|
||||
|
||||
module.exports = function (app) {
|
||||
// User route registration first. Ref: #713
|
||||
require('./users.server.routes.js')(app);
|
||||
|
||||
// Users collection routes
|
||||
app.route('/api/users').all(adminPolicy.isAllowed)
|
||||
.get(admin.list);
|
||||
app.route('/api/users')
|
||||
.get(adminPolicy.isAllowed, admin.list);
|
||||
|
||||
// Single user routes
|
||||
app.route('/api/users/:userId').all(adminPolicy.isAllowed)
|
||||
.get(admin.read)
|
||||
.put(admin.update)
|
||||
.delete(admin.delete);
|
||||
app.route('/api/users/:userId')
|
||||
.get(adminPolicy.isAllowed, admin.read)
|
||||
.put(adminPolicy.isAllowed, admin.update)
|
||||
.delete(adminPolicy.isAllowed, admin.delete);
|
||||
|
||||
// Finish by binding the user middleware
|
||||
app.param('userId', admin.userByID);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function(app) {
|
||||
module.exports = function (app) {
|
||||
// User Routes
|
||||
var users = require('../controllers/users.server.controller');
|
||||
|
||||
|
||||
@@ -1,118 +1,146 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
// Authentication controller Spec
|
||||
describe('AuthenticationController', function() {
|
||||
// Initialize global variables
|
||||
var AuthenticationController,
|
||||
scope,
|
||||
$httpBackend,
|
||||
$stateParams,
|
||||
$location;
|
||||
// Authentication controller Spec
|
||||
describe('AuthenticationController', function() {
|
||||
// Initialize global variables
|
||||
var AuthenticationController,
|
||||
scope,
|
||||
$httpBackend,
|
||||
$stateParams,
|
||||
$location;
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.addMatchers({
|
||||
toEqualData: function(util, customEqualityTesters) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
return {
|
||||
pass: angular.equals(actual, expected)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
beforeEach(function() {
|
||||
jasmine.addMatchers({
|
||||
toEqualData: function(util, customEqualityTesters) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
return {
|
||||
pass: angular.equals(actual, expected)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
|
||||
// This allows us to inject a service but then attach it to a variable
|
||||
// with the same name as the service.
|
||||
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
describe('Logged out user', function() {
|
||||
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
|
||||
// This allows us to inject a service but then attach it to a variable
|
||||
// with the same name as the service.
|
||||
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
// Point global variables to injected services
|
||||
$stateParams = _$stateParams_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$location = _$location_;
|
||||
// Point global variables to injected services
|
||||
$stateParams = _$stateParams_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$location = _$location_;
|
||||
|
||||
// Initialize the Authentication controller
|
||||
AuthenticationController = $controller('AuthenticationController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
// Initialize the Authentication controller
|
||||
AuthenticationController = $controller('AuthenticationController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
|
||||
describe('$scope.signin()', function() {
|
||||
it('should login with a correct user and password', function() {
|
||||
// Test expected GET request
|
||||
$httpBackend.when('POST', '/api/auth/signin').respond(200, 'Fred');
|
||||
|
||||
it('$scope.signin() should login with a correct user and password', function() {
|
||||
// Test expected GET request
|
||||
$httpBackend.when('POST', '/api/auth/signin').respond(200, 'Fred');
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
// Test scope value
|
||||
expect(scope.authentication.user).toEqual('Fred');
|
||||
expect($location.url()).toEqual('/');
|
||||
});
|
||||
|
||||
// Test scope value
|
||||
expect(scope.authentication.user).toEqual('Fred');
|
||||
expect($location.url()).toEqual('/');
|
||||
});
|
||||
it('should fail to log in with nothing', function() {
|
||||
// Test expected POST request
|
||||
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
|
||||
'message': 'Missing credentials'
|
||||
});
|
||||
|
||||
it('$scope.signin() should fail to log in with nothing', function() {
|
||||
// Test expected POST request
|
||||
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
|
||||
'message': 'Missing credentials'
|
||||
});
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
// Test scope value
|
||||
expect(scope.error).toEqual('Missing credentials');
|
||||
});
|
||||
|
||||
// Test scope value
|
||||
expect(scope.error).toEqual('Missing credentials');
|
||||
});
|
||||
it('should fail to log in with wrong credentials', function() {
|
||||
// Foo/Bar combo assumed to not exist
|
||||
scope.authentication.user = 'Foo';
|
||||
scope.credentials = 'Bar';
|
||||
|
||||
it('$scope.signin() should fail to log in with wrong credentials', function() {
|
||||
// Foo/Bar combo assumed to not exist
|
||||
scope.authentication.user = 'Foo';
|
||||
scope.credentials = 'Bar';
|
||||
// Test expected POST request
|
||||
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
|
||||
'message': 'Unknown user'
|
||||
});
|
||||
|
||||
// Test expected POST request
|
||||
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
|
||||
'message': 'Unknown user'
|
||||
});
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
|
||||
scope.signin();
|
||||
$httpBackend.flush();
|
||||
// Test scope value
|
||||
expect(scope.error).toEqual('Unknown user');
|
||||
});
|
||||
});
|
||||
|
||||
// Test scope value
|
||||
expect(scope.error).toEqual('Unknown user');
|
||||
});
|
||||
describe('$scope.signup()', function() {
|
||||
it('should register with correct data', function() {
|
||||
// Test expected GET request
|
||||
scope.authentication.user = 'Fred';
|
||||
$httpBackend.when('POST', '/api/auth/signup').respond(200, 'Fred');
|
||||
|
||||
it('$scope.signup() should register with correct data', function() {
|
||||
// Test expected GET request
|
||||
scope.authentication.user = 'Fred';
|
||||
$httpBackend.when('POST', '/api/auth/signup').respond(200, 'Fred');
|
||||
scope.signup();
|
||||
$httpBackend.flush();
|
||||
|
||||
scope.signup();
|
||||
$httpBackend.flush();
|
||||
// test scope value
|
||||
expect(scope.authentication.user).toBe('Fred');
|
||||
expect(scope.error).toEqual(undefined);
|
||||
expect($location.url()).toBe('/');
|
||||
});
|
||||
|
||||
// test scope value
|
||||
expect(scope.authentication.user).toBe('Fred');
|
||||
expect(scope.error).toEqual(undefined);
|
||||
expect($location.url()).toBe('/');
|
||||
});
|
||||
it('should fail to register with duplicate Username', function() {
|
||||
// Test expected POST request
|
||||
$httpBackend.when('POST', '/api/auth/signup').respond(400, {
|
||||
'message': 'Username already exists'
|
||||
});
|
||||
|
||||
it('$scope.signup() should fail to register with duplicate Username', function() {
|
||||
// Test expected POST request
|
||||
$httpBackend.when('POST', '/api/auth/signup').respond(400, {
|
||||
'message': 'Username already exists'
|
||||
});
|
||||
scope.signup();
|
||||
$httpBackend.flush();
|
||||
|
||||
scope.signup();
|
||||
$httpBackend.flush();
|
||||
// Test scope value
|
||||
expect(scope.error).toBe('Username already exists');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Test scope value
|
||||
expect(scope.error).toBe('Username already exists');
|
||||
});
|
||||
});
|
||||
describe('Logged in user', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _$location_, _Authentication_) {
|
||||
scope = $rootScope.$new();
|
||||
|
||||
$location = _$location_;
|
||||
$location.path = jasmine.createSpy().and.returnValue(true);
|
||||
|
||||
// Mock logged in user
|
||||
_Authentication_.user = {
|
||||
username: 'test',
|
||||
roles: ['user']
|
||||
};
|
||||
|
||||
AuthenticationController = $controller('AuthenticationController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
|
||||
it('should be redirected to home', function() {
|
||||
expect($location.path).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
198
modules/users/tests/client/password.client.controller.tests.js
Normal file
198
modules/users/tests/client/password.client.controller.tests.js
Normal file
@@ -0,0 +1,198 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
// Authentication controller Spec
|
||||
describe('PasswordController', function() {
|
||||
// Initialize global variables
|
||||
var PasswordController,
|
||||
scope,
|
||||
$httpBackend,
|
||||
$stateParams,
|
||||
$location,
|
||||
$window;
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.addMatchers({
|
||||
toEqualData: function(util, customEqualityTesters) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
return {
|
||||
pass: angular.equals(actual, expected)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
describe('Logged in user', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _Authentication_, _$stateParams_, _$httpBackend_, _$location_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
// Point global variables to injected services
|
||||
$stateParams = _$stateParams_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$location = _$location_;
|
||||
$location.path = jasmine.createSpy().and.returnValue(true);
|
||||
|
||||
// Mock logged in user
|
||||
_Authentication_.user = {
|
||||
username: 'test',
|
||||
roles: ['user']
|
||||
};
|
||||
|
||||
// Initialize the Authentication controller
|
||||
PasswordController = $controller('PasswordController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
|
||||
it('should redirect logged in user to home', function() {
|
||||
expect($location.path).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Logged out user', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _$window_, _$stateParams_, _$httpBackend_, _$location_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
// Point global variables to injected services
|
||||
$stateParams = _$stateParams_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$location = _$location_;
|
||||
$location.path = jasmine.createSpy().and.returnValue(true);
|
||||
$window = _$window_;
|
||||
$window.user = null;
|
||||
|
||||
// Initialize the Authentication controller
|
||||
PasswordController = $controller('PasswordController', {
|
||||
$scope: scope
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not redirect to home', function() {
|
||||
expect($location.path).not.toHaveBeenCalledWith('/');
|
||||
});
|
||||
|
||||
describe('askForPasswordReset', function() {
|
||||
var credentials = {
|
||||
username: 'test',
|
||||
password: 'test'
|
||||
};
|
||||
beforeEach(function() {
|
||||
scope.credentials = credentials;
|
||||
});
|
||||
|
||||
it('should clear scope.success and scope.error', function() {
|
||||
scope.success = 'test';
|
||||
scope.error = 'test';
|
||||
scope.askForPasswordReset();
|
||||
|
||||
expect(scope.success).toBeNull();
|
||||
expect(scope.error).toBeNull();
|
||||
});
|
||||
|
||||
describe('POST error', function() {
|
||||
var errorMessage = 'No account with that username has been found';
|
||||
beforeEach(function() {
|
||||
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond(400, {
|
||||
'message': errorMessage
|
||||
});
|
||||
|
||||
scope.askForPasswordReset();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear form', function() {
|
||||
expect(scope.credentials).toBe(null);
|
||||
});
|
||||
|
||||
it('should set error to response message', function() {
|
||||
expect(scope.error).toBe(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST success', function() {
|
||||
var successMessage = 'An email has been sent to the provided email with further instructions.';
|
||||
beforeEach(function() {
|
||||
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond({
|
||||
'message': successMessage
|
||||
});
|
||||
|
||||
scope.askForPasswordReset();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear form', function() {
|
||||
expect(scope.credentials).toBe(null);
|
||||
});
|
||||
|
||||
it('should set success to response message', function() {
|
||||
expect(scope.success).toBe(successMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetUserPassword', function() {
|
||||
var token = 'testToken';
|
||||
var passwordDetails = {
|
||||
password: 'test'
|
||||
};
|
||||
beforeEach(function() {
|
||||
$stateParams.token = token;
|
||||
scope.passwordDetails = passwordDetails;
|
||||
});
|
||||
|
||||
it('should clear scope.success and scope.error', function() {
|
||||
scope.success = 'test';
|
||||
scope.error = 'test';
|
||||
scope.resetUserPassword();
|
||||
|
||||
expect(scope.success).toBeNull();
|
||||
expect(scope.error).toBeNull();
|
||||
});
|
||||
|
||||
it('POST error should set scope.error to response message', function() {
|
||||
var errorMessage = 'Passwords do not match';
|
||||
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(400, {
|
||||
'message': errorMessage
|
||||
});
|
||||
|
||||
scope.resetUserPassword();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(scope.error).toBe(errorMessage);
|
||||
});
|
||||
|
||||
describe('POST success', function() {
|
||||
var user = {
|
||||
username: 'test'
|
||||
};
|
||||
beforeEach(function() {
|
||||
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(user);
|
||||
|
||||
scope.resetUserPassword();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear password form', function() {
|
||||
expect(scope.passwordDetails).toBe(null);
|
||||
});
|
||||
|
||||
it('should attach user profile', function() {
|
||||
expect(scope.authentication.user).toEqual(user);
|
||||
});
|
||||
|
||||
it('should redirect to password reset success view', function() {
|
||||
expect($location.path).toHaveBeenCalledWith('/password/reset/success');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
107
modules/users/tests/server/user.server.routes.tests.js
Normal file
107
modules/users/tests/server/user.server.routes.tests.js
Normal file
@@ -0,0 +1,107 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('should'),
|
||||
request = require('supertest'),
|
||||
path = require('path'),
|
||||
mongoose = require('mongoose'),
|
||||
User = mongoose.model('User'),
|
||||
express = require(path.resolve('./config/lib/express'));
|
||||
|
||||
/**
|
||||
* Globals
|
||||
*/
|
||||
var app, agent, credentials, user, admin;
|
||||
|
||||
/**
|
||||
* User routes tests
|
||||
*/
|
||||
describe('User CRUD tests', function () {
|
||||
before(function (done) {
|
||||
// Get application
|
||||
app = express.init(mongoose);
|
||||
agent = request.agent(app);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
// Create user credentials
|
||||
credentials = {
|
||||
username: 'username',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Create a new user
|
||||
user = new User({
|
||||
firstName: 'Full',
|
||||
lastName: 'Name',
|
||||
displayName: 'Full Name',
|
||||
email: 'test@test.com',
|
||||
username: credentials.username,
|
||||
password: credentials.password,
|
||||
provider: 'local'
|
||||
});
|
||||
|
||||
// Save a user to the test db and create new article
|
||||
user.save(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not be able to retrieve a list of users if not admin', function (done) {
|
||||
agent.post('/api/auth/signin')
|
||||
.send(credentials)
|
||||
.expect(200)
|
||||
.end(function (signinErr, signinRes) {
|
||||
// Handle signin error
|
||||
if (signinErr) {
|
||||
return done(signinErr);
|
||||
}
|
||||
|
||||
// Save a new article
|
||||
agent.get('/api/users')
|
||||
.expect(403)
|
||||
.end(function (usersGetErr, usersGetRes) {
|
||||
if (usersGetErr) {
|
||||
return done(usersGetErr);
|
||||
}
|
||||
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to retrieve a list of users if admin', function (done) {
|
||||
user.roles = ['user', 'admin'];
|
||||
|
||||
user.save(function () {
|
||||
agent.post('/api/auth/signin')
|
||||
.send(credentials)
|
||||
.expect(200)
|
||||
.end(function (signinErr, signinRes) {
|
||||
// Handle signin error
|
||||
if (signinErr) {
|
||||
return done(signinErr);
|
||||
}
|
||||
|
||||
// Save a new article
|
||||
agent.get('/api/users')
|
||||
.expect(200)
|
||||
.end(function (usersGetErr, usersGetRes) {
|
||||
if (usersGetErr) {
|
||||
return done(usersGetErr);
|
||||
}
|
||||
|
||||
usersGetRes.body.should.be.instanceof(Array).and.have.lengthOf(1);
|
||||
|
||||
// Call the assertion callback
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
User.remove().exec(done);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user