You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by ah...@apache.org on 2017/02/25 14:42:17 UTC

zeppelin git commit: [ZEPPELIN-2086] Move zeppelin-web related test files into src/ for efficiency

Repository: zeppelin
Updated Branches:
  refs/heads/master 8d3482aeb -> c437a1918


[ZEPPELIN-2086] Move zeppelin-web related test files into src/ for efficiency

### What is this PR for?

Since we are using a separated test directory,

- it's uncomfortable to create test
- it's hard to figure which source is related with this test file.

```javascript
// we have to import like this...
import TableData from '../../../src/app/tabledata/tabledata.js';
```

### What type of PR is it?
[Improvement]

### Todos
* [x] - Fix karma conf
* [x] - Move test files

### What is the Jira issue?

[ZEPPELIN-2086](https://issues.apache.org/jira/browse/ZEPPELIN-2086)

### How should this be tested?

- Execute `npm runt test`
- You should see this message like before

```
webpack: Compiled successfully.
09 02 2017 12:36:01.876:INFO [karma]: Karma v1.3.0 server started at http://localhost:9002/
09 02 2017 12:36:01.878:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
09 02 2017 12:36:01.888:INFO [launcher]: Starting browser PhantomJS
09 02 2017 12:36:02.372:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#BkEJkZGwxoc6HMA7AAAA with id 42992167
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 37 of 70 SUCCESS (0 secs / 0.236 secs)
LOG: function TableData(columns, rows, comment) { ... }
LOG: function TableData(columns, rows, comment) { ... }
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 70 of 70 SUCCESS (0.26 secs / 0.352 secs)
```

### Screenshots (if appropriate)

NONE

### Questions:
* Does the licenses files need update? - NO
* Is there breaking changes for older versions? - NO
* Does this needs documentation? - NO

Author: 1ambda <1a...@gmail.com>

Closes #1995 from 1ambda/ZEPPELIN-2086/refactor-web-test-dirs and squashes the following commits:

069ee06 [1ambda] fix: RAT issues
b899edd [1ambda] fix: Add inject global into .eslint to avoid undef
c81ade4 [1ambda] fix: Import path in tabledata.test.js
2bab275 [1ambda] fix: Move karma.conf file to top-level
07ffc27 [1ambda] fix: Remove useless jshintrc
9c5418e [1ambda] fix: Move test files into src/ while renaming
b1d0cbb [1ambda] fix: test file pattern in karma.conf.js


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/c437a191
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/c437a191
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/c437a191

Branch: refs/heads/master
Commit: c437a1918045a744ec8430a15fa847999399539f
Parents: 8d3482a
Author: 1ambda <1a...@gmail.com>
Authored: Mon Feb 13 12:14:04 2017 +0900
Committer: ahyoungryu <ah...@apache.org>
Committed: Sat Feb 25 23:42:03 2017 +0900

----------------------------------------------------------------------
 zeppelin-web/.eslintrc                          |   1 +
 zeppelin-web/karma.conf.js                      | 163 +++++++++++++++++++
 zeppelin-web/package.json                       |   2 +-
 zeppelin-web/pom.xml                            |   3 +-
 zeppelin-web/src/app/app.controller.test.js     |  29 ++++
 .../app/notebook/notebook.controller.test.js    | 138 ++++++++++++++++
 .../paragraph/paragraph.controller.test.js      |  51 ++++++
 .../src/app/tabledata/tabledata.test.js         |  41 +++++
 .../components/navbar/navbar.controller.test.js |  18 ++
 .../ngenter/ngenter.directive.test.js           |  25 +++
 .../noteList.datafactory.test.js                |  77 +++++++++
 .../noteName-create/notename.controller.test.js |  40 +++++
 zeppelin-web/test/.jshintrc                     |  37 -----
 zeppelin-web/test/karma.conf.js                 | 146 -----------------
 zeppelin-web/test/spec/controllers/main.js      |  29 ----
 zeppelin-web/test/spec/controllers/nav.js       |  18 --
 zeppelin-web/test/spec/controllers/notebook.js  | 138 ----------------
 zeppelin-web/test/spec/controllers/notename.js  |  40 -----
 zeppelin-web/test/spec/controllers/paragraph.js |  51 ------
 zeppelin-web/test/spec/directives/ngenter.js    |  25 ---
 zeppelin-web/test/spec/factory/noteList.js      |  77 ---------
 zeppelin-web/test/spec/tabledata/tabledata.js   |  41 -----
 22 files changed, 586 insertions(+), 604 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/.eslintrc
----------------------------------------------------------------------
diff --git a/zeppelin-web/.eslintrc b/zeppelin-web/.eslintrc
index b4d3909..3981770 100644
--- a/zeppelin-web/.eslintrc
+++ b/zeppelin-web/.eslintrc
@@ -14,6 +14,7 @@
   },
   "globals": {
     "angular": false,
+    "inject": false,
     "_": false,
     "jQuery": false,
     "hljs": false,

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/karma.conf.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/karma.conf.js b/zeppelin-web/karma.conf.js
new file mode 100644
index 0000000..b24e36a
--- /dev/null
+++ b/zeppelin-web/karma.conf.js
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+// Karma configuration
+// http://karma-runner.github.io/0.12/config/configuration-file.html
+// Generated on 2014-08-29 using
+// generator-karma 0.8.3
+
+var webpackConfig = require('./webpack.config');
+
+module.exports = function(config) {
+  'use strict';
+
+  config.set({
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+    // base path, that will be used to resolve files and exclude
+    basePath: './',
+
+    // testing framework to use (jasmine/mocha/qunit/...)
+    frameworks: ['jasmine'],
+
+    // list of files / patterns to load in the browser
+    files: [
+      // bower:js
+      'bower_components/jquery/dist/jquery.js',
+      'bower_components/es5-shim/es5-shim.js',
+      'bower_components/angular/angular.js',
+      'bower_components/json3/lib/json3.js',
+      'bower_components/bootstrap/dist/js/bootstrap.js',
+      'bower_components/angular-cookies/angular-cookies.js',
+      'bower_components/angular-sanitize/angular-sanitize.js',
+      'bower_components/angular-animate/angular-animate.js',
+      'bower_components/angular-touch/angular-touch.js',
+      'bower_components/angular-route/angular-route.js',
+      'bower_components/angular-resource/angular-resource.js',
+      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
+      'bower_components/angular-websocket/angular-websocket.min.js',
+      'bower_components/ace-builds/src-noconflict/ace.js',
+      'bower_components/ace-builds/src-noconflict/mode-scala.js',
+      'bower_components/ace-builds/src-noconflict/mode-python.js',
+      'bower_components/ace-builds/src-noconflict/mode-sql.js',
+      'bower_components/ace-builds/src-noconflict/mode-markdown.js',
+      'bower_components/ace-builds/src-noconflict/mode-sh.js',
+      'bower_components/ace-builds/src-noconflict/mode-r.js',
+      'bower_components/ace-builds/src-noconflict/keybinding-emacs.js',
+      'bower_components/ace-builds/src-noconflict/ext-language_tools.js',
+      'bower_components/ace-builds/src-noconflict/theme-chrome.js',
+      'bower_components/angular-ui-ace/ui-ace.js',
+      'bower_components/jquery.scrollTo/jquery.scrollTo.js',
+      'bower_components/d3/d3.js',
+      'bower_components/nvd3/build/nv.d3.js',
+      'bower_components/jquery-ui/jquery-ui.js',
+      'bower_components/angular-dragdrop/src/angular-dragdrop.js',
+      'bower_components/perfect-scrollbar/src/perfect-scrollbar.js',
+      'bower_components/ng-sortable/dist/ng-sortable.js',
+      'bower_components/angular-elastic/elastic.js',
+      'bower_components/angular-elastic-input/dist/angular-elastic-input.min.js',
+      'bower_components/angular-xeditable/dist/js/xeditable.js',
+      'bower_components/highlightjs/highlight.pack.js',
+      'bower_components/lodash/lodash.js',
+      'bower_components/angular-filter/dist/angular-filter.js',
+      'bower_components/ngtoast/dist/ngToast.js',
+      'bower_components/ng-focus-if/focusIf.js',
+      'bower_components/bootstrap3-dialog/dist/js/bootstrap-dialog.min.js',
+      'bower_components/zeroclipboard/dist/ZeroClipboard.js',
+      'bower_components/moment/moment.js',
+      'bower_components/pikaday/pikaday.js',
+      'bower_components/handsontable/dist/handsontable.js',
+      'bower_components/moment-duration-format/lib/moment-duration-format.js',
+      'bower_components/select2/dist/js/select2.js',
+      'bower_components/MathJax/MathJax.js',
+      'bower_components/clipboard/dist/clipboard.js',
+      'bower_components/ngclipboard/dist/ngclipboard.js',
+      'bower_components/angular-mocks/angular-mocks.js',
+      // endbower
+
+      'src/index.js',
+      // 'test/spec/**/*.js',
+      {pattern: 'src/**/*.test.js', watched: false},
+    ],
+
+    // list of files / patterns to exclude
+    exclude: [
+      '.tmp/app/visualization/builtins/*.js'
+    ],
+
+    // web server port
+    port: 9002,
+
+    // Start these browsers, currently available:
+    // - Chrome
+    // - ChromeCanary
+    // - Firefox
+    // - Opera
+    // - Safari (only Mac)
+    // - PhantomJS
+    // - IE (only Windows)
+    browsers: [
+      'PhantomJS'
+    ],
+
+    reporters: ['coverage','progress'],
+
+    webpack: webpackConfig,
+    webpackMiddleware: {
+      stats: 'errors-only'
+    },
+
+    preprocessors: {
+      'src/*/{*.js,!(test)/**/*.js}': 'coverage',
+      'src/index.js': ['webpack', 'sourcemap',],
+      'src/**/*.test.js': ['webpack', 'sourcemap',],
+    },
+
+    coverageReporter: {
+      type: 'html',
+      dir: './reports/zeppelin-web-coverage',
+      subdir: '.'
+    },
+
+    // Which plugins to enable
+    plugins: [
+      'karma-phantomjs-launcher',
+      'karma-jasmine',
+      'karma-coverage',
+      'karma-webpack',
+      'karma-sourcemap-loader',
+    ],
+
+    // Continuous Integration mode
+    // if true, it capture browsers, run tests and exit
+    singleRun: true,
+
+    colors: true,
+
+    // level of logging
+    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+    // Uncomment the following lines if you are using grunt's server to run the tests
+    // proxies: {
+    //   '/': 'http://localhost:9000/'
+    // },
+    // URL root prevent conflicts with the site root
+    // urlRoot: '_karma_'
+  });
+};

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/package.json
----------------------------------------------------------------------
diff --git a/zeppelin-web/package.json b/zeppelin-web/package.json
index c9bba37..513f5ff 100644
--- a/zeppelin-web/package.json
+++ b/zeppelin-web/package.json
@@ -17,7 +17,7 @@
     "dev": "npm-run-all --parallel dev:server dev:watch",
     "visdev": "npm-run-all --parallel visdev:server dev:watch",
     "pretest": "npm install karma-phantomjs-launcher",
-    "test": "karma start test/karma.conf.js"
+    "test": "karma start karma.conf.js"
   },
   "dependencies": {
     "grunt-angular-templates": "^0.5.7",

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-web/pom.xml b/zeppelin-web/pom.xml
index dad2db4..d5bbb8d 100644
--- a/zeppelin-web/pom.xml
+++ b/zeppelin-web/pom.xml
@@ -80,7 +80,8 @@
             <exclude>node/**</exclude>
             <exclude>node_modules/**</exclude>
             <exclude>bower_components/**</exclude>
-            <exclude>test/**</exclude>
+            <exclude>src/**/*.test.js</exclude>
+            <exclude>reports/**</exclude>
             <exclude>dist/**</exclude>
             <exclude>src/.buildignore</exclude>
             <exclude>src/fonts/fontawesome*</exclude>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/app/app.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/app.controller.test.js b/zeppelin-web/src/app/app.controller.test.js
new file mode 100644
index 0000000..329fb21
--- /dev/null
+++ b/zeppelin-web/src/app/app.controller.test.js
@@ -0,0 +1,29 @@
+describe('Controller: MainCtrl', function() {
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  var scope;
+  var rootScope;
+
+  beforeEach(inject(function($controller, $rootScope) {
+    rootScope = $rootScope;
+    scope = $rootScope.$new();
+    $controller('MainCtrl', {
+      $scope: scope
+    });
+  }));
+
+  it('should attach "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);
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/app/notebook/notebook.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.controller.test.js b/zeppelin-web/src/app/notebook/notebook.controller.test.js
new file mode 100644
index 0000000..f4a420b
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/notebook.controller.test.js
@@ -0,0 +1,138 @@
+describe('Controller: NotebookCtrl', function() {
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  var scope;
+
+  var websocketMsgSrvMock = {
+    getNote: function() {},
+    listRevisionHistory: function() {},
+    getInterpreterBindings: function() {},
+    updateNote: function() {}
+  };
+
+  var baseUrlSrvMock = {
+    getRestApiBase: function() {
+      return 'http://localhost:8080';
+    }
+  };
+
+  var noteMock = {
+    id: 1,
+    name: 'my note',
+    config: {},
+  };
+
+  beforeEach(inject(function($controller, $rootScope) {
+    scope = $rootScope.$new();
+    $controller('NotebookCtrl', {
+      $scope: scope,
+      websocketMsgSrv: websocketMsgSrvMock,
+      baseUrlSrv: baseUrlSrvMock
+    });
+  }));
+
+  beforeEach(function() {
+    scope.note = noteMock;
+  });
+
+  var functions = ['getCronOptionNameFromValue', 'removeNote', 'runAllParagraphs', 'saveNote', 'toggleAllEditor',
+    'showAllEditor', 'hideAllEditor', 'toggleAllTable', 'hideAllTable', 'showAllTable', 'isNoteRunning',
+    'killSaveTimer', 'startSaveTimer', 'setLookAndFeel', 'setCronScheduler', 'setConfig', 'updateNoteName',
+    '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 "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 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('should have "isNoteDirty" as null by default', function() {
+    expect(scope.isNoteDirty).toEqual(null);
+  });
+
+  it('should first call killSaveTimer() when calling startSaveTimer()', function() {
+    expect(scope.saveTimer).toEqual(null);
+    spyOn(scope, 'killSaveTimer');
+    scope.startSaveTimer();
+    expect(scope.killSaveTimer).toHaveBeenCalled();
+  });
+
+  it('should set "saveTimer" when saveTimer() and killSaveTimer() are called', function() {
+    expect(scope.saveTimer).toEqual(null);
+    scope.startSaveTimer();
+    expect(scope.saveTimer).toBeTruthy();
+    scope.killSaveTimer();
+    expect(scope.saveTimer).toEqual(null);
+  });
+
+  it('should NOT update note name when updateNoteName() is called with an invalid name', function() {
+    spyOn(websocketMsgSrvMock, 'updateNote');
+    scope.updateNoteName('');
+    expect(scope.note.name).toEqual(noteMock.name);
+    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
+    scope.updateNoteName(' ');
+    expect(scope.note.name).toEqual(noteMock.name);
+    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
+    scope.updateNoteName(scope.note.name);
+    expect(scope.note.name).toEqual(noteMock.name);
+    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
+  });
+
+  it('should update note name when updateNoteName() is called with a valid name', function() {
+    spyOn(websocketMsgSrvMock, 'updateNote');
+    var newName = 'Your Note';
+    scope.updateNoteName(newName);
+    expect(scope.note.name).toEqual(newName);
+    expect(websocketMsgSrvMock.updateNote).toHaveBeenCalled();
+  });
+
+  it('should reload note info once per one "setNoteMenu" event', function() {
+    spyOn(websocketMsgSrvMock, 'getNote');
+    spyOn(websocketMsgSrvMock, 'listRevisionHistory');
+
+    scope.$broadcast('setNoteMenu');
+    expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
+    expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
+
+    websocketMsgSrvMock.getNote.calls.reset();
+    websocketMsgSrvMock.listRevisionHistory.calls.reset();
+
+    scope.$broadcast('setNoteMenu');
+    expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
+    expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
+  });
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js
new file mode 100644
index 0000000..1aa4a4a
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js
@@ -0,0 +1,51 @@
+describe('Controller: ParagraphCtrl', function() {
+
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  var scope;
+  var websocketMsgSrvMock = {};
+  var paragraphMock = {
+    config: {}
+  };
+  var route = {
+    current: {
+      pathParams: {
+        noteId: 'noteId'
+      }
+    }
+  };
+
+  beforeEach(inject(function($controller, $rootScope) {
+    scope = $rootScope.$new();
+    $rootScope.notebookScope = $rootScope.$new(true, $rootScope);
+
+    $controller('ParagraphCtrl', {
+      $scope: scope,
+      websocketMsgSrv: websocketMsgSrvMock,
+      $element: {},
+      $route: route
+    });
+
+    scope.init(paragraphMock);
+  }));
+
+  var functions = ['isRunning', 'getIframeDimensions', 'cancelParagraph', 'runParagraph', 'saveParagraph',
+    'moveUp', 'moveDown', 'insertNew', 'removeParagraph', 'toggleEditor', 'closeEditor', 'openEditor',
+    'closeTable', 'openTable', 'showTitle', 'hideTitle', 'setTitle', 'showLineNumbers', 'hideLineNumbers',
+    'changeColWidth', 'columnWidthClass', 'toggleOutput', 'loadForm',
+    'aceChanged', 'aceLoaded', 'getEditorValue', 'getProgress', 'getExecutionTime', 'isResultOutdated'];
+
+  functions.forEach(function(fn) {
+    it('check for scope functions to be defined : ' + fn, function() {
+      expect(scope[fn]).toBeDefined();
+    });
+  });
+
+  it('should have this array of values for "colWidthOption"', function() {
+    expect(scope.colWidthOption).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
+  });
+
+  it('should set default value of "paragraphFocused" as false', function() {
+    expect(scope.paragraphFocused).toEqual(false);
+  });
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/app/tabledata/tabledata.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/tabledata/tabledata.test.js b/zeppelin-web/src/app/tabledata/tabledata.test.js
new file mode 100644
index 0000000..64dd915
--- /dev/null
+++ b/zeppelin-web/src/app/tabledata/tabledata.test.js
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+import TableData from './tabledata.js';
+
+describe('TableData build', function() {
+  var td;
+
+  beforeEach(function() {
+    console.log(TableData);
+    td = new TableData();
+  });
+
+  it('should initialize the default value', function() {
+    expect(td.columns.length).toBe(0);
+    expect(td.rows.length).toBe(0);
+    expect(td.comment).toBe('');
+  });
+
+  it('should able to create Tabledata from paragraph result', function() {
+    td.loadParagraphResult({
+      type: 'TABLE',
+      msg: 'key\tvalue\na\t10\nb\t20\n\nhello'
+    });
+
+    expect(td.columns.length).toBe(2);
+    expect(td.rows.length).toBe(2);
+    expect(td.comment).toBe('hello');
+  });
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/components/navbar/navbar.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.controller.test.js b/zeppelin-web/src/components/navbar/navbar.controller.test.js
new file mode 100644
index 0000000..07a5945
--- /dev/null
+++ b/zeppelin-web/src/components/navbar/navbar.controller.test.js
@@ -0,0 +1,18 @@
+describe('Controller: NavCtrl', function() {
+  // load the controller's module
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+  var NavCtrl;
+  var scope;
+  // Initialize the controller and a mock scope
+  beforeEach(inject(function($controller, $rootScope) {
+    scope = $rootScope.$new();
+    NavCtrl = $controller('NavCtrl', {
+      $scope: scope
+    });
+
+    it('NavCtrl to toBeDefined', function() {
+      expect(NavCtrl).toBeDefined();
+      expect(NavCtrl.loadNotes).toBeDefined();
+    });
+  }));
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ngenter/ngenter.directive.test.js b/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
new file mode 100644
index 0000000..d347155
--- /dev/null
+++ b/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
@@ -0,0 +1,25 @@
+describe('Directive: ngEnter', function() {
+
+  // load the directive's module
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  var element;
+  var scope;
+
+  beforeEach(inject(function($rootScope) {
+    scope = $rootScope.$new();
+  }));
+
+  it('should be define', inject(function($compile) {
+    element = angular.element('<ng-enter></ng-enter>');
+    element = $compile(element)(scope);
+    expect(element.text()).toBeDefined();
+  }));
+
+  //Test the rest of function in ngEnter
+  /*  it('should make hidden element visible', inject(function ($compile) {
+      element = angular.element('<ng-enter></ng-enter>');
+      element = $compile(element)(scope);
+      expect(element.text()).toBe('this is the ngEnter directive');
+    }));*/
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/components/noteListDataFactory/noteList.datafactory.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/noteListDataFactory/noteList.datafactory.test.js b/zeppelin-web/src/components/noteListDataFactory/noteList.datafactory.test.js
new file mode 100644
index 0000000..85fb2ba
--- /dev/null
+++ b/zeppelin-web/src/components/noteListDataFactory/noteList.datafactory.test.js
@@ -0,0 +1,77 @@
+describe('Factory: NoteList', function() {
+
+  var noteList;
+
+  beforeEach(function() {
+    angular.mock.module('zeppelinWebApp');
+
+    inject(function($injector) {
+      noteList = $injector.get('noteListDataFactory');
+    });
+  });
+
+  it('should generate both flat list and folder-based list properly', function() {
+    var notesList = [
+      {name: 'A', id: '000001'},
+      {name: 'B', id: '000002'},
+      {id: '000003'},                     // note without name
+      {name: '/C/CA', id: '000004'},
+      {name: '/C/CB', id: '000005'},
+      {name: '/C/CB/CBA', id: '000006'},  // same name with a dir
+      {name: '/C/CB/CBA', id: '000007'},  // same name with another note
+      {name: 'C///CB//CBB', id: '000008'},
+      {name: 'D/D[A/DA]B', id: '000009'}   // check if '[' and ']' considered as folder seperator
+    ];
+    noteList.setNotes(notesList);
+
+    var flatList = noteList.flatList;
+    expect(flatList.length).toBe(9);
+    expect(flatList[0].name).toBe('A');
+    expect(flatList[0].id).toBe('000001');
+    expect(flatList[1].name).toBe('B');
+    expect(flatList[2].name).toBeUndefined();
+    expect(flatList[3].name).toBe('/C/CA');
+    expect(flatList[4].name).toBe('/C/CB');
+    expect(flatList[5].name).toBe('/C/CB/CBA');
+    expect(flatList[6].name).toBe('/C/CB/CBA');
+    expect(flatList[7].name).toBe('C///CB//CBB');
+    expect(flatList[8].name).toBe('D/D[A/DA]B');
+
+    var folderList = noteList.root.children;
+    expect(folderList.length).toBe(5);
+    expect(folderList[0].name).toBe('A');
+    expect(folderList[0].id).toBe('000001');
+    expect(folderList[1].name).toBe('B');
+    expect(folderList[2].name).toBe('000003');
+    expect(folderList[3].name).toBe('C');
+    expect(folderList[3].id).toBe('C');
+    expect(folderList[3].children.length).toBe(3);
+    expect(folderList[3].children[0].name).toBe('CA');
+    expect(folderList[3].children[0].id).toBe('000004');
+    expect(folderList[3].children[0].children).toBeUndefined();
+    expect(folderList[3].children[1].name).toBe('CB');
+    expect(folderList[3].children[1].id).toBe('000005');
+    expect(folderList[3].children[1].children).toBeUndefined();
+    expect(folderList[3].children[2].name).toBe('CB');
+    expect(folderList[3].children[2].id).toBe('C/CB');
+    expect(folderList[3].children[2].children.length).toBe(3);
+    expect(folderList[3].children[2].children[0].name).toBe('CBA');
+    expect(folderList[3].children[2].children[0].id).toBe('000006');
+    expect(folderList[3].children[2].children[0].children).toBeUndefined();
+    expect(folderList[3].children[2].children[1].name).toBe('CBA');
+    expect(folderList[3].children[2].children[1].id).toBe('000007');
+    expect(folderList[3].children[2].children[1].children).toBeUndefined();
+    expect(folderList[3].children[2].children[2].name).toBe('CBB');
+    expect(folderList[3].children[2].children[2].id).toBe('000008');
+    expect(folderList[3].children[2].children[2].children).toBeUndefined();
+    expect(folderList[4].name).toBe('D');
+    expect(folderList[4].id).toBe('D');
+    expect(folderList[4].children.length).toBe(1);
+    expect(folderList[4].children[0].name).toBe('D[A');
+    expect(folderList[4].children[0].id).toBe('D/D[A');
+    expect(folderList[4].children[0].children[0].name).toBe('DA]B');
+    expect(folderList[4].children[0].children[0].id).toBe('000009');
+    expect(folderList[4].children[0].children[0].children).toBeUndefined();
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/src/components/noteName-create/notename.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/noteName-create/notename.controller.test.js b/zeppelin-web/src/components/noteName-create/notename.controller.test.js
new file mode 100644
index 0000000..47e79c1
--- /dev/null
+++ b/zeppelin-web/src/components/noteName-create/notename.controller.test.js
@@ -0,0 +1,40 @@
+describe('Controller: NotenameCtrl', function() {
+  beforeEach(angular.mock.module('zeppelinWebApp'));
+
+  var scope;
+  var ctrl;
+  var noteList;
+
+  beforeEach(inject(function($injector, $rootScope, $controller) {
+    noteList = $injector.get('noteListDataFactory');
+    scope = $rootScope.$new();
+    ctrl = $controller('NotenameCtrl', {
+      $scope: scope,
+      noteListDataFactory: noteList
+    });
+  }));
+
+  it('should create a new name from current name when cloneNoteName is called', function() {
+    var notesList = [
+      {name: 'dsds 1', id: '1'},
+      {name: 'dsds 2', id: '2'},
+      {name: 'test name', id: '3'},
+      {name: 'aa bb cc', id: '4'},
+      {name: 'Untitled Note 6', id: '4'}
+    ];
+
+    noteList.setNotes(notesList);
+
+    ctrl.sourceNoteName = 'test name';
+    expect(ctrl.cloneNoteName()).toEqual('test name 1');
+    ctrl.sourceNoteName = 'aa bb cc';
+    expect(ctrl.cloneNoteName()).toEqual('aa bb cc 1');
+    ctrl.sourceNoteName = 'Untitled Note 6';
+    expect(ctrl.cloneNoteName()).toEqual('Untitled Note 7');
+    ctrl.sourceNoteName = 'My_note';
+    expect(ctrl.cloneNoteName()).toEqual('My_note 1');
+    ctrl.sourceNoteName = 'dsds 2';
+    expect(ctrl.cloneNoteName()).toEqual('dsds 3');
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/.jshintrc
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/.jshintrc b/zeppelin-web/test/.jshintrc
deleted file mode 100644
index c82b6da..0000000
--- a/zeppelin-web/test/.jshintrc
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "node": true,
-  "browser": true,
-  "esnext": true,
-  "bitwise": true,
-  "camelcase": true,
-  "curly": true,
-  "eqeqeq": true,
-  "immed": true,
-  "indent": 2,
-  "latedef": true,
-  "newcap": true,
-  "noarg": true,
-  "quotmark": "single",
-  "regexp": true,
-  "undef": true,
-  "unused": true,
-  "strict": true,
-  "trailing": true,
-  "smarttabs": true,
-  "globals": {
-    "after": false,
-    "afterEach": false,
-    "angular": false,
-    "before": false,
-    "beforeEach": false,
-    "browser": false,
-    "describe": false,
-    "expect": false,
-    "inject": false,
-    "it": false,
-    "jasmine": false,
-    "spyOn": false,
-    "zeppelin" : false
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/karma.conf.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/karma.conf.js b/zeppelin-web/test/karma.conf.js
deleted file mode 100644
index 3a2449c..0000000
--- a/zeppelin-web/test/karma.conf.js
+++ /dev/null
@@ -1,146 +0,0 @@
-// Karma configuration
-// http://karma-runner.github.io/0.12/config/configuration-file.html
-// Generated on 2014-08-29 using
-// generator-karma 0.8.3
-
-var webpackConfig = require('../webpack.config');
-
-module.exports = function(config) {
-  'use strict';
-
-  config.set({
-    // enable / disable watching file and executing tests whenever any file changes
-    autoWatch: true,
-
-    // base path, that will be used to resolve files and exclude
-    basePath: '../',
-
-    // testing framework to use (jasmine/mocha/qunit/...)
-    frameworks: ['jasmine'],
-
-    // list of files / patterns to load in the browser
-    files: [
-      // bower:js
-      'bower_components/jquery/dist/jquery.js',
-      'bower_components/es5-shim/es5-shim.js',
-      'bower_components/angular/angular.js',
-      'bower_components/json3/lib/json3.js',
-      'bower_components/bootstrap/dist/js/bootstrap.js',
-      'bower_components/angular-cookies/angular-cookies.js',
-      'bower_components/angular-sanitize/angular-sanitize.js',
-      'bower_components/angular-animate/angular-animate.js',
-      'bower_components/angular-touch/angular-touch.js',
-      'bower_components/angular-route/angular-route.js',
-      'bower_components/angular-resource/angular-resource.js',
-      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
-      'bower_components/angular-websocket/angular-websocket.min.js',
-      'bower_components/ace-builds/src-noconflict/ace.js',
-      'bower_components/ace-builds/src-noconflict/mode-scala.js',
-      'bower_components/ace-builds/src-noconflict/mode-python.js',
-      'bower_components/ace-builds/src-noconflict/mode-sql.js',
-      'bower_components/ace-builds/src-noconflict/mode-markdown.js',
-      'bower_components/ace-builds/src-noconflict/mode-sh.js',
-      'bower_components/ace-builds/src-noconflict/mode-r.js',
-      'bower_components/ace-builds/src-noconflict/keybinding-emacs.js',
-      'bower_components/ace-builds/src-noconflict/ext-language_tools.js',
-      'bower_components/ace-builds/src-noconflict/theme-chrome.js',
-      'bower_components/angular-ui-ace/ui-ace.js',
-      'bower_components/jquery.scrollTo/jquery.scrollTo.js',
-      'bower_components/d3/d3.js',
-      'bower_components/nvd3/build/nv.d3.js',
-      'bower_components/jquery-ui/jquery-ui.js',
-      'bower_components/angular-dragdrop/src/angular-dragdrop.js',
-      'bower_components/perfect-scrollbar/src/perfect-scrollbar.js',
-      'bower_components/ng-sortable/dist/ng-sortable.js',
-      'bower_components/angular-elastic/elastic.js',
-      'bower_components/angular-elastic-input/dist/angular-elastic-input.min.js',
-      'bower_components/angular-xeditable/dist/js/xeditable.js',
-      'bower_components/highlightjs/highlight.pack.js',
-      'bower_components/lodash/lodash.js',
-      'bower_components/angular-filter/dist/angular-filter.js',
-      'bower_components/ngtoast/dist/ngToast.js',
-      'bower_components/ng-focus-if/focusIf.js',
-      'bower_components/bootstrap3-dialog/dist/js/bootstrap-dialog.min.js',
-      'bower_components/zeroclipboard/dist/ZeroClipboard.js',
-      'bower_components/moment/moment.js',
-      'bower_components/pikaday/pikaday.js',
-      'bower_components/handsontable/dist/handsontable.js',
-      'bower_components/moment-duration-format/lib/moment-duration-format.js',
-      'bower_components/select2/dist/js/select2.js',
-      'bower_components/MathJax/MathJax.js',
-      'bower_components/clipboard/dist/clipboard.js',
-      'bower_components/ngclipboard/dist/ngclipboard.js',
-      'bower_components/angular-mocks/angular-mocks.js',
-      // endbower
-
-      'src/index.js',
-      // 'test/spec/**/*.js',
-      {pattern: 'test/spec/**/*.js', watched: false},
-    ],
-
-    // list of files / patterns to exclude
-    exclude: [
-      '.tmp/app/visualization/builtins/*.js'
-    ],
-
-    // web server port
-    port: 9002,
-
-    // Start these browsers, currently available:
-    // - Chrome
-    // - ChromeCanary
-    // - Firefox
-    // - Opera
-    // - Safari (only Mac)
-    // - PhantomJS
-    // - IE (only Windows)
-    browsers: [
-      'PhantomJS'
-    ],
-
-    reporters: ['coverage','progress'],
-
-    webpack: webpackConfig,
-    webpackMiddleware: {
-      stats: 'errors-only'
-    },
-
-    preprocessors: {
-      'src/*/{*.js,!(test)/**/*.js}': 'coverage',
-      'src/index.js': ['webpack', 'sourcemap',],
-      'test/spec/**/*.js': ['webpack', 'sourcemap',],
-    },
-
-    coverageReporter: {
-      type: 'html',
-      dir: '../reports/zeppelin-web-coverage',
-      subdir: '.'
-    },
-
-    // Which plugins to enable
-    plugins: [
-      'karma-phantomjs-launcher',
-      'karma-jasmine',
-      'karma-coverage',
-      'karma-webpack',
-      'karma-sourcemap-loader',
-    ],
-
-    // Continuous Integration mode
-    // if true, it capture browsers, run tests and exit
-    singleRun: true,
-
-    colors: true,
-
-    // level of logging
-    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
-    logLevel: config.LOG_INFO,
-
-    // Uncomment the following lines if you are using grunt's server to run the tests
-    // proxies: {
-    //   '/': 'http://localhost:9000/'
-    // },
-    // URL root prevent conflicts with the site root
-    // urlRoot: '_karma_'
-  });
-};

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/controllers/main.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/main.js b/zeppelin-web/test/spec/controllers/main.js
deleted file mode 100644
index 329fb21..0000000
--- a/zeppelin-web/test/spec/controllers/main.js
+++ /dev/null
@@ -1,29 +0,0 @@
-describe('Controller: MainCtrl', function() {
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-
-  var scope;
-  var rootScope;
-
-  beforeEach(inject(function($controller, $rootScope) {
-    rootScope = $rootScope;
-    scope = $rootScope.$new();
-    $controller('MainCtrl', {
-      $scope: scope
-    });
-  }));
-
-  it('should attach "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);
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/controllers/nav.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/nav.js b/zeppelin-web/test/spec/controllers/nav.js
deleted file mode 100644
index 07a5945..0000000
--- a/zeppelin-web/test/spec/controllers/nav.js
+++ /dev/null
@@ -1,18 +0,0 @@
-describe('Controller: NavCtrl', function() {
-  // load the controller's module
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-  var NavCtrl;
-  var scope;
-  // Initialize the controller and a mock scope
-  beforeEach(inject(function($controller, $rootScope) {
-    scope = $rootScope.$new();
-    NavCtrl = $controller('NavCtrl', {
-      $scope: scope
-    });
-
-    it('NavCtrl to toBeDefined', function() {
-      expect(NavCtrl).toBeDefined();
-      expect(NavCtrl.loadNotes).toBeDefined();
-    });
-  }));
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/controllers/notebook.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/notebook.js b/zeppelin-web/test/spec/controllers/notebook.js
deleted file mode 100644
index f4a420b..0000000
--- a/zeppelin-web/test/spec/controllers/notebook.js
+++ /dev/null
@@ -1,138 +0,0 @@
-describe('Controller: NotebookCtrl', function() {
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-
-  var scope;
-
-  var websocketMsgSrvMock = {
-    getNote: function() {},
-    listRevisionHistory: function() {},
-    getInterpreterBindings: function() {},
-    updateNote: function() {}
-  };
-
-  var baseUrlSrvMock = {
-    getRestApiBase: function() {
-      return 'http://localhost:8080';
-    }
-  };
-
-  var noteMock = {
-    id: 1,
-    name: 'my note',
-    config: {},
-  };
-
-  beforeEach(inject(function($controller, $rootScope) {
-    scope = $rootScope.$new();
-    $controller('NotebookCtrl', {
-      $scope: scope,
-      websocketMsgSrv: websocketMsgSrvMock,
-      baseUrlSrv: baseUrlSrvMock
-    });
-  }));
-
-  beforeEach(function() {
-    scope.note = noteMock;
-  });
-
-  var functions = ['getCronOptionNameFromValue', 'removeNote', 'runAllParagraphs', 'saveNote', 'toggleAllEditor',
-    'showAllEditor', 'hideAllEditor', 'toggleAllTable', 'hideAllTable', 'showAllTable', 'isNoteRunning',
-    'killSaveTimer', 'startSaveTimer', 'setLookAndFeel', 'setCronScheduler', 'setConfig', 'updateNoteName',
-    '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 "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 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('should have "isNoteDirty" as null by default', function() {
-    expect(scope.isNoteDirty).toEqual(null);
-  });
-
-  it('should first call killSaveTimer() when calling startSaveTimer()', function() {
-    expect(scope.saveTimer).toEqual(null);
-    spyOn(scope, 'killSaveTimer');
-    scope.startSaveTimer();
-    expect(scope.killSaveTimer).toHaveBeenCalled();
-  });
-
-  it('should set "saveTimer" when saveTimer() and killSaveTimer() are called', function() {
-    expect(scope.saveTimer).toEqual(null);
-    scope.startSaveTimer();
-    expect(scope.saveTimer).toBeTruthy();
-    scope.killSaveTimer();
-    expect(scope.saveTimer).toEqual(null);
-  });
-
-  it('should NOT update note name when updateNoteName() is called with an invalid name', function() {
-    spyOn(websocketMsgSrvMock, 'updateNote');
-    scope.updateNoteName('');
-    expect(scope.note.name).toEqual(noteMock.name);
-    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
-    scope.updateNoteName(' ');
-    expect(scope.note.name).toEqual(noteMock.name);
-    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
-    scope.updateNoteName(scope.note.name);
-    expect(scope.note.name).toEqual(noteMock.name);
-    expect(websocketMsgSrvMock.updateNote).not.toHaveBeenCalled();
-  });
-
-  it('should update note name when updateNoteName() is called with a valid name', function() {
-    spyOn(websocketMsgSrvMock, 'updateNote');
-    var newName = 'Your Note';
-    scope.updateNoteName(newName);
-    expect(scope.note.name).toEqual(newName);
-    expect(websocketMsgSrvMock.updateNote).toHaveBeenCalled();
-  });
-
-  it('should reload note info once per one "setNoteMenu" event', function() {
-    spyOn(websocketMsgSrvMock, 'getNote');
-    spyOn(websocketMsgSrvMock, 'listRevisionHistory');
-
-    scope.$broadcast('setNoteMenu');
-    expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
-    expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
-
-    websocketMsgSrvMock.getNote.calls.reset();
-    websocketMsgSrvMock.listRevisionHistory.calls.reset();
-
-    scope.$broadcast('setNoteMenu');
-    expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
-    expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
-  });
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/controllers/notename.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/notename.js b/zeppelin-web/test/spec/controllers/notename.js
deleted file mode 100644
index 47e79c1..0000000
--- a/zeppelin-web/test/spec/controllers/notename.js
+++ /dev/null
@@ -1,40 +0,0 @@
-describe('Controller: NotenameCtrl', function() {
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-
-  var scope;
-  var ctrl;
-  var noteList;
-
-  beforeEach(inject(function($injector, $rootScope, $controller) {
-    noteList = $injector.get('noteListDataFactory');
-    scope = $rootScope.$new();
-    ctrl = $controller('NotenameCtrl', {
-      $scope: scope,
-      noteListDataFactory: noteList
-    });
-  }));
-
-  it('should create a new name from current name when cloneNoteName is called', function() {
-    var notesList = [
-      {name: 'dsds 1', id: '1'},
-      {name: 'dsds 2', id: '2'},
-      {name: 'test name', id: '3'},
-      {name: 'aa bb cc', id: '4'},
-      {name: 'Untitled Note 6', id: '4'}
-    ];
-
-    noteList.setNotes(notesList);
-
-    ctrl.sourceNoteName = 'test name';
-    expect(ctrl.cloneNoteName()).toEqual('test name 1');
-    ctrl.sourceNoteName = 'aa bb cc';
-    expect(ctrl.cloneNoteName()).toEqual('aa bb cc 1');
-    ctrl.sourceNoteName = 'Untitled Note 6';
-    expect(ctrl.cloneNoteName()).toEqual('Untitled Note 7');
-    ctrl.sourceNoteName = 'My_note';
-    expect(ctrl.cloneNoteName()).toEqual('My_note 1');
-    ctrl.sourceNoteName = 'dsds 2';
-    expect(ctrl.cloneNoteName()).toEqual('dsds 3');
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/controllers/paragraph.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/paragraph.js b/zeppelin-web/test/spec/controllers/paragraph.js
deleted file mode 100644
index 1aa4a4a..0000000
--- a/zeppelin-web/test/spec/controllers/paragraph.js
+++ /dev/null
@@ -1,51 +0,0 @@
-describe('Controller: ParagraphCtrl', function() {
-
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-
-  var scope;
-  var websocketMsgSrvMock = {};
-  var paragraphMock = {
-    config: {}
-  };
-  var route = {
-    current: {
-      pathParams: {
-        noteId: 'noteId'
-      }
-    }
-  };
-
-  beforeEach(inject(function($controller, $rootScope) {
-    scope = $rootScope.$new();
-    $rootScope.notebookScope = $rootScope.$new(true, $rootScope);
-
-    $controller('ParagraphCtrl', {
-      $scope: scope,
-      websocketMsgSrv: websocketMsgSrvMock,
-      $element: {},
-      $route: route
-    });
-
-    scope.init(paragraphMock);
-  }));
-
-  var functions = ['isRunning', 'getIframeDimensions', 'cancelParagraph', 'runParagraph', 'saveParagraph',
-    'moveUp', 'moveDown', 'insertNew', 'removeParagraph', 'toggleEditor', 'closeEditor', 'openEditor',
-    'closeTable', 'openTable', 'showTitle', 'hideTitle', 'setTitle', 'showLineNumbers', 'hideLineNumbers',
-    'changeColWidth', 'columnWidthClass', 'toggleOutput', 'loadForm',
-    'aceChanged', 'aceLoaded', 'getEditorValue', 'getProgress', 'getExecutionTime', 'isResultOutdated'];
-
-  functions.forEach(function(fn) {
-    it('check for scope functions to be defined : ' + fn, function() {
-      expect(scope[fn]).toBeDefined();
-    });
-  });
-
-  it('should have this array of values for "colWidthOption"', function() {
-    expect(scope.colWidthOption).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
-  });
-
-  it('should set default value of "paragraphFocused" as false', function() {
-    expect(scope.paragraphFocused).toEqual(false);
-  });
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/directives/ngenter.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/directives/ngenter.js b/zeppelin-web/test/spec/directives/ngenter.js
deleted file mode 100644
index d347155..0000000
--- a/zeppelin-web/test/spec/directives/ngenter.js
+++ /dev/null
@@ -1,25 +0,0 @@
-describe('Directive: ngEnter', function() {
-
-  // load the directive's module
-  beforeEach(angular.mock.module('zeppelinWebApp'));
-
-  var element;
-  var scope;
-
-  beforeEach(inject(function($rootScope) {
-    scope = $rootScope.$new();
-  }));
-
-  it('should be define', inject(function($compile) {
-    element = angular.element('<ng-enter></ng-enter>');
-    element = $compile(element)(scope);
-    expect(element.text()).toBeDefined();
-  }));
-
-  //Test the rest of function in ngEnter
-  /*  it('should make hidden element visible', inject(function ($compile) {
-      element = angular.element('<ng-enter></ng-enter>');
-      element = $compile(element)(scope);
-      expect(element.text()).toBe('this is the ngEnter directive');
-    }));*/
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/factory/noteList.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/factory/noteList.js b/zeppelin-web/test/spec/factory/noteList.js
deleted file mode 100644
index 85fb2ba..0000000
--- a/zeppelin-web/test/spec/factory/noteList.js
+++ /dev/null
@@ -1,77 +0,0 @@
-describe('Factory: NoteList', function() {
-
-  var noteList;
-
-  beforeEach(function() {
-    angular.mock.module('zeppelinWebApp');
-
-    inject(function($injector) {
-      noteList = $injector.get('noteListDataFactory');
-    });
-  });
-
-  it('should generate both flat list and folder-based list properly', function() {
-    var notesList = [
-      {name: 'A', id: '000001'},
-      {name: 'B', id: '000002'},
-      {id: '000003'},                     // note without name
-      {name: '/C/CA', id: '000004'},
-      {name: '/C/CB', id: '000005'},
-      {name: '/C/CB/CBA', id: '000006'},  // same name with a dir
-      {name: '/C/CB/CBA', id: '000007'},  // same name with another note
-      {name: 'C///CB//CBB', id: '000008'},
-      {name: 'D/D[A/DA]B', id: '000009'}   // check if '[' and ']' considered as folder seperator
-    ];
-    noteList.setNotes(notesList);
-
-    var flatList = noteList.flatList;
-    expect(flatList.length).toBe(9);
-    expect(flatList[0].name).toBe('A');
-    expect(flatList[0].id).toBe('000001');
-    expect(flatList[1].name).toBe('B');
-    expect(flatList[2].name).toBeUndefined();
-    expect(flatList[3].name).toBe('/C/CA');
-    expect(flatList[4].name).toBe('/C/CB');
-    expect(flatList[5].name).toBe('/C/CB/CBA');
-    expect(flatList[6].name).toBe('/C/CB/CBA');
-    expect(flatList[7].name).toBe('C///CB//CBB');
-    expect(flatList[8].name).toBe('D/D[A/DA]B');
-
-    var folderList = noteList.root.children;
-    expect(folderList.length).toBe(5);
-    expect(folderList[0].name).toBe('A');
-    expect(folderList[0].id).toBe('000001');
-    expect(folderList[1].name).toBe('B');
-    expect(folderList[2].name).toBe('000003');
-    expect(folderList[3].name).toBe('C');
-    expect(folderList[3].id).toBe('C');
-    expect(folderList[3].children.length).toBe(3);
-    expect(folderList[3].children[0].name).toBe('CA');
-    expect(folderList[3].children[0].id).toBe('000004');
-    expect(folderList[3].children[0].children).toBeUndefined();
-    expect(folderList[3].children[1].name).toBe('CB');
-    expect(folderList[3].children[1].id).toBe('000005');
-    expect(folderList[3].children[1].children).toBeUndefined();
-    expect(folderList[3].children[2].name).toBe('CB');
-    expect(folderList[3].children[2].id).toBe('C/CB');
-    expect(folderList[3].children[2].children.length).toBe(3);
-    expect(folderList[3].children[2].children[0].name).toBe('CBA');
-    expect(folderList[3].children[2].children[0].id).toBe('000006');
-    expect(folderList[3].children[2].children[0].children).toBeUndefined();
-    expect(folderList[3].children[2].children[1].name).toBe('CBA');
-    expect(folderList[3].children[2].children[1].id).toBe('000007');
-    expect(folderList[3].children[2].children[1].children).toBeUndefined();
-    expect(folderList[3].children[2].children[2].name).toBe('CBB');
-    expect(folderList[3].children[2].children[2].id).toBe('000008');
-    expect(folderList[3].children[2].children[2].children).toBeUndefined();
-    expect(folderList[4].name).toBe('D');
-    expect(folderList[4].id).toBe('D');
-    expect(folderList[4].children.length).toBe(1);
-    expect(folderList[4].children[0].name).toBe('D[A');
-    expect(folderList[4].children[0].id).toBe('D/D[A');
-    expect(folderList[4].children[0].children[0].name).toBe('DA]B');
-    expect(folderList[4].children[0].children[0].id).toBe('000009');
-    expect(folderList[4].children[0].children[0].children).toBeUndefined();
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c437a191/zeppelin-web/test/spec/tabledata/tabledata.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/tabledata/tabledata.js b/zeppelin-web/test/spec/tabledata/tabledata.js
deleted file mode 100644
index c465606..0000000
--- a/zeppelin-web/test/spec/tabledata/tabledata.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-import TableData from '../../../src/app/tabledata/tabledata.js';
-
-describe('TableData build', function() {
-  var td;
-
-  beforeEach(function() {
-    console.log(TableData);
-    td = new TableData();
-  });
-
-  it('should initialize the default value', function() {
-    expect(td.columns.length).toBe(0);
-    expect(td.rows.length).toBe(0);
-    expect(td.comment).toBe('');
-  });
-
-  it('should able to create Tabledata from paragraph result', function() {
-    td.loadParagraphResult({
-      type: 'TABLE',
-      msg: 'key\tvalue\na\t10\nb\t20\n\nhello'
-    });
-
-    expect(td.columns.length).toBe(2);
-    expect(td.rows.length).toBe(2);
-    expect(td.comment).toBe('hello');
-  });
-});