diff --git a/app/controllers/users/users.authentication.server.controller.js b/app/controllers/users/users.authentication.server.controller.js index cbe2d4d8..ecd4cc2c 100755 --- a/app/controllers/users/users.authentication.server.controller.js +++ b/app/controllers/users/users.authentication.server.controller.js @@ -32,10 +32,10 @@ exports.validateVerificationToken = function(req, res, next){ exports.resendVerificationEmail = function(req, res, next){ nev.resendVerificationEmail(req.body.email, function(user) { if (user){ - res.status(200).send('User successfully verified'); + res.status(200).send('Verification email successfully Re-Sent'); }else { // user hasn't been found yet - res.status(400).send( {message: 'Error: User could NOT be verified'} ); + res.status(400).send( {message: 'Error: Verification Email could NOT be sent'} ); } }); }; diff --git a/karma.conf.js b/karma.conf.js index dd6b2be1..7c0203e6 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -3,7 +3,10 @@ /** * Module dependencies. */ -var applicationConfiguration = require('./config/config'); +var applicationConfiguration = require('./config/config'), + bowerFiles = require('main-bower-files'); + +var bowerDep = bowerFiles('**/**.js'); // Karma configuration module.exports = function(config) { @@ -17,11 +20,6 @@ module.exports = function(config) { // Test results reporter to use // Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' reporters: ['mocha', 'html', 'progress'], - - // plugins: [ - // 'karma-jasmine', - // 'karma-mocha-reporter', - // ], // Web server port port: 9876, @@ -29,6 +27,14 @@ module.exports = function(config) { // Enable / disable colors in the output (reporters and logs) colors: true, + //Make sure we capture console.log output + client: { + captureConsole: true, + mocha: { + bail: true + } + }, + // Level of logging // Possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, diff --git a/public/application.js b/public/application.js index 2c9db1ce..7db87c97 100755 --- a/public/application.js +++ b/public/application.js @@ -24,55 +24,55 @@ angular.module(ApplicationConfiguration.applicationModuleName).constant('USER_RO superuser: 'superuser', }); -angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams', - function($rootScope, Auth, $state, $stateParams) { +// angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams', +// function($rootScope, Auth, $state, $stateParams) { - $rootScope.$state = $state; - $rootScope.$stateParams = $stateParams; +// $rootScope.$state = $state; +// $rootScope.$stateParams = $stateParams; - // add previous state property - $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) { - $state.previous = fromState; +// // add previous state property +// $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) { +// $state.previous = fromState; - //Redirect to listForms if user is authenticated - if(toState.name === 'home' || toState.name === 'signin' || toState.name === 'resendVerifyEmail' || toState.name === 'verify' || toState.name === 'signup' || toState.name === 'signup-success'){ - if(Auth.isAuthenticated()){ - event.preventDefault(); // stop current execution - $state.go('listForms'); // go to listForms page - } - } - //Redirect to 'home' route if user is not authenticated - else if(toState.name !== 'access_denied' && !Auth.isAuthenticated() ){ - event.preventDefault(); // stop current execution - $state.go('home'); // go to listForms page - } +// //Redirect to listForms if user is authenticated +// if(toState.name === 'home' || toState.name === 'signin' || toState.name === 'resendVerifyEmail' || toState.name === 'verify' || toState.name === 'signup' || toState.name === 'signup-success'){ +// if(Auth.isAuthenticated()){ +// event.preventDefault(); // stop current execution +// $state.go('listForms'); // go to listForms page +// } +// } +// //Redirect to 'home' route if user is not authenticated +// else if(toState.name !== 'access_denied' && !Auth.isAuthenticated() ){ +// event.preventDefault(); // stop current execution +// $state.go('home'); // go to listForms page +// } - }); +// }); - } -]); +// } +// ]); -//Page access/authorization logic -angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', 'User', 'Authorizer', '$state', '$stateParams', - function($rootScope, Auth, User, Authorizer, $state, $stateParams) { - $rootScope.$on('$stateChangeStart', function(event, next) { - var authenticator, permissions, user; - permissions = next && next.data && next.data.permissions ? next.data.permissions : null; +// //Page access/authorization logic +// angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', 'User', 'Authorizer', '$state', '$stateParams', +// function($rootScope, Auth, User, Authorizer, $state, $stateParams) { +// $rootScope.$on('$stateChangeStart', function(event, next) { +// var authenticator, permissions, user; +// permissions = next && next.data && next.data.permissions ? next.data.permissions : null; - Auth.ensureHasCurrentUser(User); - user = Auth.currentUser; +// Auth.ensureHasCurrentUser(User); +// user = Auth.currentUser; - if(user){ - authenticator = new Authorizer(user); +// if(user){ +// authenticator = new Authorizer(user); - if( (permissions !== null) && !authenticator.canAccess(permissions) ){ - event.preventDefault(); - console.log('access denied') - $state.go('access_denied'); - } - } - }); -}]); +// if( (permissions !== null) && !authenticator.canAccess(permissions) ){ +// event.preventDefault(); +// console.log('access denied') +// $state.go('access_denied'); +// } +// } +// }); +// }]); //Then define the init function for starting up the application angular.element(document).ready(function() { diff --git a/public/modules/forms/controllers/admin-form.client.controller.js b/public/modules/forms/controllers/admin-form.client.controller.js index 8f442342..39fbed6c 100644 --- a/public/modules/forms/controllers/admin-form.client.controller.js +++ b/public/modules/forms/controllers/admin-form.client.controller.js @@ -4,7 +4,6 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$modal', function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $modal) { - var deleteModal; $scope = $rootScope; $scope.myform = CurrentForm.getForm(); @@ -17,7 +16,6 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope }); CurrentForm.setForm($scope.myform); }; - $scope.setForm = function(form){ $scope.myform = form; }; @@ -31,82 +29,70 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope ** DeleteModal Functions */ $scope.openDeleteModal = function(){ - - deleteModal = $modal.open({ + $scope.deleteModal = $modal.open({ animation: $scope.animationsEnabled, templateUrl: 'myModalContent.html', controller: 'AdminFormController', }); }; $scope.cancelDeleteModal = function(){ - if(deleteModal){ - deleteModal.dismiss('cancel'); + if($scope.deleteModal){ + $scope.deleteModal.dismiss('cancel'); } }; // Remove existing Form - $scope.remove = function(form_id) { - if(deleteModal && deleteModal.opened){ + $scope.removeCurrentForm = function() { + if($scope.deleteModal && $scope.deleteModal.opened){ - deleteModal.close(); + $scope.deleteModal.close(); - var form = {}; - if(!form_id){ - form = CurrentForm.getForm(); - if(!form) form = $scope.myform; - }else { - form._id = form_id; - } + var form_id = $scope.myform._id; + if(!form_id) throw new Error('Error - removeCurrentForm(): $scope.myform._id does not exist'); - $http.delete('/forms/'+form._id) + $http.delete('/forms/'+form_id) .success(function(data, status, headers){ console.log('form deleted successfully'); - if(!form_id){ - $state.go('listForms', {}, {reload: true}); - } - if($scope.myforms.length > 0){ - $scope.myforms = _.filter($scope.myforms, function(myform){ - return myform._id !== form._id; - }); - } + $state.go('listForms', {}, {reload: true}); }).error(function(error){ console.log('ERROR: Form could not be deleted.'); console.error(error); - }).finally(function(){ - }); } }; - // Update existing Form - $scope.update = $rootScope.update = function(shouldUpdateNow, cb){ - // console.log('shouldUpdateNow: '+shouldUpdateNow); + $scope.update = $rootScope.update = function(updateImmediately, cb){ + var continueUpdate = true; - if(shouldUpdateNow){ - continueUpdate = !$rootScope.saveInProgress; + if(!updateImmediately){ + continueUpdate = !$rootScope.saveInProgress; } + //Update form if we **are not currently updating** or if **shouldUpdateNow flag is set** if(continueUpdate){ - console.log('begin updating form'); + // console.log('begin updating form'); var err = null; - if(shouldUpdateNow){ $rootScope.saveInProgress = true; } + if(!updateImmediately){ $rootScope.saveInProgress = true; } $scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform}) .then(function(response){ $rootScope.myform = $scope.myform = response.data; - console.log(response.data); + // console.log(response.data); }).catch(function(response){ - console.log('Error occured during form UPDATE.\n'); - console.log(response.data); + // console.log('Error occured during form UPDATE.\n'); + // console.log(response.data); err = response.data; }).finally(function() { - console.log('finished updating'); - if(shouldUpdateNow){$rootScope.saveInProgress = false; } - cb(err); + // console.log('finished updating'); + if(!updateImmediately){$rootScope.saveInProgress = false; } + + if( (typeof cb) === 'function'){ + cb(err); + } }); } }; diff --git a/public/modules/forms/controllers/list-forms.client.controller.js b/public/modules/forms/controllers/list-forms.client.controller.js index 6e782007..52f54043 100644 --- a/public/modules/forms/controllers/list-forms.client.controller.js +++ b/public/modules/forms/controllers/list-forms.client.controller.js @@ -1,7 +1,7 @@ 'use strict'; // Forms controller -angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm','$http', +angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http) { $scope = $rootScope; @@ -33,13 +33,14 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope $state.go(route, {'formId': id}, {reload: true}); }; - $scope.duplicate = function(form, form_index){ + $scope.duplicate = function(form_index){ + var form = $scope.myforms[form_index]; delete form._id; $http.post('/forms', {form: form}) .success(function(data, status, headers){ - console.log('form duplicated'); - $scope.myforms.splice(form_index, 0, data); + // console.log('form duplicated'); + $scope.myforms.splice(form_index+1, 0, data); }).error(function(errorResponse){ console.log(errorResponse); $scope.error = errorResponse.data.message; @@ -69,19 +70,16 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope } }; - $scope.removeFromList = function(deleted_form_id) { + $scope.removeForm = function(form_index) { + if(form_index >= $scope.myforms.length || form_index < 0){ + throw new Error('Error: form_index in removeForm() must be between 0 and '+$scope.myforms.length-1); + } - console.log('Remove existing form'); - - $http.delete('/forms/'+deleted_form_id) + $http.delete('/forms/'+$scope.myforms[form_index]._id) .success(function(data, status, headers){ console.log('form deleted successfully'); - if($scope.myforms.length > 0){ - $scope.myforms = _.filter($scope.myforms, function(myform){ - return myform._id !== deleted_form_id; - }); - } + $scope.myforms.splice(form_index, 1); }).error(function(error){ console.log('ERROR: Form could not be deleted.'); diff --git a/public/modules/forms/directives/auto-save.client.directive.js b/public/modules/forms/directives/auto-save.client.directive.js index ea5c7830..7bd69c65 100644 --- a/public/modules/forms/directives/auto-save.client.directive.js +++ b/public/modules/forms/directives/auto-save.client.directive.js @@ -37,12 +37,10 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun var debounceSave = function () { $rootScope.saveInProgress = true; - $rootScope[$attrs.autoSaveCallback](false, + $rootScope[$attrs.autoSaveCallback](true, function(err){ if(!err){ console.log('\n\nForm data persisted -- setting pristine flag'); - // console.log('\n\n---------\nUpdate form CLIENT'); - // console.log(Date.now()); $formCtrl.$setPristine(); }else{ console.error('Error form data NOT persisted'); @@ -51,7 +49,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun }); }; - + //Update/save Form if any Form fields are Dirty and Touched $scope.$watch(function(newValue, oldValue) { if($scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){ debounceSave(); @@ -86,7 +84,9 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun console.log('Saving Form'); debounceSave(); }); - }else if($rootScope.finishedRender && $rootScope.saveInProgress){ + } + //If we are finished rendering then form saving should be finished + else if($rootScope.finishedRender && $rootScope.saveInProgress){ $rootScope.saveInProgress = false; } diff --git a/public/modules/forms/services/current-form.client.service.js b/public/modules/forms/services/current-form.client.service.js index 0c1c37ad..b95b3bc3 100644 --- a/public/modules/forms/services/current-form.client.service.js +++ b/public/modules/forms/services/current-form.client.service.js @@ -1,8 +1,8 @@ 'use strict'; //Forms service used for communicating with the forms REST endpoints -angular.module('forms').service('CurrentForm', ['Forms', - function(Forms){ +angular.module('forms').service('CurrentForm', + function(){ //Private variables var _form = {}; @@ -15,4 +15,4 @@ angular.module('forms').service('CurrentForm', ['Forms', _form = form; }; } -]); \ No newline at end of file +); \ No newline at end of file diff --git a/public/modules/forms/services/forms.client.service.js b/public/modules/forms/services/forms.client.service.js index 06e33d45..abae0c91 100644 --- a/public/modules/forms/services/forms.client.service.js +++ b/public/modules/forms/services/forms.client.service.js @@ -3,21 +3,22 @@ //Forms service used for communicating with the forms REST endpoints angular.module('forms').factory('Forms', ['$resource', function($resource) { - return $resource('forms/:formId', { + return $resource('/forms/:formId', { formId: '@_id' }, { 'query' : { method: 'GET', isArray: true, - transformResponse: function(data, header) { - var forms = angular.fromJson(data); - angular.forEach(forms, function(form, idx) { - form.visible_form_fields = _.filter(form.form_fields, function(field){ - return field.deletePreserved === false; - }); //<-- replace each item with an instance of the resource object - }); - return forms; - } + //DAVID: TODO: Do we really need to get visible_form_fields for a Query? + // transformResponse: function(data, header) { + // var forms = angular.fromJson(data); + // angular.forEach(forms, function(form, idx) { + // form.visible_form_fields = _.filter(form.form_fields, function(field){ + // return (field.deletePreserved === false); + // }); + // }); + // return forms; + // } }, 'get' : { method: 'GET', @@ -25,8 +26,8 @@ angular.module('forms').factory('Forms', ['$resource', var form = angular.fromJson(data); form.visible_form_fields = _.filter(form.form_fields, function(field){ - return field.deletePreserved === false; - }); //<-- replace each item with an instance of the resource object + return (field.deletePreserved === false); + }); return form; } }, diff --git a/public/modules/forms/tests/admin-from.client.controller.test.js b/public/modules/forms/tests/admin-from.client.controller.test.js index e8061966..de20eca5 100644 --- a/public/modules/forms/tests/admin-from.client.controller.test.js +++ b/public/modules/forms/tests/admin-from.client.controller.test.js @@ -5,10 +5,74 @@ describe('AdminFormController Tests', function() { // Initialize global variables var AdminFormController, + createAdminFormController, scope, $httpBackend, $stateParams, - $location; + $location, + $state; + + var sampleUser = { + firstName: 'Full', + lastName: 'Name', + email: 'test@test.com', + username: 'test@test.com', + password: 'password', + provider: 'local', + roles: ['user'], + _id: 'ed873933b1f1dea0ce12fab9' + }; + + var sampleForm = { + title: 'Form Title', + admin: 'ed873933b1f1dea0ce12fab9', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '525a8422f6d0f87f0e407a33' + }; + + var expectedForm = { + title: 'Form Title', + admin: 'ed873933b1f1dea0ce12fab9', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + visible_form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '525a8422f6d0f87f0e407a33' + }; + + var fakeModal = function(){ + this.opened = true; + + this.result = function(confirmCallback, cancelCallback) { + //Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog + this.confirmCallBack = confirmCallback; + this.cancelCallback = cancelCallback; + }; + this.close = function( item ) { + //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item + this.opened = false; + this.confirmCallBack( item ); + }; + this.dismiss = function( type ) { + //The user clicked cancel on the modal dialog, call the stored cancel callback + this.opened = false; + this.cancelCallback( type ); + }; + } + + // 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 @@ -29,156 +93,185 @@ }); }); - // Then we can start by loading the main application module + //Mock Users Service + beforeEach(module(function($provide) { + $provide.service('User', function($q) { + return { + getCurrent: function() { + var deferred = $q.defer(); + deferred.resolve( JSON.stringify(sampleUser) ); + return deferred.promise; + }, + login: function(credentials) { + var deferred = $q.defer(); + if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){ + deferred.resolve( JSON.stringify(sampleUser) ); + }else { + deferred.resolve('Error: User could not be loggedin'); + } + + return deferred.promise; + }, + logout: function() { + var deferred = $q.defer(); + deferred.resolve(null); + return deferred.promise; + }, + signup: function(credentials) { + var deferred = $q.defer(); + if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){ + deferred.resolve( JSON.stringify(sampleUser) ); + }else { + deferred.resolve('Error: User could not be signed up'); + } + + return deferred.promise; + } + }; + }); + })); + + //Mock Authentication Service + beforeEach(module(function($provide) { + $provide.service('Auth', function() { + return { + ensureHasCurrentUser: function() { + return sampleUser; + }, + isAuthenticated: function() { + return true; + }, + getUserState: function() { + return true; + } + }; + }); + })); + + // Load the main application module beforeEach(module(ApplicationConfiguration.applicationModuleName)); + beforeEach(module('stateMock')); + + beforeEach(inject(function($modal) { + spyOn($modal, 'open').and.returnValue(new fakeModal()); + })); + // 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_, _$state_, _$stateParams_, _$httpBackend_) { + beforeEach(inject(function($controller, $rootScope, _$state_, _$location_, _$stateParams_, _$httpBackend_, CurrentForm, Forms) { // Set a new global scope scope = $rootScope.$new(); + //Set CurrentForm + CurrentForm.setForm(sampleForm); + // Point global variables to injected services $stateParams = _$stateParams_; $httpBackend = _$httpBackend_; $location = _$location_; + $state = _$state_; + + $httpBackend.whenGET(/\.html$/).respond(''); + $httpBackend.whenGET('/users/me/').respond(''); // Initialize the Forms controller. - AdminFormController = $controller('AdminFormController', { - $scope: scope, - }); + createAdminFormController = function(){ + return $controller('AdminFormController', { $scope: scope }); + }; + })); + + it('AdminFormController should fetch current Form when instantiated', inject(function() { + // Run controller functionality + var controller = createAdminFormController(); + + // Test scope value + expect(scope.myform).toEqualData(sampleForm); })); - //Mock Authentication Service - $provide.value("MyLoginServce", { - ensureHasCurrentUser: function(){ - return true; - }, - redirectForLogin: function {} - }); - it('$scope.findOne() should fetch current Form', inject(function(Forms) { + // Define a sample article object - var sampleForm = new Forms({ - title: 'Form Title', - admin: 'ed873933b1f1dea0ce12fab9', - language: 'english', - form_fields: [ - {'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''}, - {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''}, - {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''} - ] - }); + var expectedFormObj = new Forms(expectedForm); + + var controller = createAdminFormController(); + // Set the URL parameter - $stateParams.formId = '525a8422f6d0f87f0e407a33'; + $stateParams.formId = expectedForm._id; // Set GET response - $httpBackend.expectGET(/forms\/([0-9a-fA-F]{24})$/).respond(sampleForm); + $httpBackend.expectGET(/^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm); // Run controller functionality scope.findOne(); $httpBackend.flush(); // Test scope value - expect(scope.article).toEqualData(sampleArticle); + expect( scope.myform.toJSON() ).toEqualData(expectedFormObj.toJSON()); })); - // it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Forms) { - // // Create sample article using the Forms service - // var sampleArticle = new Forms({ - // title: 'An Article about MEAN', - // content: 'MEAN rocks!' - // }); + it('$scope.removeCurrentForm() with valid form data should send a DELETE request with the id of form', function() { + var controller = createAdminFormController(); - // // Create a sample Forms array that includes the new article - // var sampleForms = [sampleForm]; + //Set expected $state transition + $state.expectTransitionTo('listForms'); - // // Set GET response - // $httpBackend.expectGET('Forms').respond(sampleForms); + // Set DELETE response + $httpBackend.expect('DELETE', /^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm); - // // Run controller functionality - // scope.find(); - // $httpBackend.flush(); + //Run controller functionality + scope.openDeleteModal(); - // // Test scope value - // expect(scope.Forms).toEqualData(sampleForms); - // })); + scope.deleteModal.result(function(selectedItem){ + scope.selected = selectedItem; + }, function(type){ + $scope.canceled = true; + }); + scope.removeCurrentForm(); + + $httpBackend.flush(); + }); - // 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(Forms) { - // // Create a sample article object - // var sampleArticlePostData = new Forms({ - // title: 'An Article about MEAN', - // content: 'MEAN rocks!' - // }); + it('$scope.update() should send a PUT request with the id of form', function() { + var controller = createAdminFormController(); - // // Create a sample article response - // var sampleArticleResponse = new Forms({ - // _id: '525cf20451979dea2c000001', - // title: 'An Article about MEAN', - // content: 'MEAN rocks!' - // }); + //Set PUT response + $httpBackend.expect('PUT', /^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm); - // // Fixture mock form input values - // scope.title = 'An Article about MEAN'; - // scope.content = 'MEAN rocks!'; + //Run controller functionality + scope.update(false, null); - // // Set POST response - // $httpBackend.expectPOST('Forms', sampleArticlePostData).respond(sampleArticleResponse); + $httpBackend.flush(); + }); - // // Run controller functionality - // scope.create(); - // $httpBackend.flush(); + it('$scope.openDeleteModal() should open scope.deleteModal', function() { + var controller = createAdminFormController(); - // // Test form inputs are reset - // expect(scope.title).toEqual(''); - // expect(scope.content).toEqual(''); + //Run controller functionality + scope.openDeleteModal(); + expect( scope.deleteModal.opened ).toEqual(true); + }); - // // Test URL redirection after the article was created - // expect($location.path()).toBe('/Forms/' + sampleArticleResponse._id); - // })); + it('$scope.cancelDeleteModal() should close scope.deleteModal', inject(function($modal) { + var controller = createAdminFormController(); - // it('$scope.update() should update a valid article', inject(function(Forms) { - // // Define a sample article put data - // var sampleArticlePutData = new Forms({ - // _id: '525cf20451979dea2c000001', - // title: 'An Article about MEAN', - // content: 'MEAN Rocks!' - // }); + //Run controller functionality + scope.openDeleteModal(); + console.log(scope.deleteModal.opened); - // // Mock article in scope - // scope.article = sampleArticlePutData; + scope.deleteModal.result(function(selectedItem){ + this.selected = selectedItem; + }, function(type){ + this.canceled = true; + }); - // // Set PUT response - // $httpBackend.expectPUT(/Forms\/([0-9a-fA-F]{24})$/).respond(); + scope.cancelDeleteModal(); + console.log(scope.deleteModal.opened); + expect( scope.deleteModal.opened ).toEqual(false); + expect( scope.deleteModal.canceled ).toEqual(true); - // // Run controller functionality - // scope.update(); - // $httpBackend.flush(); - - // // Test URL location to new object - // expect($location.path()).toBe('/Forms/' + sampleArticlePutData._id); - // })); - - // it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Forms) { - // // Create new article object - // var sampleArticle = new Forms({ - // _id: '525a8422f6d0f87f0e407a33' - // }); - - // // Create new Forms array and include the article - // scope.Forms = [sampleArticle]; - - // // Set expected DELETE response - // $httpBackend.expectDELETE(/Forms\/([0-9a-fA-F]{24})$/).respond(204); - - // // Run controller functionality - // scope.remove(sampleArticle); - // $httpBackend.flush(); - - // // Test array after successful delete - // expect(scope.Forms.length).toBe(0); - // })); + })); }); }()); \ No newline at end of file diff --git a/public/modules/forms/tests/list-forms.client.controller.test.js b/public/modules/forms/tests/list-forms.client.controller.test.js new file mode 100644 index 00000000..5cc7e7cb --- /dev/null +++ b/public/modules/forms/tests/list-forms.client.controller.test.js @@ -0,0 +1,255 @@ +'use strict'; + +(function() { + // Forms Controller Spec + describe('ListFormsController Tests', function() { + // Initialize global variables + var ListFormsController, + createListFormsController, + scope, + $httpBackend, + $stateParams, + $location, + $state; + + var sampleUser = { + firstName: 'Full', + lastName: 'Name', + email: 'test@test.com', + username: 'test@test.com', + password: 'password', + provider: 'local', + roles: ['user'], + _id: 'ed873933b1f1dea0ce12fab9' + }; + + var sampleForm = { + title: 'Form Title', + admin: 'ed873933b1f1dea0ce12fab9', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '525a8422f6d0f87f0e407a33' + }; + + var sampleFormList = [{ + title: 'Form Title1', + admin: 'ed873933b1f1dea0ce12fab9', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '525a8422f6d0f87f0e407a33' + },{ + title: 'Form Title2', + admin: '39223933b1f1dea0ce12fab9', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '52f6d0f87f5a407a384220e3' + },{ + title: 'Form Title3', + admin: '2fab9ed873937f0e1dea0ce1', + language: 'english', + form_fields: [ + {'fieldType':'textfield', 'title':'First Name', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': '', 'deletePreserved': false}, + {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': '', 'deletePreserved': false} + ], + _id: '922f6d0f87fed8730e4e1233' + } + ]; + + + // 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 + // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher. + // When the toEqualData matcher compares two objects, it takes only object properties into + // account and ignores methods. + beforeEach(function() { + jasmine.addMatchers({ + toEqualData: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + return { + pass: angular.equals(actual, expected) + }; + } + }; + } + }); + }); + + //Mock Users Service + beforeEach(module(function($provide) { + $provide.service('User', function($q) { + return { + getCurrent: function() { + var deferred = $q.defer(); + deferred.resolve( JSON.stringify(sampleUser) ); + return deferred.promise; + }, + login: function(credentials) { + var deferred = $q.defer(); + if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){ + deferred.resolve( JSON.stringify(sampleUser) ); + }else { + deferred.resolve('Error: User could not be loggedin'); + } + + return deferred.promise; + }, + logout: function() { + var deferred = $q.defer(); + deferred.resolve(null); + return deferred.promise; + }, + signup: function(credentials) { + var deferred = $q.defer(); + if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){ + deferred.resolve( JSON.stringify(sampleUser) ); + }else { + deferred.resolve('Error: User could not be signed up'); + } + + return deferred.promise; + } + }; + }); + })); + + //Mock Authentication Service + beforeEach(module(function($provide) { + $provide.service('Auth', function() { + return { + ensureHasCurrentUser: function() { + return sampleUser; + }, + isAuthenticated: function() { + return true; + }, + getUserState: function() { + return true; + } + }; + }); + })); + + // Load the main application module + beforeEach(module(ApplicationConfiguration.applicationModuleName)); + + beforeEach(module('stateMock')); + + // 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, _$state_, _$location_, _$stateParams_, _$httpBackend_, CurrentForm, Forms) { + // Set a new global scope + scope = $rootScope.$new(); + + //Set CurrentForm + CurrentForm.setForm(sampleForm); + + // Point global variables to injected services + $stateParams = _$stateParams_; + $httpBackend = _$httpBackend_; + $location = _$location_; + $state = _$state_; + + $httpBackend.whenGET(/\.html$/).respond(''); + $httpBackend.whenGET('/users/me/').respond(''); + + // Initialize the Forms controller. + createListFormsController = function(){ + return $controller('ListFormsController', { $scope: scope }); + }; + })); + + it('$scope.findAll() should query all User\'s Forms', inject(function(Forms) { + + var controller = createListFormsController(); + + // Set GET response + $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList); + + // Run controller functionality + scope.findAll(); + $httpBackend.flush(); + + // Test scope value + expect( scope.myforms ).toEqualData(sampleFormList); + })); + + it('$scope.duplicate() should duplicate a Form', inject(function(Forms) { + + var dupSampleForm = sampleFormList[2], + dupSampleForm_index = 3, + newSampleFormList = sampleFormList; + dupSampleForm._id = 'a02df75b44c1d26b6a5e05b8'; + newSampleFormList.splice(2, 0, dupSampleForm); + + var controller = createListFormsController(); + + // Set GET response + $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList); + + // Run controller functionality + scope.findAll(); + $httpBackend.flush(); + + // Set GET response + $httpBackend.expect('POST', '/forms').respond(200, dupSampleForm); + + // Run controller functionality + scope.duplicate(2); + $httpBackend.flush(); + + // Test scope value + expect( scope.myforms.length ).toEqual(sampleFormList.length+1); + // expect( scope.myforms ).toEqualData(newSampleFormList); + expect( scope.myforms[dupSampleForm_index] ).toEqualData(dupSampleForm); + + })); + + it('$scope.removeForm() should remove a Form', inject(function(Forms) { + + var delIndex = 0, + delSampleForm = sampleFormList[delIndex], + delSampleFormList = sampleFormList; + delSampleFormList.splice(delIndex, 1); + + var controller = createListFormsController(); + + // Set GET response + $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList); + + // Run controller functionality + scope.findAll(); + $httpBackend.flush(); + + // Set GET response + $httpBackend.expect('DELETE', /^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, delSampleForm); + + // Run controller functionality + scope.removeForm(delIndex); + $httpBackend.flush(); + + // Test scope value + expect( scope.myforms.length ).toEqual(sampleFormList.length-1); + for(var i=0; i 0){ + var expectedState = this.expectedTransitions.shift(); + if(expectedState !== stateName){ + throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName ); + } + }else{ + throw Error("No more transitions were expected! Tried to transition to "+ stateName ); + } + console.log("Mock transition to: " + stateName); + var deferred = $q.defer(); + var promise = deferred.promise; + deferred.resolve(); + return promise; + } + this.go = this.transitionTo; + this.expectTransitionTo = function(stateName){ + this.expectedTransitions.push(stateName); + } + + + this.ensureAllTransitionsHappened = function(){ + if(this.expectedTransitions.length > 0){ + throw Error("Not all transitions happened!"); + } + } +}); \ No newline at end of file diff --git a/public/modules/forms/views/admin-form.client.view.html b/public/modules/forms/views/admin-form.client.view.html index f54e3f3c..badd8f73 100644 --- a/public/modules/forms/views/admin-form.client.view.html +++ b/public/modules/forms/views/admin-form.client.view.html @@ -19,7 +19,7 @@

- diff --git a/public/modules/forms/views/directiveViews/form/configure-form.client.view.html b/public/modules/forms/views/directiveViews/form/configure-form.client.view.html index a6581f5e..26be3905 100644 --- a/public/modules/forms/views/directiveViews/form/configure-form.client.view.html +++ b/public/modules/forms/views/directiveViews/form/configure-form.client.view.html @@ -276,7 +276,7 @@
- +
diff --git a/public/modules/forms/views/directiveViews/form/edit-form.client.view.html b/public/modules/forms/views/directiveViews/form/edit-form.client.view.html index 5ce53e73..b57cf5f8 100644 --- a/public/modules/forms/views/directiveViews/form/edit-form.client.view.html +++ b/public/modules/forms/views/directiveViews/form/edit-form.client.view.html @@ -269,15 +269,6 @@
- diff --git a/public/modules/forms/views/list-forms.client.view.html b/public/modules/forms/views/list-forms.client.view.html index 85b0b8d9..d57cb485 100644 --- a/public/modules/forms/views/list-forms.client.view.html +++ b/public/modules/forms/views/list-forms.client.view.html @@ -54,8 +54,8 @@
- - + +
diff --git a/public/modules/users/services/user.client.service.js b/public/modules/users/services/user.client.service.js index dd4b6051..c26242b2 100644 --- a/public/modules/users/services/user.client.service.js +++ b/public/modules/users/services/user.client.service.js @@ -24,7 +24,6 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', ' $http.post('/auth/signin', credentials).success(function(response) { deferred.resolve(response); }).error(function(error) { - deferred.reject(error.message || error); }); return deferred.promise; @@ -79,7 +78,6 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', ' resetPassword: function(passwordDetails, token) { var deferred = $q.defer(); $http.get('/auth/password/'+token, passwordDetails).success(function(response) { - deferred.resolve(); }).error(function(error) { deferred.reject(error.message || error);