diff --git a/example/index.html b/example/index.html index 9f5632c..976a50f 100644 --- a/example/index.html +++ b/example/index.html @@ -70,4 +70,3 @@

Invenio Records Demo

- diff --git a/src/invenio-records-js/invenioRecords.module.js b/src/invenio-records-js/invenioRecords.module.js index a849031..99ff566 100644 --- a/src/invenio-records-js/invenioRecords.module.js +++ b/src/invenio-records-js/invenioRecords.module.js @@ -47,15 +47,19 @@ }; // The form model - vm.invenioRecordsModel = {}; - // Set loading - vm.invenioRecordsLoading = true; + vm.invenioRecordsModel = null; // Set endpoints - vm.invenioRecordsEndpoints = {}; - // Set errors - vm.invenioRecordsError = {}; - // Set notify - vm.invenioRecordsNotify = false; + vm.invenioRecordsEndpoints = null; + + // Record Loading - If the invenioRecords has the state loading + vm.invenioRecordsLoading = true; + + // Record Error - if the invenioRecords has any error + vm.invenioRecordsError = null; + + // Record Warn - if the invenioRecords has any warning + vm.invenioRecordsWarning = null; + // Set action handler if everything is ok var Handler = new InvenioRecordsActionsHandler(); @@ -84,13 +88,13 @@ /** * Initialize the controller * @memberof invenioRecordsController - * @function invenioRecordsInitialize + * @function invenioRecordsInit * @param {Object} evt - The event object. * @param {Object} args - The invenio records arguments. * @param {Object} endpoints - The invenio endpoints for actions. * @param {Object} record - The record object. */ - function invenioRecordsInitialize(evt, args, endpoints, record) { + function invenioRecordsInit(evt, args, endpoints, record) { // Assign the model vm.invenioRecordsModel = angular.copy(record); // Assign the args @@ -112,14 +116,15 @@ invenioRecordsAPI.get(vm.invenioRecordsEndpoints.form) .then(invenioRecordsSetForm) ]).then(function() { - vm.invenioRecordsLoading = false; // Pass the endpoints to the factory Handler.setEndpoint(vm.invenioRecordsEndpoints); + // Remove loading state + $scope.$broadcast('invenio.records.loading.stop'); }); } /** - * Initialize the controller + * Records actions * @memberof invenioRecordsController * @function invenioRecordsActions * @param {Object} evt - The event object. @@ -129,11 +134,7 @@ */ function invenioRecordsActions(evt, type, successCallback, errorCallback) { // Set loading to true - vm.invenioRecordsLoading = true; - // Reset any errors - vm.invenioRecordsError = {}; - // Reset any notifications - vm.invenioRecordsNotify = false; + $scope.$broadcast('invenio.records.loading.start'); // If the type function exists run it if (typeof Handler[type] === 'function') { // Make the request iff the type exists @@ -143,7 +144,8 @@ successCallback || angular.noop, errorCallback || angular.noop ).finally(function() { - vm.invenioRecordsLoading = false; + // Set loading to stop + $scope.$broadcast('invenio.records.loading.stop'); }); } } @@ -162,7 +164,7 @@ * @param {Object} response - The action request response. */ function _actionSuccessful(response) { - vm.invenioRecordsNotify = response.data || 'Successfully deleted!'; + $scope.$broadcast('invenio.records.warn', response); } /** @@ -172,7 +174,7 @@ * @param {Object} response - The action request response. */ function _actionErrored(response) { - vm.invenioRecordsError = response; + $scope.$broadcast('invenio.records.error', response); } // Request submission @@ -184,6 +186,57 @@ ); } + + /** + * Change the state to loading + * @memberof invenioRecordsController + * @function invenioRecordsLoadingStart + * @param {Object} evt - The event object. + */ + function invenioRecordsLoadingStart(evt) { + // Set the state to loading + vm.invenioRecordsLoading = true; + } + + /** + * Change the state to normal + * @memberof invenioRecordsController + * @function invenioRecordsLoadingStop + * @param {Object} evt - The event object. + */ + function invenioRecordsLoadingStop(evt) { + // Set the state to normal + vm.invenioRecordsLoading = false; + } + + /** + * Show error messages + * @memberof invenioRecordsController + * @function invenioRecordsError + * @param {Object} evt - The event object. + * @param {Object} error - The object with the errors. + */ + function invenioRecordsError(evt, error) { + // Reset the error + vm.invenioRecordsError = null; + // Attach the error to the scope + vm.invenioRecordsError = error; + } + + /** + * Show warning messages + * @memberof invenioRecordsController + * @function invenioRecordsWarn + * @param {Object} evt - The event object. + * @param {Object} warning - The object with the warnings. + */ + function invenioRecordsWarn(evt, warning) { + // Reset the error + vm.invenioRecordsWarning = null; + // Attach the warning to the scope + vm.invenioRecordsWarning = warning; + } + // Attach fuctions to the scope vm.actionHandler = invenioRecordsHandler; @@ -191,14 +244,21 @@ // Listeners - // When invenio.records initialization requested - $scope.$on( - 'invenio.records.initialization', invenioRecordsInitialize - ); // When invenio.records action requested - $scope.$on( - 'invenio.records.action', invenioRecordsActions - ); + $scope.$on('invenio.records.action', invenioRecordsActions); + + // When the module initialized + $scope.$on('invenio.records.init', invenioRecordsInit); + + // When there is an error + $scope.$on('invenio.records.error', invenioRecordsError); + // When there is a warning + $scope.$on('invenio.records.warn', invenioRecordsWarn); + + // When loading requested to start + $scope.$on('invenio.records.loading.start', invenioRecordsLoadingStart); + // When loading requested to stop + $scope.$on('invenio.records.loading.stop', invenioRecordsLoadingStop); } // Inject depedencies @@ -272,7 +332,7 @@ * @ngdoc factory * @namei invenioRecordsActionsHandler * @namespace invenioRecordsActionsHandler - * @param {service} $http - Angular http requests service. + * @param {service} invenioRecordsAPI - Invenio Records API. * @param {service} $q - Angular promise service. * @description * Call the records API @@ -426,7 +486,7 @@ // Spread the love of initialization scope.$broadcast( - 'invenio.records.initialization', args, endpoints, record + 'invenio.records.init', args, endpoints, record ); } diff --git a/test/unit/invenio-records-js/controllers/controllersSpec.js b/test/unit/invenio-records-js/controllers/controllersSpec.js new file mode 100644 index 0000000..e0ea652 --- /dev/null +++ b/test/unit/invenio-records-js/controllers/controllersSpec.js @@ -0,0 +1,105 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2016 CERN. + * + * Invenio is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Invenio is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Invenio; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * In applying this license, CERN does not + * waive the privileges and immunities granted to it by virtue of its status + * as an Intergovernmental Organization or submit itself to any jurisdiction. + */ + +'use strict'; + +describe('Unit: testing controllers', function() { + + var $controller; + var $rootScope; + var ctrl; + var scope; + + // Inject the angular module + beforeEach(angular.mock.module('invenioRecords')); + + beforeEach(inject(function(_$controller_, _$rootScope_) { + // Controller + $controller = _$controller_; + // The Scope + $rootScope = _$rootScope_; + // Set the scope + scope = $rootScope; + // The controller + ctrl = $controller('invenioRecordsController', { + $scope: scope, + }); + })); + + it('should have the default parameters', function() { + // Expect loading to be ``true`` + expect(ctrl.invenioRecordsLoading).to.be.equal(true); + + // Expect error to be ``null`` + expect(ctrl.invenioRecordsError).to.be.equal(null); + // Expect notify to be ``null`` + expect(ctrl.invenioRecordsWarning).to.be.equal(null); + + // Expect model to be ``{}`` + expect(ctrl.invenioRecordsModel).to.be.equal(null); + // Expect endpoints to be ``{}`` + expect(ctrl.invenioRecordsEndpoints).to.be.equal(null); + + // Expect the request args + var args = { + url: '/', + method: 'GET' + }; + expect(ctrl.invenioRecordsArgs).to.deep.equal(args); + }); + + it('should trigger the events', function() { + + // Trigger error event + scope.$broadcast('invenio.records.error', { + message: 'Bruce Wayne is not Superman Clark Kent is, dah!' + }); + + // Expect error to be the above message + expect(ctrl.invenioRecordsError.message).to.be.equal( + 'Bruce Wayne is not Superman Clark Kent is, dah!' + ); + + // Trigger warning event + scope.$broadcast('invenio.records.warn', { + message: 'Tell me, do you bleed?' + }); + + // Expect warning to be the above message + expect(ctrl.invenioRecordsWarning.message).to.be.equal( + 'Tell me, do you bleed?' + ); + + // Trigger loading start event + scope.$broadcast('invenio.records.loading.start'); + + // Expect loading to be ``false`` + expect(ctrl.invenioRecordsLoading).to.be.equal(true); + + // Trigger loading start event + scope.$broadcast('invenio.records.loading.stop'); + + // Expect loading to be ``false`` + expect(ctrl.invenioRecordsLoading).to.be.equal(false); + }); +}); diff --git a/test/unit/invenio-records-js/directives/invenioRecordsActionsSpec.js b/test/unit/invenio-records-js/directives/invenioRecordsActionsSpec.js new file mode 100644 index 0000000..54f9700 --- /dev/null +++ b/test/unit/invenio-records-js/directives/invenioRecordsActionsSpec.js @@ -0,0 +1,254 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2016 CERN. + * + * Invenio is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Invenio is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Invenio; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * In applying this license, CERN does not + * waive the privileges and immunities granted to it by virtue of its status + * as an Intergovernmental Organization or submit itself to any jurisdiction. + */ + +'use strict'; + +describe('Unit: testing directive invenio-records-actions', function() { + + var $compile; + var $httpBackend; + var $rootScope; + var scope; + var template; + + // Inject the angular module + beforeEach(angular.mock.module('invenioRecords')); + + // Load the templates + beforeEach(angular.mock.module('templates')); + + beforeEach(inject(function(_$compile_, _$rootScope_, _$httpBackend_) { + // Template compiler + $compile = _$compile_; + // The Scope + $rootScope = _$rootScope_; + // The http backend + $httpBackend = _$httpBackend_; + // Expected requests responses + var schema = { + data: { + question: 'Do you bleed?', + answer: 'You will!' + } + }; + var form = { + data: { + jarvis: 'Where is Jessica Jones and Luke?', + answer: 'They are with the Punisher' + } + }; + + $httpBackend.whenGET('/example/static/json/form.json').respond(200, form); + $httpBackend.whenGET('/example/static/json/schema.json').respond(200, schema); + $httpBackend.whenPOST('gotham city://batman/sucess').respond(200, {}); + $httpBackend.whenPOST('metropolitan://superman/init').respond(200, { + self: 'gotham city://batman/sucess' + }); + $httpBackend.whenDELETE('gotham city://batman/sucess').respond(200, {}); + $httpBackend.whenPOST('gotham city://batman/error').respond(500, { + message: 'Bruce Wayne is with Wonder Woman and Superman right now!' + }); + $httpBackend.whenDELETE('gotham city://batman/error').respond(500, { + message: 'Bruce Wayne is with Wonder Woman and Superman right now!' + }); + + // Attach it + scope = $rootScope; + + })); + + it('should have the action buttons', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + + // Digest + scope.$digest(); + // The rendered buttons should be ``2`` + expect(template.find('.btn').length).to.be.equal(2); + }); + + it('should trigger action event for save', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Spy the broadcast + var spy = sinon.spy($rootScope, '$broadcast') + + // Flash responses to trigger the events + $httpBackend.flush(); + // Trigger an event + template.find('.btn').eq(0).triggerHandler('click'); + + // Should trigger an event + spy.should.have.been.called.twice; + + // Flash responses to trigger the events + $httpBackend.flush(); + // Expect no errors + expect(scope.vm.invenioRecordsError).to.be.equal(null); + }); + + it('should trigger action event for delete', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Spy the broadcast + var spy = sinon.spy($rootScope, '$broadcast') + + // Flash responses to trigger the events + $httpBackend.flush(); + // Trigger an event + template.find('.btn').eq(1).triggerHandler('click'); + + // Should trigger an event + spy.should.have.been.called.twice; + + // Flash responses to trigger the events + $httpBackend.flush(); + // Expect no errors + expect(scope.vm.invenioRecordsError).to.be.equal(null); + }); + + it('should trigger error for delete', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Flash responses to trigger the events + $httpBackend.flush(); + + // Trigger an event + template.find('.btn').eq(1).triggerHandler('click'); + // Flash responses to trigger the events + $httpBackend.flush(); + // Expect error + var error = 'Bruce Wayne is with Wonder Woman and Superman right now!'; + + // Expect the message to be + expect(scope.vm.invenioRecordsError.data.message).to.be.equal(error); + }); + + it('should trigger error for save', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Flash responses to trigger the events + $httpBackend.flush(); + + // Trigger an event + template.find('.btn').eq(0).triggerHandler('click'); + // Flash responses to trigger the events + $httpBackend.flush(); + // Expect error + var error = 'Bruce Wayne is with Wonder Woman and Superman right now!'; + + // Expect the message to be + expect(scope.vm.invenioRecordsError.data.message).to.be.equal(error); + }); + + it('should trigger action with create', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ' ' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Spy the broadcast + var spy = sinon.spy($rootScope, '$broadcast') + + // Flash responses to trigger the events + $httpBackend.flush(); + + // Trigger an event + template.find('.btn').eq(0).triggerHandler('click'); + + // Should trigger an event + spy.should.have.been.called.twice; + }); +}); diff --git a/test/unit/invenio-records-js/directives/invenioRecordsErrorSpec.js b/test/unit/invenio-records-js/directives/invenioRecordsErrorSpec.js new file mode 100644 index 0000000..8f36660 --- /dev/null +++ b/test/unit/invenio-records-js/directives/invenioRecordsErrorSpec.js @@ -0,0 +1,89 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2016 CERN. + * + * Invenio is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Invenio is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Invenio; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * In applying this license, CERN does not + * waive the privileges and immunities granted to it by virtue of its status + * as an Intergovernmental Organization or submit itself to any jurisdiction. + */ + +'use strict'; + +describe('Unit: testing directive invenio-records-error', function() { + + var $compile; + var $httpBackend; + var $rootScope; + var scope; + var template; + + // Inject the angular module + beforeEach(angular.mock.module('invenioRecords')); + + // Load the templates + beforeEach(angular.mock.module('templates')); + + beforeEach(inject(function(_$compile_, _$rootScope_, _$httpBackend_) { + // Template compiler + $compile = _$compile_; + // The Scope + $rootScope = _$rootScope_; + // The http backend + $httpBackend = _$httpBackend_; + // Expected requests responses + var schema = { + question: 'Do you bleed?', + answer: 'You will!' + }; + var form = { + jarvis: 'Where is Jessica Jones and Luke?', + answer: 'They are with the Punisher' + }; + + $httpBackend.whenGET('/example/static/json/form.json').respond(200, form); + $httpBackend.whenGET('/example/static/json/schema.json').respond(200, schema); + + // Attach it + scope = $rootScope; + // Complile&Digest here to catch the event + // The directive's template + template = '' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + })); + + it('should display the error', function() { + var message = { + message: 'Harley Quinn looking for Jessica Jones' + }; + scope.$broadcast('invenio.records.error', message); + expect(scope.vm.invenioRecordsError) + .to.deep.equal(message); + }); +}); diff --git a/test/unit/invenio-records-js/directives/invenioRecordsFormSpec.js b/test/unit/invenio-records-js/directives/invenioRecordsFormSpec.js new file mode 100644 index 0000000..1cb858e --- /dev/null +++ b/test/unit/invenio-records-js/directives/invenioRecordsFormSpec.js @@ -0,0 +1,84 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2016 CERN. + * + * Invenio is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Invenio is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Invenio; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * In applying this license, CERN does not + * waive the privileges and immunities granted to it by virtue of its status + * as an Intergovernmental Organization or submit itself to any jurisdiction. + */ + +'use strict'; + +describe('Unit: testing directive invenio-records-form', function() { + + var $compile; + var $httpBackend; + var $rootScope; + var scope; + var template; + + // Inject the angular module + beforeEach(angular.mock.module('invenioRecords')); + + // Load the templates + beforeEach(angular.mock.module('templates')); + + beforeEach(inject(function(_$compile_, _$rootScope_, _$httpBackend_) { + // Template compiler + $compile = _$compile_; + // The Scope + $rootScope = _$rootScope_; + // The http backend + $httpBackend = _$httpBackend_; + // Expected requests responses + var schema = { + question: 'Do you bleed?', + answer: 'You will!' + }; + var form = { + jarvis: 'Where is Jessica Jones and Luke?', + answer: 'They are with the Punisher' + }; + + $httpBackend.whenGET('/example/static/json/form.json').respond(200, form); + $httpBackend.whenGET('/example/static/json/schema.json').respond(200, schema); + + // Attach it + scope = $rootScope; + + // Complile&Digest here to catch the event + // The directive's template + template = '' + + ' '+ + ''+ + ''; + // Compile + template = $compile(template)(scope); + + // Digest + scope.$digest(); + })); + + it('should have the action buttons', function() { + // Should have ``form`` element + expect(template.find('form').length).to.be.equal(1); + }); +}); diff --git a/test/unit/invenio-records-js/directives/invenioRecordsSpec.js b/test/unit/invenio-records-js/directives/invenioRecordsSpec.js new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/invenio-records-js/invenioRecordsSpec.js b/test/unit/invenio-records-js/invenioRecordsSpec.js index 7f80a2b..d4e343e 100644 --- a/test/unit/invenio-records-js/invenioRecordsSpec.js +++ b/test/unit/invenio-records-js/invenioRecordsSpec.js @@ -23,35 +23,120 @@ 'use strict'; -describe('Unit: testing dependencies', function() { +describe('Unit: testing directive invenio-records', function() { - var module; - var dependencies; - dependencies = []; + var $compile; + var $httpBackend; + var $rootScope; + var scope; + var template; - var hasModule = function(module) { - return dependencies.indexOf(module) >= 0; - }; + // Inject the angular module + beforeEach(angular.mock.module('invenioRecords')); - beforeEach(function() { - // Get module - module = angular.module('invenioRecords'); - dependencies = module.requires; - }); + // Load the templates + beforeEach(angular.mock.module('templates')); - it('should load controllers module', function() { - expect(hasModule('invenioRecords.controllers')).to.be.ok; - }); + beforeEach(inject(function(_$compile_, _$rootScope_, _$httpBackend_) { + // Template compiler + $compile = _$compile_; + // The Scope + $rootScope = _$rootScope_; + // The http backend + $httpBackend = _$httpBackend_; + // Attach it + scope = $rootScope; + + // Expected requests responses + var schema = { + question: 'Do you bleed?', + answer: 'You will!' + }; + var form = { + jarvis: 'Where is Jessica Jones and Luke?', + answer: 'They are with the Punisher' + }; + $httpBackend.whenGET('/example/static/json/form.json').respond(200, form); + $httpBackend.whenGET('/example/static/json/schema.json').respond(200, schema); + })); - it('should load services module', function() { - expect(hasModule('invenioRecords.services')).to.be.ok; + it('should trigger init event', function() { + // Spy the broadcast + var spy = sinon.spy($rootScope, '$broadcast') + + // Complile&Digest here to catch the event + // The directive's template + template = ''; + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // Check if the event has been triggered + spy.should.have.been.calledOnce; }); - it('should load directives module', function() { - expect(hasModule('invenioRecords.directives')).to.be.ok; + it('should update the parameters', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ''; + + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // The record model should have the title + expect(scope.vm.invenioRecordsModel.title_statement.title) + .to.be.equal('Jessica Jones Vol. 1'); + + // The endpoints should be updated + var endpoints = { + action: null, + form: '/example/static/json/form.json', + initialization: null, + schema: '/example/static/json/schema.json', + } + + expect(scope.vm.invenioRecordsEndpoints) + .to.deep.equal(endpoints); }); - it('should load factories module', function() { - expect(hasModule('invenioRecords.factories')).to.be.ok; + it('should have action url', function() { + // Complile&Digest here to catch the event + // The directive's template + template = ''; + + // Compile + template = $compile(template)(scope); + // Digest + scope.$digest(); + + // The args should be the following + var args = { + url: '/', + method: 'GET', + params: { + 'suicide squad': 'Harley Quinn' + } + }; + expect(scope.vm.invenioRecordsArgs) + .to.deep.equal(args); }); });