diff --git a/frontend-js/src/main/js/Configuration.js b/frontend-js/src/main/js/Configuration.js
index beadc52c9e654e11957de7f8934dbacf0f27fa0c..df5d61bea47e7ba9235def7a00ea95df0824f64f 100644
--- a/frontend-js/src/main/js/Configuration.js
+++ b/frontend-js/src/main/js/Configuration.js
@@ -12,6 +12,27 @@ var MiriamType = require('./map/data/MiriamType');
 var PrivilegeType = require('./map/data/PrivilegeType');
 var ModificationStateType = require('./map/data/ModificationStateType');
 
+/**
+ * @typedef {Object} BioEntityType
+ * @property {string} className - string identifying java class
+ * @property {string} name - common name of element
+ * @property {string} parentClass - string identifying parent java class
+ */
+
+/**
+ * @typedef {Object} BioEntityTypeTreeNode
+ * @property {string} text - string description of node
+ * @property {BioEntityTypeTreeNode[]} children - set if children types
+ * @property {BioEntityType} data - metadata of the type
+ *
+ */
+
+
+/**
+ *
+ * @param {Object|Configuration} json
+ * @constructor
+ */
 function Configuration(json) {
   var self = this;
 
@@ -66,23 +87,50 @@ function Configuration(json) {
   }
 }
 
+/**
+ *
+ * @param {string} version
+ */
 Configuration.prototype.setVersion = function (version) {
   this._version = version;
 };
+
+/**
+ *
+ * @returns {string}
+ */
 Configuration.prototype.getVersion = function () {
   return this._version;
 };
 
+/**
+ *
+ * @param {string} buildDate
+ */
 Configuration.prototype.setBuildDate = function (buildDate) {
   this._buildDate = buildDate;
 };
+
+/**
+ *
+ * @returns {string}
+ */
 Configuration.prototype.getBuildDate = function () {
   return this._buildDate;
 };
 
+/**
+ *
+ * @param {string} gitHash
+ */
 Configuration.prototype.setGitHash = function (gitHash) {
   this._gitHash = gitHash;
 };
+
+/**
+ *
+ * @returns {string}
+ */
 Configuration.prototype.getGitHash = function () {
   return this._gitHash;
 };
@@ -410,6 +458,10 @@ Configuration.prototype.update = function (original) {
   }
 };
 
