GUI: Added {view}-spec.js files for all main views

Change-Id: I75a50ae2689d0ab7863c8bb0546ec72ef8e9e7ea
diff --git a/tools/gui/gulp-tasks/lint/esconfig.json b/tools/gui/gulp-tasks/lint/esconfig.json
index 670a48d..7ce1a78 100644
--- a/tools/gui/gulp-tasks/lint/esconfig.json
+++ b/tools/gui/gulp-tasks/lint/esconfig.json
@@ -22,7 +22,6 @@
         "block-spacing": ["error", "always"],
         "space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }],
         "max-len": ["error", 120],
-        "no-invalid-this": 0,
-        "switch-colon-spacing": ["error", { "after": true, "before": false }]
+        "no-invalid-this": 0
     }
 }
diff --git a/tools/gui/gulp-tasks/lint/index.js b/tools/gui/gulp-tasks/lint/index.js
index f864c6b..1aeb444 100644
--- a/tools/gui/gulp-tasks/lint/index.js
+++ b/tools/gui/gulp-tasks/lint/index.js
@@ -7,6 +7,8 @@
     '../../web/gui/src/main/webapp/app/**/*.js'
 ];
 
+console.log(eslint().version);
+
 function isFixed(file) {
     // Has ESLint fixed the file contents?
     return file.eslint != null && file.eslint.fixed;
diff --git a/tools/gui/gulp-tasks/unit-tests/index.js b/tools/gui/gulp-tasks/unit-tests/index.js
index e6e7436..899392c 100644
--- a/tools/gui/gulp-tasks/unit-tests/index.js
+++ b/tools/gui/gulp-tasks/unit-tests/index.js
@@ -6,8 +6,7 @@
 
 const test = () => {
     new Server({
-        configFile: path.join(__dirname, '../../../../../', '/web/gui/src/main/webapp/tests/karma.conf.js'),
-        singleRun: true
+        configFile: path.join(__dirname, '../../../../', '/web/gui/src/main/webapp/tests/karma.conf.js'),
     }).start();
 };
 
diff --git a/tools/gui/package.json b/tools/gui/package.json
index 304cd54..25e418b 100644
--- a/tools/gui/package.json
+++ b/tools/gui/package.json
@@ -10,17 +10,16 @@
   },
   "author": "",
   "license": "ISC",
