You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2019/01/17 14:46:11 UTC

[ambari] branch trunk updated: AMBARI-25108 Cover views of the modals with unit tests

This is an automated email from the ASF dual-hosted git repository.

atkach pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new b992966  AMBARI-25108 Cover views of the modals with unit tests
b992966 is described below

commit b992966e3af3a76cab571194b977c921894826ee
Author: Andrii Tkach <at...@apache.org>
AuthorDate: Thu Jan 17 15:31:18 2019 +0200

    AMBARI-25108 Cover views of the modals with unit tests
---
 ambari-web/app/assets/test/tests.js                |   3 +
 .../modal_popups/dependent_configs_list_popup.js   |   6 +-
 .../views/common/modal_popups/invalid_KDC_popup.js |  11 +-
 .../common/modal_popups/select_groups_popup.js     |  85 +++++---
 ambari-web/app/views/main/menu.js                  |   4 +-
 .../dependent_configs_list_popup_test.js           | 239 +++++++++++++++++++--
 .../common/modal_popups/invalid_KDC_popup_test.js  | 104 +++++++++
 .../manage_kdc_credentials_popup_test.js           |  82 +++++++
 .../modal_popups/select_groups_popup_test.js       | 204 ++++++++++++++++++
 ambari-web/test/views/main/menu_test.js            |  16 --
 10 files changed, 671 insertions(+), 83 deletions(-)

diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 30c9f8d..5f003e9 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -294,6 +294,9 @@ var files = [
   'test/views/common/modal_popups/edit_dashboard_widget_popup_test',
   'test/views/common/modal_popups/hosts_table_list_popup_test',
   'test/views/common/modal_popups/dependent_configs_list_popup_test',
+  'test/views/common/modal_popups/invalid_KDC_popup_test',
+  'test/views/common/modal_popups/manage_kdc_credentials_popup_test',
+  'test/views/common/modal_popups/select_groups_popup_test',
   'test/views/main/admin_test',
   'test/views/main/dashboard_test',
   'test/views/main/menu_test',
diff --git a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
index 451d038..9bb15f0 100644
--- a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
+++ b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
@@ -26,9 +26,7 @@ App.DependentConfigsTableView = Em.View.extend({
   elementsWithPopover: function () {
     return this.$('td.config-dependency-name');
   }.property(),
-  hideMessage: function () {
-    return this.get('controller.isInstallWizard');
-  }.property('controller.isInstallWizard'),
+  hideMessage: Em.computed.alias('controller.isInstallWizard'),
   updateRecommendedDefault: function () {
     if (this.get('controller.isInstallWizard')) {
       var applyRecommendations = this.get('recommendations').filterProperty('saveRecommended');
@@ -97,7 +95,7 @@ App.DependentConfigsListView = Em.View.extend({
   }),
   setAllConfigsWithErrors: function () {
     if (this.get('state') === 'inBuffer' || Em.isNone(this.get('controller.stepConfigs'))) {
-      return;
+      return false;
     }
     this.set('allConfigsWithErrors', this.get('controller.stepConfigs').reduce(function (result, stepConfig) {
       if (stepConfig.get('configsWithErrors.length')) {
diff --git a/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js b/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js
index 675e01e..b868f50 100644
--- a/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js
+++ b/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js
@@ -83,16 +83,13 @@ App.showInvalidKDCPopup = function (ajaxOpt, message) {
     },
 
     onSecondary: function() {
-      this.hide();
-      if (ajaxOpt.kdcCancelHandler) {
-        ajaxOpt.kdcCancelHandler();
-      }
+      this.onClose();
     },
-
+  
     onPrimary: function () {
       this.hide();
-        var resource = credentialsUtils.createCredentialResource(this.get('principal'), this.get('password'), this.get('storageType'));
-        App.get('router.clusterController').createKerberosAdminSession(resource, ajaxOpt);
+      var resource = credentialsUtils.createCredentialResource(this.get('principal'), this.get('password'), this.get('storageType'));
+      App.get('router.clusterController').createKerberosAdminSession(resource, ajaxOpt);
     }
   });
 };
diff --git a/ambari-web/app/views/common/modal_popups/select_groups_popup.js b/ambari-web/app/views/common/modal_popups/select_groups_popup.js
index fc54d22..b3c60ce 100644
--- a/ambari-web/app/views/common/modal_popups/select_groups_popup.js
+++ b/ambari-web/app/views/common/modal_popups/select_groups_popup.js
@@ -35,72 +35,91 @@ App.showSelectGroupsPopup = function (selectedServiceName, selectedConfigGroup,
     selectedConfigGroup: selectedConfigGroup,
     dependentStepConfigs: dependentStepConfigs,
     selectedGroups: {},
-    didInsertElement: function() {
+    didInsertElement: function () {
       this._super();
-      this.set('selectedGroups', $.extend({},selectedConfigGroup.get('dependentConfigGroups')));
+      this.set('selectedGroups', $.extend({}, selectedConfigGroup.get('dependentConfigGroups')));
     },
     bodyClass: Em.CollectionView.extend({
       content: dependentStepConfigs,
       itemViewClass: Em.View.extend({
         templateName: require('templates/common/modal_popups/select_groups_popup'),
-        didInsertElement: function() {
+        didInsertElement: function () {
           this.set('selectedGroup', this.get('parentView.parentView.selectedConfigGroup.dependentConfigGroups')[this.get('serviceName')]);
         },
         hasGroups: Em.computed.bool('groups.length'),
         serviceName: Em.computed.alias('content.serviceName'),
         selectedGroup: null,
-        updateGroup: function() {
-          var dependentGroups = $.extend({},this.get('parentView.parentView.selectedConfigGroup.dependentConfigGroups'));
+        updateGroup: function () {
+          var dependentGroups = $.extend({}, this.get('parentView.parentView.selectedConfigGroup.dependentConfigGroups'));
           dependentGroups[this.get('serviceName')] = this.get('selectedGroup');
           this.set('parentView.parentView.selectedConfigGroup.dependentConfigGroups', dependentGroups);
         }.observes('selectedGroup'),
-        groups: function() {
+        groups: function () {
           return this.get('content').get('configGroups').filterProperty('isDefault', false).mapProperty('name');
         }.property('content')
       })
     }),
     onPrimary: function () {
       this._super();
-      Object.keys(this.get('selectedConfigGroup.dependentConfigGroups')).forEach(function(serviceName) {
+      Object.keys(this.get('selectedConfigGroup.dependentConfigGroups')).forEach(function (serviceName) {
         var selectedGroupName = this.get('selectedConfigGroup.dependentConfigGroups')[serviceName];
         var currentGroupName = this.get('selectedGroups')[serviceName] || "";
         var configGroup = this.get('dependentStepConfigs').findProperty('serviceName', serviceName).get('configGroups').findProperty('name', selectedGroupName);
         if (!configGroup) return; //There can be no dependent config group.
-        if (selectedGroupName != currentGroupName) {
+        if (selectedGroupName !== currentGroupName) {
           /** changing config group for recommendations **/
           configs.filterProperty('serviceName', serviceName).filterProperty('configGroup', selectedGroupName).forEach(function (c) {
-            if (configs.filterProperty('serviceName', serviceName).filterProperty('configGroup', currentGroupName)) {
-              configs.removeObject(c);
-            }
+            configs.removeObject(c);
           });
           configs.filterProperty('serviceName', serviceName).filterProperty('configGroup', currentGroupName).setEach('configGroup', selectedGroupName);
           /** danger part!!!! changing config group ***/
-          this.get('dependentStepConfigs').findProperty('serviceName', serviceName).get('configs').forEach(function(cp) {
-            var dependentConfig = configs.filterProperty('propertyName', cp.get('name')).filterProperty('fileName', App.config.getConfigTagFromFileName(cp.get('filename'))).findProperty('configGroup', selectedGroupName);
-            var recommendedValue = dependentConfig && Em.get(dependentConfig, 'recommendedValue');
-            if (cp.get('overrides')) {
-              var currentGroupOverride = cp.get('overrides').findProperty('group.name', currentGroupName);
-              if (currentGroupOverride && currentGroupOverride.get('initialValue') != currentGroupOverride.get('recommendedValue')) {
-                currentGroupOverride.set('group', configGroup);
-                currentGroupOverride.set('recommendedValue', recommendedValue);
-                currentGroupOverride.set('value', recommendedValue);
-              } else {
-                var selectedGroupOverride = cp.get('overrides').findProperty('group.name', configGroup.get('name'));
-                if (selectedGroupOverride) {
-                  selectedGroupOverride.set('recommendedValue', recommendedValue);
-                  selectedGroupOverride.set('value', recommendedValue);
-                } else {
-                  App.config.createOverride(cp, {"value": recommendedValue, "recommendedValue": recommendedValue,"isEditable": true}, configGroup);
-                }
-              }
+          this.applyOverridesToConfigGroups(serviceName, configGroup, currentGroupName, selectedGroupName);
+        }
+      }, this);
+    },
+    
+    /**
+     *
+     * @param serviceName
+     * @param configGroup
+     * @param currentGroupName
+     * @param selectedGroupName
+     */
+    applyOverridesToConfigGroups: function(serviceName, configGroup, currentGroupName, selectedGroupName) {
+      this.get('dependentStepConfigs').findProperty('serviceName', serviceName).get('configs').forEach(function (cp) {
+        var dependentConfig = configs.filterProperty('propertyName', cp.get('name'))
+        .filterProperty('fileName', App.config.getConfigTagFromFileName(cp.get('filename')))
+        .findProperty('configGroup', selectedGroupName);
+        var recommendedValue = dependentConfig && Em.get(dependentConfig, 'recommendedValue');
+        if (cp.get('overrides')) {
+          var currentGroupOverride = cp.get('overrides').findProperty('group.name', currentGroupName);
+          if (currentGroupOverride && currentGroupOverride.get('initialValue') !== currentGroupOverride.get('recommendedValue')) {
+            currentGroupOverride.set('group', configGroup);
+            currentGroupOverride.set('recommendedValue', recommendedValue);
+            currentGroupOverride.set('value', recommendedValue);
+          } else {
+            var selectedGroupOverride = cp.get('overrides').findProperty('group.name', configGroup.get('name'));
+            if (selectedGroupOverride) {
+              selectedGroupOverride.set('recommendedValue', recommendedValue);
+              selectedGroupOverride.set('value', recommendedValue);
             } else {
-              App.config.createOverride(cp, {"value": recommendedValue, "recommendedValue": recommendedValue,"isEditable": true}, configGroup);
+              App.config.createOverride(cp, {
+                "value": recommendedValue,
+                "recommendedValue": recommendedValue,
+                "isEditable": true
+              }, configGroup);
             }
-          }, this)
+          }
+        } else {
+          App.config.createOverride(cp, {
+            "value": recommendedValue,
+            "recommendedValue": recommendedValue,
+            "isEditable": true
+          }, configGroup);
         }
-      }, this);
+      }, this)
     },
-    onSecondary: function() {
+    onSecondary: function () {
       this._super();
       this.get('selectedConfigGroup').set('dependentConfigGroups', this.get('selectedGroups'));
     }
diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js
index cf8085b..3a4ca54 100644
--- a/ambari-web/app/views/main/menu.js
+++ b/ambari-web/app/views/main/menu.js
@@ -22,9 +22,7 @@ App.MainSideMenuView = Em.CollectionView.extend({
   tagName: 'ul',
   classNames: ['nav', 'side-nav-menu', 'nav-pills', 'nav-stacked'],
 
-  views: function () {
-    return App.router.get('mainViewsController.ambariViews');
-  }.property('App.router.mainViewsController.ambariViews'),
+  views: Em.computed.alias('App.router.mainViewsController.ambariViews'),
 
   didInsertElement: function() {
     $('[data-toggle="collapse-side-nav"]').on('click', () => {
diff --git a/ambari-web/test/views/common/modal_popups/dependent_configs_list_popup_test.js b/ambari-web/test/views/common/modal_popups/dependent_configs_list_popup_test.js
index f351347..f4b3603 100644
--- a/ambari-web/test/views/common/modal_popups/dependent_configs_list_popup_test.js
+++ b/ambari-web/test/views/common/modal_popups/dependent_configs_list_popup_test.js
@@ -20,37 +20,236 @@
 var App = require('app');
 require('views/common/modal_popups/hosts_table_list_popup');
 
-var view;
-
-describe('App.showDependentConfigsPopup', function () {
 
+describe('App.DependentConfigsTableView', function () {
+  var view;
+ 
+  
   beforeEach(function () {
-    sinon.stub(Em.run, 'next', Em.K);
-    sinon.stub(Em.run, 'once', Em.K);
+    view = App.DependentConfigsTableView.create({
+      controller: Em.Object.create({
+        undoRedoRecommended: sinon.spy()
+      }),
+      parentView: Em.Object.create(),
+      elementsWithPopover: {
+        popover: sinon.spy()
+      },
+      recommendations: [
+        {
+          saveRecommended: false
+        },
+        {
+          saveRecommended: true
+        }
+      ]
+    });
   });
 
-  afterEach(function () {
-    Em.run.next.restore();
-    Em.run.once.restore();
+  describe('#updateRecommendedDefault', function() {
+    
+    it('undoRedoRecommended should be called with applyRecommendations', function() {
+      view.set('controller.isInstallWizard', true);
+      
+      view.updateRecommendedDefault();
+      expect(view.get('controller').undoRedoRecommended.calledWith(
+        [{saveRecommended: true}], true
+      )).to.be.true;
+    });
+  
+    it('undoRedoRecommended should be called with dontApplyRecommendations', function() {
+      view.set('controller.isInstallWizard', true);
+    
+      view.updateRecommendedDefault();
+      expect(view.get('controller').undoRedoRecommended.calledWith(
+        [{saveRecommended: false}], false
+      )).to.be.true;
+    });
+  });
+  
+  describe('#message', function() {
+    
+    it('should return required message', function() {
+      view.set('isEditable', false);
+      view.propertyDidChange('message');
+      expect(view.get('message')).to.be.equal(Em.I18n.t('popup.dependent.configs.title.required'));
+    });
+  
+    it('should return values message', function() {
+      view.set('isEditable', true);
+      view.set('parentView.isAfterRecommendation', false);
+      view.propertyDidChange('message');
+      expect(view.get('message')).to.be.equal(Em.I18n.t('popup.dependent.configs.title.values'));
+    });
+  
+    it('should return recommendation message', function() {
+      view.set('isEditable', true);
+      view.set('parentView.isAfterRecommendation', true);
+      view.propertyDidChange('message');
+      expect(view.get('message')).to.be.equal(
+        Em.I18n.t('popup.dependent.configs.title.recommendation') +
+        '<br>' +Em.I18n.t('popup.dependent.configs.title.values')
+      );
+    });
   });
+  
+  describe('#didInsertElement', function() {
+    beforeEach(function() {
+      sinon.stub(App, 'popover');
+    });
+    afterEach(function() {
+      App.popover.restore();
+    });
+    
+    it('App.popover should be called', function() {
+      view.set('showPopovers', true);
+      view.didInsertElement();
+      expect(App.popover.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#willDestroyElement', function() {
+    
+    it('popover should be called', function() {
+      view.set('showPopovers', true);
+      view.willDestroyElement();
+      expect(view.get('elementsWithPopover').popover.calledOnce).to.be.true;
+    });
+  });
+  
+});
 
-  describe('#onClose', function () {
+describe('App.DependentConfigsListView', function () {
+  var view;
+  
+  
+  beforeEach(function () {
+    view = App.DependentConfigsListView.create({
+      controller: Em.Object.create(),
+      parentView: Em.Object.create()
+    });
+  });
+  
+  describe('#setAllConfigsWithErrors', function() {
+    
+    it('no stepConfigs', function() {
+      view.set('controller.stepConfigs', null);
+      view.setAllConfigsWithErrors();
+      expect(view.get('allConfigsWithErrors')).to.be.empty;
+    });
+  
+    it('should copy configWithErrors to allConfigsWithErrors', function() {
+      view.set('controller.stepConfigs', [Em.Object.create({
+        configsWithErrors: [{}]
+      })]);
+      view.setAllConfigsWithErrors();
+      expect(view.get('allConfigsWithErrors')).to.be.eql([{}]);
+    });
+  });
+  
+  describe('#didInsertElement', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'setAllConfigsWithErrors');
+    });
+    afterEach(function() {
+      view.setAllConfigsWithErrors.restore();
+    });
+    
+    it('setAllConfigsWithErrors should be called', function() {
+      view.didInsertElement();
+      expect(view.setAllConfigsWithErrors.calledOnce).to.be.true;
+    });
+  });
+});
 
+describe('App.showDependentConfigsPopup', function () {
+  var view;
+  
+  describe('#saveChanges', function () {
+    
     beforeEach(function () {
-      this.ff = function () {};
-      sinon.spy(this, 'ff');
-      view = App.showDependentConfigsPopup([], [], Em.K, this.ff);
+      this.recommendations = [{saveRecommended: true}];
+      view = App.showDependentConfigsPopup(this.recommendations, [], this.primary);
     });
-
+    
+    it('should save saveRecommendedDefault', function () {
+      view.saveChanges();
+      expect(this.recommendations[0].saveRecommendedDefault).to.be.true;
+    });
+  });
+  
+  describe('#discardChanges', function () {
+    
+    beforeEach(function () {
+      this.recommendations = [{saveRecommendedDefault: true}];
+      view = App.showDependentConfigsPopup(this.recommendations, [], this.primary);
+    });
+    
+    it('should discard saveRecommended', function () {
+      view.discardChanges();
+      expect(this.recommendations[0].saveRecommended).to.be.true;
+    });
+  });
+  
+  describe('#onPrimary', function () {
+    
+    beforeEach(function () {
+      this.primary = sinon.spy();
+      view = App.showDependentConfigsPopup([], [], this.primary);
+      sinon.stub(view, 'saveChanges');
+    });
+    
     afterEach(function () {
-      this.ff.restore();
+      view.saveChanges.restore();
     });
-
+    
+    it('should call primary-callback', function () {
+      view.onPrimary();
+      expect(this.primary.calledOnce).to.be.true;
+    });
+    
+    it('saveChanges should be called', function () {
+      view.onPrimary();
+      expect(view.saveChanges.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#onSecondary', function () {
+    
+    beforeEach(function () {
+      this.secondary = sinon.spy();
+      view = App.showDependentConfigsPopup([], [], Em.K, this.secondary);
+      sinon.stub(view, 'discardChanges');
+    });
+  
+    afterEach(function () {
+      view.discardChanges.restore();
+    });
+    
     it('should call secondary-callback', function () {
-      view.onClose();
-      expect(this.ff.calledOnce).to.be.true;
+      view.onSecondary();
+      expect(this.secondary.calledOnce).to.be.true;
+    });
+  
+    it('discardChanges should be called', function () {
+      view.onSecondary();
+      expect(view.discardChanges.calledOnce).to.be.true;
     });
-
   });
-
-});
\ No newline at end of file
+  
+  describe('#onClose', function () {
+    
+    beforeEach(function () {
+      view = App.showDependentConfigsPopup([], [], Em.K);
+      sinon.stub(view, 'onSecondary');
+    });
+    
+    afterEach(function () {
+      view.onSecondary.restore();
+    });
+    
+    it('onSecondary should be called', function () {
+      view.onSecondary();
+      expect(view.onSecondary.calledOnce).to.be.true;
+    });
+  });
+});
diff --git a/ambari-web/test/views/common/modal_popups/invalid_KDC_popup_test.js b/ambari-web/test/views/common/modal_popups/invalid_KDC_popup_test.js
new file mode 100644
index 0000000..d7bf1c6
--- /dev/null
+++ b/ambari-web/test/views/common/modal_popups/invalid_KDC_popup_test.js
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+require('views/common/modal_popups/invalid_KDC_popup');
+
+describe('App.showInvalidKDCPopup', function () {
+  var view,
+    ajaxOpt = {
+        kdcCancelHandler: sinon.spy()
+      };
+  
+  describe('#onClose', function () {
+    
+    beforeEach(function () {
+      view = App.showInvalidKDCPopup(ajaxOpt);
+      sinon.stub(view, 'hide');
+    });
+    
+    afterEach(function() {
+      view.hide.restore();
+    });
+  
+    it('kdcCancelHandler should be called', function () {
+      view.onClose();
+      expect(ajaxOpt.kdcCancelHandler.calledOnce).to.be.true;
+    });
+    
+    it('hide should be called', function () {
+      view.onClose();
+      expect(view.hide.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#onSecondary', function () {
+    
+    beforeEach(function () {
+      view = App.showInvalidKDCPopup(ajaxOpt);
+      sinon.stub(view, 'onClose');
+    });
+    
+    afterEach(function() {
+      view.onClose.restore();
+    });
+    
+    it('onClose should be called', function () {
+      view.onSecondary();
+      expect(view.onClose.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#onSecondary', function () {
+    
+    beforeEach(function () {
+      view = App.showInvalidKDCPopup(ajaxOpt);
+      sinon.stub(view, 'onClose');
+    });
+    
+    afterEach(function() {
+      view.onClose.restore();
+    });
+    
+    it('onClose should be called', function () {
+      view.onSecondary();
+      expect(view.onClose.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#onPrimary', function () {
+    var mock = {
+      createKerberosAdminSession: sinon.spy()
+    };
+    
+    beforeEach(function () {
+      view = App.showInvalidKDCPopup(ajaxOpt);
+      sinon.stub(App, 'get').returns(mock);
+    });
+    
+    afterEach(function() {
+      App.get.restore();
+    });
+    
+    it('createKerberosAdminSession should be called', function () {
+      view.onPrimary();
+      expect(mock.createKerberosAdminSession.calledOnce).to.be.true;
+    });
+  });
+});
diff --git a/ambari-web/test/views/common/modal_popups/manage_kdc_credentials_popup_test.js b/ambari-web/test/views/common/modal_popups/manage_kdc_credentials_popup_test.js
new file mode 100644
index 0000000..ff21e46
--- /dev/null
+++ b/ambari-web/test/views/common/modal_popups/manage_kdc_credentials_popup_test.js
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+require('views/common/modal_popups/manage_kdc_credentials_popup');
+
+describe('App.showManageCredentialsPopup', function () {
+  var view;
+  
+  describe('#onPrimary', function () {
+    
+    beforeEach(function () {
+      view = App.showManageCredentialsPopup();
+    });
+
+    it('saveKDCCredentials should be called', function () {
+      var formView = {
+        saveKDCCredentials: sinon.stub().returns({
+          always: Em.clb
+        })
+      };
+      view.reopen({
+        formView: formView
+      });
+      sinon.stub(view, 'hide');
+      
+      view.onPrimary();
+      expect(formView.saveKDCCredentials.called).to.be.true;
+  
+      view.hide.restore();
+    });
+  
+    it('hide should be called', function () {
+      sinon.stub(view, 'hide');
+    
+      view.onPrimary();
+      expect(view.hide.calledOnce).to.be.true;
+    
+      view.hide.restore();
+    });
+  });
+  
+  describe('#onThird', function () {
+    
+    beforeEach(function () {
+      view = App.showManageCredentialsPopup();
+    });
+    
+    it('removeKDCCredentials should be called', function () {
+      var formView = {
+        removeKDCCredentials: sinon.stub().returns({deferred: {
+          always: Em.clb
+        }})
+      };
+      view.reopen({
+        formView: formView
+      });
+      sinon.stub(view, 'hide');
+      
+      view.onThird();
+      expect(formView.removeKDCCredentials.called).to.be.true;
+      
+      view.hide.restore();
+    });
+  });
+});
diff --git a/ambari-web/test/views/common/modal_popups/select_groups_popup_test.js b/ambari-web/test/views/common/modal_popups/select_groups_popup_test.js
new file mode 100644
index 0000000..78be0b8
--- /dev/null
+++ b/ambari-web/test/views/common/modal_popups/select_groups_popup_test.js
@@ -0,0 +1,204 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+require('views/common/modal_popups/select_groups_popup');
+
+describe('App.showSelectGroupsPopup', function () {
+  var view;
+  
+  describe('#onSecondary', function () {
+  
+    beforeEach(function () {
+      view = App.showSelectGroupsPopup('', Em.Object.create({
+        dependentConfigGroups: {
+          S1: 'g1'
+        }
+      }), []);
+    });
+
+    it('dependentConfigGroups should be set', function () {
+      view.set('selectedGroups', {g1: {}});
+      view.onSecondary();
+      expect(view.get('selectedConfigGroup.dependentConfigGroups')).to.be.eql({
+        g1: {}
+      });
+    });
+  });
+  
+  
+  describe('#onPrimary', function () {
+    var configs = [
+      {
+        serviceName: 'S1',
+        configGroup: 'g1'
+      },
+      {
+        serviceName: 'S1',
+        configGroup: 'g2'
+      }
+    ];
+    beforeEach(function () {
+      view = App.showSelectGroupsPopup('', Em.Object.create({
+          dependentConfigGroups: {
+            S1: 'g1'
+          }
+        }),
+        [
+          Em.Object.create({
+            serviceName: 'S1',
+            configGroups: [
+              {
+                name: 'g1'
+              }
+            ]
+          })
+        ],
+        configs);
+      sinon.stub(view, 'applyOverridesToConfigGroups');
+    });
+  
+    afterEach(function() {
+      view.applyOverridesToConfigGroups.restore();
+    });
+    
+    it('configs should be modified', function () {
+      view.set('selectedGroups', {
+        S1: 'g2'
+      });
+      view.onPrimary();
+      expect(JSON.stringify(configs)).to.be.eql(JSON.stringify([{
+        serviceName: 'S1',
+        configGroup: 'g1'
+      }]));
+    });
+  
+    it('applyOverridesToConfigGroups should be called', function () {
+      view.set('selectedGroups', {
+        S1: 'g2'
+      });
+      view.onPrimary();
+      expect(view.applyOverridesToConfigGroups.calledOnce).to.be.true;
+    });
+  });
+  
+  describe('#applyOverridesToConfigGroups', function () {
+    var configs = [
+      {
+        propertyName: 'c1',
+        fileName: 'site',
+        serviceName: 'S1',
+        configGroup: 'g1',
+        recommendedValue: 'val1'
+      }
+    ];
+    var dependentStepConfigs = [
+      Em.Object.create({
+        serviceName: 'S1',
+        configGroups: [
+          {
+            name: 'g1'
+          }
+        ],
+        configs: [
+          Em.Object.create({
+            name: 'c1',
+            filename: 'site'
+          })
+        ]
+      })
+    ];
+    beforeEach(function () {
+      sinon.stub(App.config, 'createOverride');
+    });
+    
+    afterEach(function() {
+      App.config.createOverride.restore();
+    });
+   
+    it('App.config.createOverride should be called when no overrides', function () {
+      view = App.showSelectGroupsPopup('', {}, dependentStepConfigs, configs);
+      view.applyOverridesToConfigGroups('S1', {}, 'g2', 'g1');
+      expect(App.config.createOverride.calledWith(
+        Em.Object.create({
+          name: 'c1',
+          filename: 'site'
+        }),
+        {
+          "value": 'val1',
+          "recommendedValue": 'val1',
+          "isEditable": true
+        }, {}
+      )).to.be.true;
+    });
+  
+    it('should set value of override to recommended', function () {
+      var override = Em.Object.create({
+        group: {
+          name: 'g2'
+        },
+        initialValue: 'val2',
+        recommendedValue: 'val1'
+      });
+      dependentStepConfigs[0].get('configs')[0].set('overrides', [override]);
+      view = App.showSelectGroupsPopup('', {}, dependentStepConfigs, configs);
+      view.applyOverridesToConfigGroups('S1', {}, 'g2', 'g1');
+      expect(override.get('value')).to.be.equal('val1');
+    });
+  
+    it('App.config.createOverride should be called when no overrides for selected group', function () {
+      var override = Em.Object.create({
+        group: {
+          name: 'g2'
+        },
+        initialValue: 'val1',
+        recommendedValue: 'val1'
+      });
+      dependentStepConfigs[0].get('configs')[0].set('overrides', [override]);
+      view = App.showSelectGroupsPopup('', {}, dependentStepConfigs, configs);
+      view.applyOverridesToConfigGroups('S1', Em.Object.create({name: 'g1'}), 'g2', 'g1');
+      expect(App.config.createOverride.calledWith(
+        Em.Object.create({
+          name: 'c1',
+          filename: 'site',
+          overrides: [override]
+        }),
+        {
+          "value": 'val1',
+          "recommendedValue": 'val1',
+          "isEditable": true
+        }, Em.Object.create({name: 'g1'})
+      )).to.be.true;
+    });
+  
+    it('should set value of override to recommended for selected group', function () {
+      var override = Em.Object.create({
+        group: {
+          name: 'g2'
+        },
+        initialValue: 'val1',
+        recommendedValue: 'val1'
+      });
+      dependentStepConfigs[0].get('configs')[0].set('overrides', [override]);
+      view = App.showSelectGroupsPopup('', {}, dependentStepConfigs, configs);
+      view.applyOverridesToConfigGroups('S1', Em.Object.create({name: 'g2'}), 'g2', 'g1');
+      expect(override.get('value')).to.be.equal('val1');
+    });
+  });
+});
diff --git a/ambari-web/test/views/main/menu_test.js b/ambari-web/test/views/main/menu_test.js
index f7dff30..3279102 100644
--- a/ambari-web/test/views/main/menu_test.js
+++ b/ambari-web/test/views/main/menu_test.js
@@ -27,22 +27,6 @@ describe('App.MainMenuView', function () {
     view = App.MainSideMenuView.create();
   });
 
-  describe("#views", function () {
-
-    beforeEach(function() {
-      sinon.stub(App.router, 'get').withArgs('mainViewsController.ambariViews').returns([{}]);
-    });
-
-    afterEach(function() {
-      App.router.get.restore();
-    });
-
-    it("should return views", function() {
-      view.propertyDidChange('views');
-      expect(view.get('views')).to.be.eql([{}]);
-    });
-  });
-
   describe("#itemViewClass", function () {
     var itemViewClass;