+/**
+ *
+ * @returns {BioEntityTypeTreeNode}
+ */
 Configuration.prototype.getElementTypeTree = function () {
   var elementTypes = this.getElementTypes();
   var reactionTypes = this.getReactionTypes();
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index a4d4f5bb0fcce4131ef7fe74359107037b8247e7..b5f1f91ffc246eb2d9cf8487c0c153f3420c1afb 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -1170,7 +1170,7 @@ ServerConnector.getUser = function (login) {
   return self.sendGetRequest(self.getUserUrl(queryParams, filterParams)).then(function (content) {
     var obj = JSON.parse(content);
     var user = new User(obj);
-    if (self._usersByLogin[user.getLogin()] !== undefined) {
+    if (self._usersByLogin[user.getLogin()] instanceof User) {
       self._usersByLogin[user.getLogin()].update(user);
     } else {
       self._usersByLogin[user.getLogin()] = user;
@@ -1314,12 +1314,8 @@ ServerConnector.updateUserPreferences = function (params) {
   }).then(function (content) {
     var obj = JSON.parse(content);
     var user = new User(obj);
-    if (self._usersByLogin[user.getLogin()] !== undefined) {
-      self._usersByLogin[user.getLogin()].getPreferences().update(user.getPreferences());
-    } else {
-      self._usersByLogin[user.getLogin()] = user;
-    }
-    return self._usersByLogin[user.getLogin()];
+    params.user.getPreferences().update(user.getPreferences());
+    return params.user;
   });
 };
 
diff --git a/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js b/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd6441728532085b3ce19efdb1a72656562a4dbc
--- /dev/null
+++ b/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js
@@ -0,0 +1,42 @@
+"use strict";
+
+/* exported logger */
+
+var AbstractGuiElement = require('../AbstractGuiElement');
+
+// noinspection JSUnusedLocalSymbols
+var logger = require('../../logger');
+
+function AbstractAnnotatorsDialog(params) {
+  AbstractGuiElement.call(this, params);
+}
+
+AbstractAnnotatorsDialog.prototype = Object.create(AbstractGuiElement.prototype);
+AbstractAnnotatorsDialog.prototype.constructor = AbstractAnnotatorsDialog;
+
+/**
+ *
+ * @param {BioEntityType} elementType
+ * @param {boolean} [includeChildren=false]
+ *
+ * @returns {BioEntityType[]}
+ */
+AbstractAnnotatorsDialog.prototype.getAllChildrenTypesIfNeeded = function (elementType, includeChildren) {
+  var result = [elementType];
+  if (includeChildren) {
+    var queue = [elementType];
+    var elementTypes = this.getConfiguration().getElementTypes();
+    while (queue.length > 0) {
+      var type = queue.shift();
+      for (var i = 0; i < elementTypes.length; i++) {
+        if (type.className === elementTypes[i].parentClass) {
+          queue.push(elementTypes[i]);
+          result.push(elementTypes[i]);
+        }
+      }
+    }
+  }
+  return result;
+};
+
+module.exports = AbstractAnnotatorsDialog;
diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
index a436197c2afc643d766b5fcb0159975209c58744..00bf2533ae0ecf84245cac06d1d360302d7eab3e 100644
--- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
@@ -131,7 +131,8 @@ AddProjectDialog.prototype.showAnnotatorsDialog = function () {
     self._annotatorsDialog = new ChooseAnnotatorsDialog({
       element: Functions.createElement({type: "div"}),
       customMap: null,
-      configuration: self.getConfiguration()
+      configuration: self.getConfiguration(),
+      serverConnector: self.getServerConnector()
     });
     promise = self._annotatorsDialog.init();
   } else {
@@ -147,7 +148,9 @@ AddProjectDialog.prototype.showValidatorsDialog = function () {
   if (self._validatorsDialog === undefined) {
     self._validatorsDialog = new ChooseValidatorsDialog({
       element: Functions.createElement({type: "div"}),
-      customMap: null
+      configuration: self.getConfiguration(),
+      customMap: null,
+      serverConnector: self.getServerConnector()
     });
     promise = self._validatorsDialog.init();
   } else {
diff --git a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js
index e86ed8f7880052202cfb6125d358ea910913398b..f7969805f7927a073312f7882d0af621483d2c09 100644
--- a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js
+++ b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js
@@ -2,7 +2,7 @@
 
 /* exported logger */
 
-var AbstractGuiElement = require('../AbstractGuiElement');
+var AbstractAnnotatorsDialog = require('./AbstractAnnotatorsDialog');
 var GuiConnector = require("../../GuiConnector");
 var MultiCheckboxList = require("multi-checkbox-list");
 var UserPreferences = require("../../map/data/UserPreferences");
@@ -12,12 +12,12 @@ var Functions = require('../../Functions');
 var logger = require('../../logger');
 
 function ChooseAnnotatorsDialog(params) {
-  AbstractGuiElement.call(this, params);
+  AbstractAnnotatorsDialog.call(this, params);
   var self = this;
   self.createGui();
 }
 
-ChooseAnnotatorsDialog.prototype = Object.create(AbstractGuiElement.prototype);
+ChooseAnnotatorsDialog.prototype = Object.create(AbstractAnnotatorsDialog.prototype);
 ChooseAnnotatorsDialog.prototype.constructor = ChooseAnnotatorsDialog;
 
 ChooseAnnotatorsDialog.prototype.createGui = function () {
@@ -81,25 +81,6 @@ ChooseAnnotatorsDialog.prototype.saveAnnotatorsInfo = function (elementTypes, se
   }).catch(GuiConnector.alert);
 };
 
-ChooseAnnotatorsDialog.prototype.getAllChildrenTypesIfNeeded = function (elementType, includeChildren) {
-  var result = [elementType];
-  if (includeChildren) {
-    var queue = [elementType];
-    var elementTypes = this.getConfiguration().getElementTypes();
-    while (queue.length > 0) {
-      var type = queue.shift();
-      for (var i = 0; i < elementTypes.length; i++) {
-        if (type.className === elementTypes[i].parentClass) {
-          queue.push(elementTypes[i]);
-          result.push(elementTypes[i]);
-        }
-      }
-    }
-  }
-  return result;
-};
-
-
 ChooseAnnotatorsDialog.prototype.setElementType = function (elementType) {
   var self = this;
 
diff --git a/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js b/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js
index 1241d1c4e0eab5527b165a179657f645e62f8106..2e5e45c36fff45804aa80ec812d79223817e0455 100644
--- a/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js
+++ b/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js
@@ -2,26 +2,41 @@
 
 /* exported logger */
 
-var AbstractGuiElement = require('../AbstractGuiElement');
-var DualListbox = require('dual-listbox').DualListbox;
+var AbstractAnnotatorsDialog = require('./AbstractAnnotatorsDialog');
 var GuiConnector = require("../../GuiConnector");
 var UserPreferences = require("../../map/data/UserPreferences");
 var MultiCheckboxList = require("multi-checkbox-list");
 
 var Functions = require('../../Functions');
+// noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
-var Promise = require("bluebird");
-
+/**
+ *
+ /**
+ *
+ * @param {Object} params
+ * @param {HTMLElement} params.element
+ * @param {CustomMap} params.customMap
+ * @param {Configuration} [params.configuration]
+ * @param {ServerConnector} [params.serverConnector]
+ *
+ * @constructor
+ *
+ * @extends AbstractGuiElement
+ */
 function ChooseValidatorsDialog(params) {
-  AbstractGuiElement.call(this, params);
+  AbstractAnnotatorsDialog.call(this, params);
   var self = this;
   self.createGui();
 }
 
-ChooseValidatorsDialog.prototype = Object.create(AbstractGuiElement.prototype);
+ChooseValidatorsDialog.prototype = Object.create(AbstractAnnotatorsDialog.prototype);
 ChooseValidatorsDialog.prototype.constructor = ChooseValidatorsDialog;
 
+/**
+ *
+ */
 ChooseValidatorsDialog.prototype.createGui = function () {
   var self = this;
   var content = Functions.createElement({
@@ -45,14 +60,19 @@ ChooseValidatorsDialog.prototype.createGui = function () {
   self.getElement().appendChild(content);
 };
 
+/**
+ *
+ * @param {BioEntityType} elementType
+ * @returns {Promise}
+ */
 ChooseValidatorsDialog.prototype.setElementType = function (elementType) {
   var self = this;
 
   var configuration;
 
-  return ServerConnector.getConfiguration().then(function (result) {
+  return self.getServerConnector().getConfiguration().then(function (result) {
     configuration = result;
-    return ServerConnector.getLoggedUser();
+    return self.getServerConnector().getLoggedUser();
   }).then(function (user) {
     var element = $("[name='annotatorListBox']", self.getElement())[0];
     Functions.removeChildren(element);
@@ -70,11 +90,108 @@ ChooseValidatorsDialog.prototype.setElementType = function (elementType) {
     });
     element.appendChild(verifyAnnotationSelect);
     self.createVerifyAnnotationsDualListBox(user, configuration, elementType, verifyAnnotationSelect);
+
+    element.appendChild(Functions.createElement({type: "br"}));
+    var includeChildrenCheckbox = Functions.createElement({type: "input", inputType: "checkbox"});
+    var copyFromButton = Functions.createElement({
+      type: "button", content: "Copy from", name: "copy-from-validator", onclick: function () {
+        var typeClassName = copyFromSelect.value;
+        var requiredAnnotations, validAnnotators;
+        for (var i = 0; i < configuration.getElementTypes().length; i++) {
+          var type = configuration.getElementTypes()[i];
+          if (typeClassName === type.className) {
+            requiredAnnotations = user.getPreferences().getElementRequiredAnnotations(typeClassName);
+            validAnnotators = user.getPreferences().getElementValidAnnotations(typeClassName);
+          }
+        }
+        if (requiredAnnotations === undefined) {
+          return GuiConnector.alert("Invalid element type: " + copyFromSelect.value);
+        } else {
+          var includeChildren = includeChildrenCheckbox.checked;
+          return self.saveAnnotationsInfo({
+            elementTypes: self.getAllChildrenTypesIfNeeded(elementType, includeChildren),
+            requiredAnnotators: requiredAnnotations,
+            validAnnotators: validAnnotators
+          }).then(function () {
+            return self.setElementType(elementType);
+          });
+        }
+      }
+    });
+    element.appendChild(copyFromButton);
+    var copyFromSelect = Functions.createElement({type: "select", style: "margin:5px"});
+    element.appendChild(copyFromSelect);
+    var options = [], i;
+    for (i = 0; i < configuration.getElementTypes().length; i++) {
+      var type = configuration.getElementTypes()[i];
+      var name = type.className;
+      if (name.indexOf(".") > 0) {
+        name = name.substr(name.lastIndexOf(".") + 1);
+      }
+      options.push(Functions.createElement({
+        type: "option",
+        value: type.className,
+        content: name
+      }));
+    }
+    options.sort(function (a, b) {
+      return a.text === b.text ? 0 : a.text < b.text ? -1 : 1
+    });
+    for (i = 0; i < options.length; i++) {
+      copyFromSelect.appendChild(options[i]);
+    }
+    element.appendChild(includeChildrenCheckbox);
+    element.appendChild(Functions.createElement({type: "span", content: "Apply to all in subtree"}));
+
   });
 
 };
 
+/**
+ *
+ * @param {BioEntityType[]} params.elementTypes
+ * @param {{list:string[], requiredAtLeastOnce:boolean}} params.requiredAnnotators
+ * @param {string[]} params.validAnnotators
+ *
+ * @returns {Promise}
+ */
+ChooseValidatorsDialog.prototype.saveAnnotationsInfo = function (params) {
+  var elementTypes = params.elementTypes;
+  var requiredAnnotators = params.requiredAnnotators;
+  var validAnnotators = params.validAnnotators;
+  var self = this;
+  return self.getServerConnector().getLoggedUser().then(function (user) {
+
+    var data = new UserPreferences();
+
+    var elementRequiredAnnotators = {};
+    var elementValidAnnotators = {};
+    for (var i = 0; i < elementTypes.length; i++) {
+      elementRequiredAnnotators[elementTypes[i].className] = {
+        "require-at-least-one": requiredAnnotators.requiredAtLeastOnce,
+        "annotation-list": requiredAnnotators.list.slice()
+      };
+      elementValidAnnotators[elementTypes[i].className] = validAnnotators.slice();
+    }
+    data.setElementRequiredAnnotations(elementRequiredAnnotators);
+    data.setElementValidAnnotations(elementValidAnnotators);
+    return self.getServerConnector().updateUserPreferences({
+      user: user,
+      preferences: data
+    });
+  }).catch(GuiConnector.alert);
+};
+
+
+/**
+ *
+ * @param {User} user
+ * @param {Configuration} configuration
+ * @param {BioEntityType} elementType
+ * @param {HTMLElement} validAnnotationSelect
+ */
 ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (user, configuration, elementType, validAnnotationSelect) {
+  var self = this;
 
   var miriamTypes = configuration.getMiriamTypes();
 
@@ -87,7 +204,6 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
     var miriamType = miriamTypes[i];
     var entry = {name: miriamType.getCommonName(), value: miriamType.getName(), selected: false};
 
-    var selected = false;
     for (var j = 0; j < validAnnotations.length; j++) {
       if (miriamType.getName() === validAnnotations[j]) {
         entry.selected = true;
@@ -125,7 +241,10 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
     var elementAnnotators = {};
     elementAnnotators[elementType.className] = validAnnotations;
     data.setElementValidAnnotations(elementAnnotators);
-    return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
+    return self.getServerConnector().updateUserPreferences({
+      user: user,
+      preferences: data
+    }).catch(GuiConnector.alert);
   };
 
   checkboxList.addListener("select", function (element) {
@@ -137,14 +256,23 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
 
 };
 
+/**
+ *
+ * @param {User} user
+ * @param {Configuration} configuration
+ * @param {BioEntityType} elementType
+ * @param {HTMLElement} verifyAnnotationSelect
+ */
+
 ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (user, configuration, elementType, verifyAnnotationSelect) {
+  var self = this;
   var requiredAnnotationsData = user.getPreferences().getElementRequiredAnnotations(elementType.className);
 
   var verifyCheckboxDiv = Functions.createElement({type: "div"});
   var checkbox = Functions.createElement({
-    id: "test",
     type: "input",
     inputType: "checkbox",
+    name: "require-at-least-one-checkbox",
     onclick: function () {
       var data = new UserPreferences();
 
@@ -154,7 +282,7 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
         "annotation-list": requiredAnnotationsData.list
       };
       data.setElementRequiredAnnotations(elementRequiredAnnotations);
-      return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
+      return self.getServerConnector().updateUserPreferences({user: user, preferences: data}).catch(GuiConnector.alert);
     }
   });
   checkbox.checked = requiredAnnotationsData.requiredAtLeastOnce;
@@ -215,7 +343,7 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
       "annotation-list": requiredAnnotationsData.list
     };
     data.setElementRequiredAnnotations(elementRequiredAnnotations);
-    return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
+    return self.getServerConnector().updateUserPreferences({user: user, preferences: data}).catch(GuiConnector.alert);
   };
 
   checkboxList.addListener("select", function (element) {
@@ -227,9 +355,13 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
 
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 ChooseValidatorsDialog.prototype.init = function () {
   var self = this;
-  return ServerConnector.getConfiguration().then(function (configuration) {
+  return self.getServerConnector().getConfiguration().then(function (configuration) {
 
     var treeData = configuration.getElementTypeTree();
 
@@ -248,10 +380,16 @@ ChooseValidatorsDialog.prototype.init = function () {
   });
 };
 
+/**
+ *
+ */
 ChooseValidatorsDialog.prototype.destroy = function () {
   $(this.getElement()).dialog("destroy");
 };
 
+/**
+ *
+ */
 ChooseValidatorsDialog.prototype.open = function () {
   var self = this;
   var div = self.getElement();
diff --git a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
index 939f0eb159ef19145d3046c1a804879f8b580bc9..f09ccc985410b0478df811e8365d18119e36d6d6 100644
--- a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
@@ -282,7 +282,8 @@ MapsAdminPanel.prototype.onAddClicked = function () {
         type: "div"
       }),
       customMap: null,
-      configuration: self.getConfiguration()
+      configuration: self.getConfiguration(),
+      serverConnector: self.getServerConnector()
     });
     self._addDialog = dialog;
     dialog.addListener("onProjectAdd", function () {
diff --git a/frontend-js/src/main/js/map/data/UserPreferences.js b/frontend-js/src/main/js/map/data/UserPreferences.js
index 36ff821d76c9f6f184047d51a2875af2ce813b6a..a42b804aad16f17f893c01fd6412c0018018d192 100644
--- a/frontend-js/src/main/js/map/data/UserPreferences.js
+++ b/frontend-js/src/main/js/map/data/UserPreferences.js
@@ -34,8 +34,8 @@ UserPreferences.prototype.update = function (userPreferences) {
 
   updateDict(this._projectUpload, userPreferences.getProjectUpload());
   updateDict(this._elementAnnotators, userPreferences.getElementAnnotators);
-  updateDict(this._elementValidAnnotations, userPreferences.getElementValidAnnotations());
-  updateDict(this._elementRequiredAnnotations, userPreferences.getElementRequiredAnnotations());
+  updateDict(this._elementValidAnnotations, userPreferences._elementValidAnnotations);
+  updateDict(this._elementRequiredAnnotations, userPreferences._elementRequiredAnnotations);
   updateDict(this._annotatorsParameters, userPreferences.getAnnotatorsParameters());
   updateDict(this._guiPreferences, userPreferences.getGuiPreferences());
 };
@@ -78,6 +78,12 @@ UserPreferences.prototype.getProjectUpload = function () {
 UserPreferences.prototype.setElementAnnotators = function (elementAnnotators) {
   this._elementAnnotators = elementAnnotators;
 };
+
+/**
+ *
+ * @param {string} className
+ * @returns {string[]}
+ */
 UserPreferences.prototype.getElementAnnotators = function (className) {
   var result = this._elementAnnotators[className];
   if (result === undefined) {
@@ -86,6 +92,11 @@ UserPreferences.prototype.getElementAnnotators = function (className) {
   }
   return result;
 };
+
+/**
+ *
+ * @param {Object<string, Object>} elementRequiredAnnotations
+ */
 UserPreferences.prototype.setElementRequiredAnnotations = function (elementRequiredAnnotations) {
   this._elementRequiredAnnotations = {};
   for (var key in elementRequiredAnnotations) {
@@ -98,16 +109,33 @@ UserPreferences.prototype.setElementRequiredAnnotations = function (elementRequi
     }
   }
 };
+
+/**
+ *
+ * @param {string} className
+ * @returns {{list:string[], requiredAtLeastOnce:boolean}}
+ */
 UserPreferences.prototype.getElementRequiredAnnotations = function (className) {
   var result = this._elementRequiredAnnotations[className];
   if (result === undefined) {
-    result = {list: []};
+    result = {list: [], requiredAtLeastOnce: false};
   }
   return result;
 };
+
+/**
+ *
+ * @param {Object<string,string[]>}elementValidAnnotations
+ */
 UserPreferences.prototype.setElementValidAnnotations = function (elementValidAnnotations) {
   this._elementValidAnnotations = elementValidAnnotations;
 };
+
+/**
+ *
+ * @param {string} className
+ * @returns {string[]}
+ */
 UserPreferences.prototype.getElementValidAnnotations = function (className) {
   var result = this._elementValidAnnotations[className];
   if (result === undefined) {
diff --git a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
index a1e373fcd61fa20bf2328d7b9ffd2655260db4f9..a83943d8057db13e978ca78523d1d612fd0342cd 100644
--- a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
@@ -3,7 +3,6 @@
 require("../../mocha-config");
 
 var AddProjectDialog = require('../../../../main/js/gui/admin/AddProjectDialog');
-var ConfigurationType = require('../../../../main/js/ConfigurationType');
 var ServerConnector = require('../../ServerConnector-mock');
 var ValidationError = require('../../../../main/js/ValidationError');
 
@@ -23,13 +22,13 @@ describe('AddProjectDialog', function () {
     return new AddProjectDialog({
       element: testDiv,
       customMap: null,
-      configuration: helper.getConfiguration()
+      configuration: helper.getConfiguration(),
+      serverConnector: ServerConnector
     });
   };
   it('init', function () {
     helper.loginAsAdmin();
     var dialog = createDialog();
-    var manualUrl;
     return dialog.init().then(function () {
       assert.ok(dialog.getNotifyEmail() !== "");
       assert.equal(0, logger.getWarnings().length);
diff --git a/frontend-js/src/test/js/gui/admin/ChooseValidatorsDialog-test.js b/frontend-js/src/test/js/gui/admin/ChooseValidatorsDialog-test.js
index b92f7df9a55b821cb149554cf615923f9c926e58..c40a4c1d5b0ef26763e231abe14c911e31d411d5 100644
--- a/frontend-js/src/test/js/gui/admin/ChooseValidatorsDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/ChooseValidatorsDialog-test.js
@@ -5,6 +5,7 @@ require("../../mocha-config");
 var ChooseValidatorsDialog = require('../../../../main/js/gui/admin/ChooseValidatorsDialog');
 var ServerConnector = require('../../ServerConnector-mock');
 var logger = require('../../logger');
+var Promise = require('bluebird');
 
 var chai = require('chai');
 var assert = chai.assert;
@@ -13,7 +14,8 @@ describe('ChooseValidatorsDialog', function () {
   it('init', function () {
     var dialog = new ChooseValidatorsDialog({
       element: testDiv,
-      customMap: null
+      customMap: null,
+      serverConnector: ServerConnector
     });
     assert.equal(0, logger.getWarnings().length);
     return dialog.init();
@@ -22,11 +24,54 @@ describe('ChooseValidatorsDialog', function () {
   it('setElementType', function () {
     var dialog = new ChooseValidatorsDialog({
       element: testDiv,
-      customMap: null
+      customMap: null,
+      serverConnector: ServerConnector
     });
     return ServerConnector.getConfiguration().then(function (configuration) {
       return dialog.setElementType(configuration.getReactionTypes()[0]);
     })
   });
 
+  it('open', function () {
+    var dialog = new ChooseValidatorsDialog({
+      element: testDiv,
+      customMap: null,
+      serverConnector: ServerConnector
+    });
+    return dialog.init().then(function () {
+      return dialog.open();
+    }).then(function () {
+      return dialog.destroy();
+    }).then(function () {
+      assert.equal(logger.getWarnings().length, 0);
+    });
+  });
+
+  it('copy from', function () {
+    helper.loginAsAdmin();
+    var originalFunction = ServerConnector.updateUserPreferences;
+    var functionCalled = false;
+    var dialog = new ChooseValidatorsDialog({
+      element: testDiv,
+      customMap: null,
+      serverConnector: ServerConnector
+    });
+    return dialog.init().then(function () {
+      return dialog.open();
+    }).then(function () {
+      return dialog.setElementType(helper.getConfiguration().getReactionTypes()[0]);
+    }).then(function () {
+      ServerConnector.updateUserPreferences = function (params) {
+        functionCalled = true;
+        return Promise.resolve(params.user);
+      };
+      return $("[name='copy-from-validator']")[0].onclick();
+    }).then(function () {
+      assert.ok(functionCalled);
+    }).finally(function () {
+      ServerConnector.updateUserPreferences = originalFunction;
+      return dialog.destroy();
+    });
+  });
+
 });
diff --git a/frontend-js/src/test/js/map/data/UserPreferences-test.js b/frontend-js/src/test/js/map/data/UserPreferences-test.js
index 28b2c517262bd43ebcbc607a15b5b29e8be8f93f..44ebb515d4b09ed828257da7b984e40613439594 100644
--- a/frontend-js/src/test/js/map/data/UserPreferences-test.js
+++ b/frontend-js/src/test/js/map/data/UserPreferences-test.js
@@ -40,4 +40,23 @@ describe('UserPreferences', function () {
     object.setGuiPreference("test", "val");
     assert.ok(object.getGuiPreference("test") === "val");
   });
+
+  describe("update", function () {
+    it("requiredAtLeastOnce", function () {
+      return helper.readFile("testFiles/preferences.json").then(function (content) {
+        var object = new UserPreferences(JSON.parse(content));
+
+        var modifiedObject = new UserPreferences(JSON.parse(content));
+        var newValue = !modifiedObject.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce;
+        modifiedObject.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce = newValue;
+
+        assert.equal(newValue, !object.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce);
+
+        object.update(modifiedObject);
+        assert.equal(newValue, object.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce);
+      });
+    });
+  });
+
+
 });