From 48bfb957d442bb7008daa45bccf6a29e0c520a71 Mon Sep 17 00:00:00 2001 From: Renjith Kamath Date: Mon, 17 Aug 2015 22:44:08 +0530 Subject: [PATCH 1/3] ZEPPELIN-228 add unit tests for controllers --- .../src/app/notebook/notebook.controller.js | 5 +- zeppelin-web/test/spec/controllers/main.js | 16 ++++- .../test/spec/controllers/notebook.js | 67 ++++++++++++++++++- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 0eb4b77b336..3e4e5d11fd0 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -21,6 +21,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro $scope.editorToggled = false; $scope.tableToggled = false; $scope.viewOnly = false; + $scope.showSetting = false; $scope.looknfeelOption = [ 'default', 'simple', 'report']; $scope.cronOption = [ {name: 'None', value : undefined}, @@ -35,7 +36,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro $scope.interpreterSettings = []; $scope.interpreterBindings = []; - $scope.isNoteDirty = null; + $scope.isNoteDirty = null; $scope.saveTimer = null; var angularObjectRegistry = {}; @@ -149,7 +150,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro }; $scope.setLookAndFeel = function(looknfeel) { - $scope.note.config.looknfeel = looknfeel; + $scope.note.config.looknfeel = looknfeel; $scope.setConfig(); }; diff --git a/zeppelin-web/test/spec/controllers/main.js b/zeppelin-web/test/spec/controllers/main.js index 3b2e9da82c2..012b21f62f8 100644 --- a/zeppelin-web/test/spec/controllers/main.js +++ b/zeppelin-web/test/spec/controllers/main.js @@ -6,18 +6,30 @@ describe('Controller: MainCtrl', function () { beforeEach(module('zeppelinWebApp')); var MainCtrl, - scope; + scope, + rootScope; // Initialize the controller and a mock scope beforeEach(inject(function ($controller, $rootScope) { + rootScope = $rootScope; scope = $rootScope.$new(); MainCtrl = $controller('MainCtrl', { $scope: scope }); })); - it('should attach a asIframe to the scope', function () { + it('should attach a asIframe to the scope and the default value should be false', function () { expect(scope.asIframe).toBeDefined(); + expect(scope.asIframe).toEqual(false); + }); + + it('should set the default value of "looknfeel to "default"', function () { + expect(scope.looknfeel).toEqual('default'); + }); + + it('should set asIframe flag to true when a controller broadcasts setIframe event', function () { + rootScope.$broadcast('setIframe', true); + expect(scope.asIframe).toEqual(true); }); }); diff --git a/zeppelin-web/test/spec/controllers/notebook.js b/zeppelin-web/test/spec/controllers/notebook.js index 5dde4e2cf06..906b541dac2 100644 --- a/zeppelin-web/test/spec/controllers/notebook.js +++ b/zeppelin-web/test/spec/controllers/notebook.js @@ -7,14 +7,75 @@ describe('Controller: NotebookCtrl', function() { var NotebookCtrl, scope; + var websocketMsgSrvMock = { + getNotebook:function() {} + }; + + var baseUrlSrvMock = { + getRestApiBase: function () { + return 'http://localhost:8080'; + } + }; + + var noteMock = { + id: 1, + config: {}, + }; + // Initialize the controller and a mock scope - beforeEach(inject(function($controller, $rootScope/*, websocketMsgSrv, baseUrlSrv*/) { + beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); NotebookCtrl = $controller('NotebookCtrl', { - $scope: scope + $scope: scope, + websocketMsgSrv: websocketMsgSrvMock, + baseUrlSrv: baseUrlSrvMock }); })); - //Test Can be writting for to test NotebookCtrl + beforeEach(function () { + scope.note = noteMock; + }); + + it('should set default value of "showEditor" to false', function () { + expect(scope.showEditor).toEqual(false); + }); + + it('should set default value of "editorToggled" to false', function () { + expect(scope.editorToggled).toEqual(false); + }); + + it('should set showSetting to true when openSetting is called', function () { + scope.openSetting(); + expect(scope.showSetting).toEqual(true); + }); + + it('should set showSetting to false when closeSetting is called', function () { + scope.closeSetting(); + expect(scope.showSetting).toEqual(false); + }); + + it('should return the correct value for getCronOptionNameFromValue', function () { + var oneMin = scope.getCronOptionNameFromValue('0 0/1 * * * ?'); + var oneHour = scope.getCronOptionNameFromValue('0 0 0/1 * * ?'); + expect(oneMin).toEqual('1m'); + expect(oneHour).toEqual('1h'); + }); + + it('default value for isNoteDirty should be null', function () { + expect(scope.isNoteDirty).toEqual(null); + }); + + it('calling startSaveTimer should first call killSaveTimer and start a new timer', function () { + expect(scope.saveTimer).toEqual(null); + scope.startSaveTimer(); + expect(scope.isNoteDirty).toEqual(true); + expect(scope.saveTimer).toBeTruthy(); + }); + + it('calling killSaveTimer should clear saveTimer flag', function () { + scope.killSaveTimer(); + expect(scope.saveTimer).toEqual(null); + }); + }); From a750a301622fc15d2daf015ef2cecf036ab6ebdd Mon Sep 17 00:00:00 2001 From: Renjith Kamath Date: Wed, 19 Aug 2015 12:20:41 +0530 Subject: [PATCH 2/3] ZEPPELIN-228 add more tests for getCronOptionNameFromValue --- zeppelin-web/test/spec/controllers/notebook.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/zeppelin-web/test/spec/controllers/notebook.js b/zeppelin-web/test/spec/controllers/notebook.js index 906b541dac2..15fa732babd 100644 --- a/zeppelin-web/test/spec/controllers/notebook.js +++ b/zeppelin-web/test/spec/controllers/notebook.js @@ -19,6 +19,7 @@ describe('Controller: NotebookCtrl', function() { var noteMock = { id: 1, + name: 'my notebook', config: {}, }; @@ -55,10 +56,23 @@ describe('Controller: NotebookCtrl', function() { }); it('should return the correct value for getCronOptionNameFromValue', function () { + var none = scope.getCronOptionNameFromValue(); var oneMin = scope.getCronOptionNameFromValue('0 0/1 * * * ?'); + var fiveMin = scope.getCronOptionNameFromValue('0 0/5 * * * ?'); var oneHour = scope.getCronOptionNameFromValue('0 0 0/1 * * ?'); + var threeHours = scope.getCronOptionNameFromValue('0 0 0/3 * * ?'); + var sixHours = scope.getCronOptionNameFromValue('0 0 0/6 * * ?'); + var twelveHours = scope.getCronOptionNameFromValue('0 0 0/12 * * ?'); + var oneDay = scope.getCronOptionNameFromValue('0 0 0 * * ?'); + + expect(none).toEqual(''); expect(oneMin).toEqual('1m'); + expect(fiveMin).toEqual('5m'); expect(oneHour).toEqual('1h'); + expect(threeHours).toEqual('3h'); + expect(sixHours).toEqual('6h'); + expect(twelveHours).toEqual('12h'); + expect(oneDay).toEqual('1d'); }); it('default value for isNoteDirty should be null', function () { From 743a13d52e9ba29a4f74710f93db2617f1b413a6 Mon Sep 17 00:00:00 2001 From: Renjith Kamath Date: Mon, 24 Aug 2015 15:02:51 +0530 Subject: [PATCH 3/3] ZEPPELIN-228 add tests for paragraph controller and update notebook tests --- zeppelin-web/.jshintrc | 2 + zeppelin-web/test/spec/controllers/main.js | 19 ++--- .../test/spec/controllers/notebook.js | 40 ++++++---- .../test/spec/controllers/paragraph.js | 77 +++++++++++++++++-- 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/zeppelin-web/.jshintrc b/zeppelin-web/.jshintrc index 374aab426f9..bb2795019e8 100644 --- a/zeppelin-web/.jshintrc +++ b/zeppelin-web/.jshintrc @@ -19,6 +19,8 @@ "strict": true, "trailing": true, "smarttabs": true, + "jasmine": true, + "predef": [ "inject" ], "globals": { "angular": false, "_": false, diff --git a/zeppelin-web/test/spec/controllers/main.js b/zeppelin-web/test/spec/controllers/main.js index 012b21f62f8..16785a9004b 100644 --- a/zeppelin-web/test/spec/controllers/main.js +++ b/zeppelin-web/test/spec/controllers/main.js @@ -1,16 +1,13 @@ 'use strict'; -describe('Controller: MainCtrl', function () { - - // load the controller's module +describe('Controller: MainCtrl', function() { beforeEach(module('zeppelinWebApp')); - var MainCtrl, - scope, - rootScope; + var MainCtrl; + var scope; + var rootScope; - // Initialize the controller and a mock scope - beforeEach(inject(function ($controller, $rootScope) { + beforeEach(inject(function($controller, $rootScope) { rootScope = $rootScope; scope = $rootScope.$new(); MainCtrl = $controller('MainCtrl', { @@ -18,16 +15,16 @@ describe('Controller: MainCtrl', function () { }); })); - it('should attach a asIframe to the scope and the default value should be false', function () { + it('should attach a asIframe to the scope and the default value should be false', function() { expect(scope.asIframe).toBeDefined(); expect(scope.asIframe).toEqual(false); }); - it('should set the default value of "looknfeel to "default"', function () { + it('should set the default value of "looknfeel to "default"', function() { expect(scope.looknfeel).toEqual('default'); }); - it('should set asIframe flag to true when a controller broadcasts setIframe event', function () { + it('should set asIframe flag to true when a controller broadcasts setIframe event', function() { rootScope.$broadcast('setIframe', true); expect(scope.asIframe).toEqual(true); }); diff --git a/zeppelin-web/test/spec/controllers/notebook.js b/zeppelin-web/test/spec/controllers/notebook.js index 15fa732babd..313aa9d2e30 100644 --- a/zeppelin-web/test/spec/controllers/notebook.js +++ b/zeppelin-web/test/spec/controllers/notebook.js @@ -1,18 +1,17 @@ 'use strict'; describe('Controller: NotebookCtrl', function() { - - // load the controller's module beforeEach(module('zeppelinWebApp')); - var NotebookCtrl, scope; + var NotebookCtrl; + var scope; var websocketMsgSrvMock = { - getNotebook:function() {} + getNotebook: function() {} }; var baseUrlSrvMock = { - getRestApiBase: function () { + getRestApiBase: function() { return 'http://localhost:8080'; } }; @@ -23,7 +22,6 @@ describe('Controller: NotebookCtrl', function() { config: {}, }; - // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); NotebookCtrl = $controller('NotebookCtrl', { @@ -33,29 +31,40 @@ describe('Controller: NotebookCtrl', function() { }); })); - beforeEach(function () { + beforeEach(function() { scope.note = noteMock; }); - it('should set default value of "showEditor" to false', function () { + var functions = ['getCronOptionNameFromValue', 'removeNote', 'runNote', 'saveNote', 'toggleAllEditor', + 'showAllEditor', 'hideAllEditor', 'toggleAllTable', 'hideAllTable', 'showAllTable', 'isNoteRunning', + 'killSaveTimer', 'startSaveTimer', 'setLookAndFeel', 'setCronScheduler', 'setConfig', 'sendNewName', + 'openSetting', 'closeSetting', 'saveSetting', 'toggleSetting']; + + functions.forEach(function(fn) { + it('check for scope functions to be defined : ' + fn, function() { + expect(scope[fn]).toBeDefined(); + }); + }); + + it('should set default value of "showEditor" to false', function() { expect(scope.showEditor).toEqual(false); }); - it('should set default value of "editorToggled" to false', function () { + it('should set default value of "editorToggled" to false', function() { expect(scope.editorToggled).toEqual(false); }); - it('should set showSetting to true when openSetting is called', function () { + it('should set showSetting to true when openSetting is called', function() { scope.openSetting(); expect(scope.showSetting).toEqual(true); }); - it('should set showSetting to false when closeSetting is called', function () { + it('should set showSetting to false when closeSetting is called', function() { scope.closeSetting(); expect(scope.showSetting).toEqual(false); }); - it('should return the correct value for getCronOptionNameFromValue', function () { + it('should return the correct value for getCronOptionNameFromValue', function() { var none = scope.getCronOptionNameFromValue(); var oneMin = scope.getCronOptionNameFromValue('0 0/1 * * * ?'); var fiveMin = scope.getCronOptionNameFromValue('0 0/5 * * * ?'); @@ -75,21 +84,20 @@ describe('Controller: NotebookCtrl', function() { expect(oneDay).toEqual('1d'); }); - it('default value for isNoteDirty should be null', function () { + it('default value for isNoteDirty should be null', function() { expect(scope.isNoteDirty).toEqual(null); }); - it('calling startSaveTimer should first call killSaveTimer and start a new timer', function () { + it('calling startSaveTimer should first call killSaveTimer and start a new timer', function() { expect(scope.saveTimer).toEqual(null); scope.startSaveTimer(); expect(scope.isNoteDirty).toEqual(true); expect(scope.saveTimer).toBeTruthy(); }); - it('calling killSaveTimer should clear saveTimer flag', function () { + it('calling killSaveTimer should clear saveTimer flag', function() { scope.killSaveTimer(); expect(scope.saveTimer).toEqual(null); }); - }); diff --git a/zeppelin-web/test/spec/controllers/paragraph.js b/zeppelin-web/test/spec/controllers/paragraph.js index 1ea4d264b0e..abde0d91864 100644 --- a/zeppelin-web/test/spec/controllers/paragraph.js +++ b/zeppelin-web/test/spec/controllers/paragraph.js @@ -1,19 +1,82 @@ 'use strict'; -describe('Controller: ParagraphCtrl', function () { +describe('Controller: ParagraphCtrl', function() { - // load the controller's module beforeEach(module('zeppelinWebApp')); - var ParagraphCtrl, scope; + var ParagraphCtrl; + var scope; + var websocketMsgSrvMock = {}; + var paragraphMock = { + config: {} + }; - // Initialize the controller and a mock scope - beforeEach(inject(function ($controller, $rootScope) { + beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); ParagraphCtrl = $controller('ParagraphCtrl', { - $scope: scope + $scope: scope, + websocketMsgSrv: websocketMsgSrvMock, + $element: {} }); + scope.init(paragraphMock); })); - //Write test to test ParagraphCtrl + var functions = ['isRunning', 'getIframeDimensions', 'cancelParagraph', 'runParagraph', 'saveParagraph', + 'moveUp', 'moveDown', 'insertNew', 'removeParagraph', 'toggleEditor', 'closeEditor', 'openEditor', + 'closeTable', 'openTable', 'showTitle', 'hideTitle', 'setTitle', 'showLineNumbers', 'hideLineNumbers', + 'changeColWidth', 'columnWidthClass', 'toggleGraphOption', 'toggleOutput', 'loadForm', + 'aceChanged', 'aceLoaded', 'getEditorValue', 'getProgress', 'getExecutionTime', 'isResultOutdated', + 'getResultType', 'loadTableData', 'setGraphMode', 'isGraphMode', 'onGraphOptionChange', + 'removeGraphOptionKeys', 'removeGraphOptionValues', 'removeGraphOptionGroups', 'setGraphOptionValueAggr', + 'removeScatterOptionXaxis', 'removeScatterOptionYaxis', 'removeScatterOptionGroup', + 'removeScatterOptionSize']; + + functions.forEach(function(fn) { + it('check for scope functions to be defined : ' + fn, function() { + expect(scope[fn]).toBeDefined(); + }); + }); + + it('getResultType should return "TEXT" when the type is unknown', function() { + expect(scope.getResultType()).toEqual('TEXT'); + }); + + it('init value for colWidthOption should be false', function() { + expect(scope.colWidthOption).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + }); + + it('init value for paragraphFocused should be false', function() { + expect(scope.paragraphFocused).toEqual(false); + }); + + it('loadTableData should be called when the result type is "TABLE" and the Graph mode should be "table"', function() { + scope.getResultType = jasmine.createSpy('getResultType spy').andCallFake(function() { + return 'TABLE'; + }); + spyOn(scope, 'loadTableData'); + spyOn(scope, 'setGraphMode'); + scope.init(paragraphMock); + expect(scope.loadTableData).toHaveBeenCalled(); + expect(scope.setGraphMode).toHaveBeenCalled(); + expect(scope.getGraphMode()).toEqual('table'); + }); + + it('renderHtml should be called when the result type is "HTML"', function() { + scope.getResultType = jasmine.createSpy('getResultType spy').andCallFake(function() { + return 'HTML'; + }); + spyOn(scope, 'renderHtml'); + scope.init(paragraphMock); + expect(scope.renderHtml).toHaveBeenCalled(); + }); + + it('renderAngular should be called when the result type is "ANGULAR"', function() { + scope.getResultType = jasmine.createSpy('getResultType spy').andCallFake(function() { + return 'ANGULAR'; + }); + spyOn(scope, 'renderAngular'); + scope.init(paragraphMock); + expect(scope.renderAngular).toHaveBeenCalled(); + }); + });