-  "dependencies": {},
   "devDependencies": {
     "babel": "^6.23.0",
     "babel-core": "^6.25.0",
     "babel-preset-es2015": "^6.24.1",
     "browser-sync": "^2.18.12",
-    "eslint": "^4.2.0",
+    "eslint": "^4.4.1",
     "eslint-config-google": "^0.9.1",
     "gulp": "^3.9.1",
     "gulp-concat": "^2.6.1",
-    "gulp-eslint": "3.0.1",
+    "gulp-eslint": "^4.0.0",
     "gulp-if": "^2.0.2",
     "gulp-sourcemaps": "^2.6.0",
     "gulp-strip-comments": "^2.4.5",
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
index bce5efb..a3b75f5 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
@@ -56,7 +56,7 @@
         if (add) {
             _.each(add, function (value, key) {
                 // filter out meta properties (e.g. _keyOrder)
-                if (!(key.startsWith('_'))) {
+                if (!(_.startsWith(key, '_'))) {
                     // don't allow re-definition of existing key bindings
                     if (am[key]) {
                         $log.warn('keybind: ' + key + ' already exists');
diff --git a/web/gui/src/main/webapp/package.json b/web/gui/src/main/webapp/package.json
index afe0ebe..a5a9f4e 100644
--- a/web/gui/src/main/webapp/package.json
+++ b/web/gui/src/main/webapp/package.json
@@ -15,8 +15,6 @@
   "license": "Apache 2.0",
   "devDependencies": {
     "browser-sync": "^2.12.8",
-    "eslint": "^3.4.0",
-    "eslint-config-google": "^0.6.0",
     "express": "^4.14.0",
     "parallelshell": "^2.0.0",
     "serve-static": "^1.10.2"
diff --git a/web/gui/src/main/webapp/tests/app/fw/layer/dialog-spec.js b/web/gui/src/main/webapp/tests/app/fw/layer/dialog-spec.js
new file mode 100644
index 0000000..01168bd
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/fw/layer/dialog-spec.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Layer -- Dialog Service - Unit Tests
+ */
+
+describe('factory: fw/layer/dialog.js', function () {
+
+    var $log, $timeout, fs, ps, d3Elem, dialog;
+
+    beforeEach(module('onosLayer', 'onosNav', 'onosSvg', 'onosRemote'));
+
+    beforeEach(inject(function (_$log_, _$timeout_, FnService, PanelService, DialogService) {
+        $log = _$log_;
+        $timeout = _$timeout_;
+        fs = FnService;
+        ps = PanelService;
+        dialog = DialogService;
+
+        spyOn(fs, 'debugOn').and.returnValue(true);
+        d3Elem = d3.select('body').append('div').attr('id', 'floatpanels');
+        ps.init();
+    }));
+
+    afterEach(function () {
+        d3.select('#floatpanels').remove();
+        ps.init();
+    });
+
+    it('should define DialogService', function () {
+        expect(dialog).toBeDefined();
+    });
+
+    it('should define api functions', function () {
+        expect(fs.areFunctions(dialog, [
+            'openDialog', 'closeDialog', 'createDiv',
+        ])).toBe(true);
+    });
+
+    it('should create div', function () {
+        var div = dialog.createDiv();
+        expect(div).toBeDefined();
+    });
+
+    it('should create div with class', function () {
+        var div = dialog.createDiv('test-dialog');
+        expect(div.classed('test-dialog')).toBe(true);
+    });
+
+    it('should openDialog and return API', function () {
+
+        var dialogOptions = {
+            edge: 'right',
+            width: 400,
+            cssCls: 'test-dialog',
+        };
+
+        var d = dialog.openDialog('test-dialog', dialogOptions);
+
+        expect(fs.areFunctions(d, [
+            'setTitle', 'addContent', 'addButton', 'addOk', 'addOkChained', 'addCancel', 'bindKeys',
+        ])).toBe(true);
+    });
+
+    it('should append elements, reset and destroy', function () {
+
+        var okCallback = jasmine.createSpy('cb');
+        var cancelCallback = jasmine.createSpy('cb');
+
+        var dialogOptions = {
+            edge: 'right',
+            width: 400,
+            cssCls: 'test-dialog',
+        };
+
+        var d = dialog.openDialog('test-dialog', dialogOptions);
+        // Title
+        d.setTitle('Dialog Title');
+
+        // Content
+        var content = dialog.createDiv();
+        content.append('p').text('Dialog Content');
+        d.addContent(content);
+
+        d.addOk(okCallback);
+        d.addOk(okCallback, 'Ok');
+
+        d.addCancel(cancelCallback);
+        d.addCancel(cancelCallback, 'Cancel');
+
+        // TODO: Test elements have been correctly added
+        // Resets dialog
+        d = dialog.openDialog('test-dialog', dialogOptions);
+
+        d.addContent('content');
+        d.addOkChained(okCallback, 'ok');
+        dialog.closeDialog();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/fw/layer/flash-spec.js b/web/gui/src/main/webapp/tests/app/fw/layer/flash-spec.js
index da00d67..7677db1 100644
--- a/web/gui/src/main/webapp/tests/app/fw/layer/flash-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/layer/flash-spec.js
@@ -69,4 +69,8 @@
             expect(text.text()).toEqual('foo');
         }, 100);
     });
+
+    it('should create temp div', function () {
+        expect(flash.tempDiv()).toBeDefined();
+    });
 });
diff --git a/web/gui/src/main/webapp/tests/app/fw/util/theme-spec.js b/web/gui/src/main/webapp/tests/app/fw/util/theme-spec.js
index b6709e5..53df5f7 100644
--- a/web/gui/src/main/webapp/tests/app/fw/util/theme-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/util/theme-spec.js
@@ -144,4 +144,19 @@
         expect(cb.calls.count()).toEqual(2);
     });
 
+    it('should return a color', function () {
+        ts.theme('light');
+        var color = ts.spriteColor('gray1', 'stroke');
+        expect(color).toEqual('#cccccc');
+
+        color = ts.spriteColor('gray1');
+        expect(color).toEqual('#cccccc');
+
+        color = ts.spriteColor('gray1', 'fill');
+        expect(color).toEqual('#eeeeee');
+
+        color = ts.spriteColor(null, 'stroke');
+        expect(color).toEqual('none');
+    });
+
 });
diff --git a/web/gui/src/main/webapp/tests/app/view/app/app-spec.js b/web/gui/src/main/webapp/tests/app/view/app/app-spec.js
new file mode 100644
index 0000000..60cadd2
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/app/app-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- App Controller - Unit Tests
+ */
+describe('Controller: OvAppCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovApp', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvAppCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/cluster/cluster-spec.js b/web/gui/src/main/webapp/tests/app/view/cluster/cluster-spec.js
new file mode 100644
index 0000000..449dc24
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/cluster/cluster-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Cluster Controller - Unit Tests
+ */
+describe('Controller: OvClusterCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovCluster', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvClusterCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/flow/flow-spec.js b/web/gui/src/main/webapp/tests/app/view/flow/flow-spec.js
new file mode 100644
index 0000000..48ca797
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/flow/flow-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Flow Controller - Unit Tests
+ */
+describe('Controller: OvFlowCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovFlow', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvFlowCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/group/group-spec.js b/web/gui/src/main/webapp/tests/app/view/group/group-spec.js
new file mode 100644
index 0000000..8722502
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/group/group-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Group Controller - Unit Tests
+ */
+describe('Controller: OvGroupCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovGroup', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvGroupCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/host/host-spec.js b/web/gui/src/main/webapp/tests/app/view/host/host-spec.js
new file mode 100644
index 0000000..a6ad93b
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/host/host-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Host Controller - Unit Tests
+ */
+describe('Controller: OvHostCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovHost', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvHostCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/intent/intent-spec.js b/web/gui/src/main/webapp/tests/app/view/intent/intent-spec.js
new file mode 100644
index 0000000..9d2e4b1
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/intent/intent-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Intent Controller - Unit Tests
+ */
+describe('Controller: OvIntentCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovIntent', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast', 'ovTopo'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvIntentCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/link/link-spec.js b/web/gui/src/main/webapp/tests/app/view/link/link-spec.js
new file mode 100644
index 0000000..e3635fe
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/link/link-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Link Controller - Unit Tests
+ */
+describe('Controller: OvLinkCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovLink', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvLinkCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/meter/meter-spec.js b/web/gui/src/main/webapp/tests/app/view/meter/meter-spec.js
new file mode 100644
index 0000000..2078b4e
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/meter/meter-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Meter Controller - Unit Tests
+ */
+describe('Controller: OvMeterCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovMeter', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvMeterCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/partition/partition-spec.js b/web/gui/src/main/webapp/tests/app/view/partition/partition-spec.js
new file mode 100644
index 0000000..aaf6db2
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/partition/partition-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Partition Controller - Unit Tests
+ */
+describe('Controller: OvPartitionCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovPartition', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvPartitionCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/port/port-spec.js b/web/gui/src/main/webapp/tests/app/view/port/port-spec.js
new file mode 100644
index 0000000..f28fe2a
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/port/port-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Port Controller - Unit Tests
+ */
+describe('Controller: OvPortCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovPort', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvPortCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/processor/processor-spec.js b/web/gui/src/main/webapp/tests/app/view/processor/processor-spec.js
new file mode 100644
index 0000000..3de8671
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/processor/processor-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Processor Controller - Unit Tests
+ */
+describe('Controller: OvProcessorCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovProcessor', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvProcessorCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/settings/settings-spec.js b/web/gui/src/main/webapp/tests/app/view/settings/settings-spec.js
new file mode 100644
index 0000000..3d48cc6
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/settings/settings-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Settings Controller - Unit Tests
+ */
+describe('Controller: OvSettingsCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovSettings', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvSettingsCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topo-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topo-spec.js
new file mode 100644
index 0000000..cb7fcde
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topo-spec.js
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topo Controller - Unit Tests
+ */
+describe('Controller: OvTopoCtrl', function () {
+
+    var $scope, $controller, createController, d3Topo, d3Map;
+
+    beforeEach(module('ovTopo', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        d3Topo = d3.select('body').append('div').attr('id', 'ov-topo');
+        d3Topo.append('svg');
+
+        createController = function () {
+            return $controller('OvTopoCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    afterEach(function () {
+        d3.select('#ov-topo').remove();
+        d3.select('#ov-map').remove();
+    });
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/topo2/topo2-spec.js b/web/gui/src/main/webapp/tests/app/view/topo2/topo2-spec.js
new file mode 100644
index 0000000..a6ca7b2
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/topo2/topo2-spec.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topo2 Controller - Unit Tests
+ */
+describe('Controller: OvTopo2Ctrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovTopo2', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        d3Topo = d3.select('body').append('div').attr('id', 'ov-topo2');
+        topoSvg = d3Topo.append('svg').attr('id', 'topo2');
+        topoSvg.append('g').attr('id', 'topo2-noDevsLayer')
+
+        createController = function () {
+            return $controller('OvTopo2Ctrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/app/view/tunnel/tunnel-spec.js b/web/gui/src/main/webapp/tests/app/view/tunnel/tunnel-spec.js
new file mode 100644
index 0000000..3d4bb99
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/view/tunnel/tunnel-spec.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Tunnel Controller - Unit Tests
+ */
+describe('Controller: OvTunnelCtrl', function () {
+
+    var $scope, $controller, createController;
+
+    beforeEach(module('ovTunnel', 'onosRemote', 'onosLayer', 'onosSvg',
+        'onosNav', 'ngRoute', 'onosWidget', 'onosMast'));
+
+    beforeEach(inject(function ($rootScope, _$controller_) {
+        $scope = $rootScope.$new();
+        $controller = _$controller_;
+
+        createController = function () {
+            return $controller('OvTunnelCtrl', {
+                '$scope': $scope,
+            });
+        };
+    }));
+
+    it('should create controller', function () {
+        var controller = createController();
+    });
+
+});
diff --git a/web/gui/src/main/webapp/tests/karma.ci.js b/web/gui/src/main/webapp/tests/karma.ci.js
index 64c04cd..fddf81a 100644
--- a/web/gui/src/main/webapp/tests/karma.ci.js
+++ b/web/gui/src/main/webapp/tests/karma.ci.js
@@ -22,6 +22,7 @@
         '../tp/angular-cookies.js',
         '../tp/d3.js',
         '../tp/topojson.v1.min.js',
+        '../tp/lodash.min.js',
 
         // production code...
         // make sure modules are defined first...
diff --git a/web/gui/src/main/webapp/tests/karma.conf.js b/web/gui/src/main/webapp/tests/karma.conf.js
index 8e9cd39..ba08e18 100644
--- a/web/gui/src/main/webapp/tests/karma.conf.js
+++ b/web/gui/src/main/webapp/tests/karma.conf.js
@@ -22,6 +22,7 @@
         '../tp/angular-cookies.js',
         '../tp/d3.js',
         '../tp/topojson.v1.min.js',
+        '../tp/lodash.min.js',
 
         // production code...
         // make sure modules are defined first...