diff --git a/composer.json b/composer.json
index d7ad8e5963984d10a73a4734516816f4076bfe96..e75fa765964c5f3fe07588cf84ff6360a5679fa5 100644
--- a/composer.json
+++ b/composer.json
@@ -171,7 +171,7 @@
         "drupal/token": "1.7",
         "drupal/twig_tweak": "2.6",
         "drupal/twitter_block": "3.0-alpha0",
-        "drupal/userprotect": "1.0",
+        "drupal/userprotect": "1.1",
         "drupal/video_embed_field": "2.4",
         "drupal/view_unpublished": "1.0-rc1",
         "drupal/views_accordion": "1.1",
diff --git a/composer.lock b/composer.lock
index b4fa092ecd8a0ed198805514a09f715f17a97ca3..2b05c44f242f32b70ae07286b99c4860b379d094 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "b9be0e811209c12590dacc555ae9d6b5",
+    "content-hash": "7330c5a1f65d3610e46131939e58c151",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -7824,29 +7824,29 @@
         },
         {
             "name": "drupal/userprotect",
-            "version": "1.0.0",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/userprotect.git",
-                "reference": "8.x-1.0"
+                "reference": "8.x-1.1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.0.zip",
-                "reference": "8.x-1.0",
-                "shasum": "addff8ed82e8cdb77073e2a8b023a7e9809f856b"
+                "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.1.zip",
+                "reference": "8.x-1.1",
+                "shasum": "485e240317a7fc1c0523b082f333c983ea3ca639"
             },
             "require": {
-                "drupal/core": "*"
+                "drupal/core": "^8 || ^9"
+            },
+            "require-dev": {
+                "drupal/role_delegation": "^1.0"
             },
             "type": "drupal-module",
             "extra": {
-                "branch-alias": {
-                    "dev-1.x": "1.x-dev"
-                },
                 "drupal": {
-                    "version": "8.x-1.0",
-                    "datestamp": "1477741139",
+                    "version": "8.x-1.1",
+                    "datestamp": "1578341583",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 1665601de5f3e1f49199f7cde891a7e6eba01cfa..46983c31e787604d098edec4cbe89bc3fe14e7f7 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -8066,30 +8066,30 @@
     },
     {
         "name": "drupal/userprotect",
-        "version": "1.0.0",
-        "version_normalized": "1.0.0.0",
+        "version": "1.1.0",
+        "version_normalized": "1.1.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/userprotect.git",
-            "reference": "8.x-1.0"
+            "reference": "8.x-1.1"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.0.zip",
-            "reference": "8.x-1.0",
-            "shasum": "addff8ed82e8cdb77073e2a8b023a7e9809f856b"
+            "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.1.zip",
+            "reference": "8.x-1.1",
+            "shasum": "485e240317a7fc1c0523b082f333c983ea3ca639"
         },
         "require": {
-            "drupal/core": "*"
+            "drupal/core": "^8 || ^9"
+        },
+        "require-dev": {
+            "drupal/role_delegation": "^1.0"
         },
         "type": "drupal-module",
         "extra": {
-            "branch-alias": {
-                "dev-1.x": "1.x-dev"
-            },
             "drupal": {
-                "version": "8.x-1.0",
-                "datestamp": "1477741139",
+                "version": "8.x-1.1",
+                "datestamp": "1578341583",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
diff --git a/web/modules/userprotect/README.txt b/web/modules/userprotect/README.txt
index 541d6f1da3d86cbf28f868c040d9434185b924de..08624242eba609c7018fd36ebad72a5d85da924c 100644
--- a/web/modules/userprotect/README.txt
+++ b/web/modules/userprotect/README.txt
@@ -1,6 +1,88 @@
-User protect
+User Protect
+============
+
+CONTENTS OF THIS FILE
+---------------------
+
+ * Introduction
+ * Requirements
+ * Installation
+ * Configuration
+ * Maintainers
+
+
+INTRODUCTION
+------------
+
+The User Protect module allows fine-grained access control of user
+administrators, by providing various editing protection for users. The
+protections can be specific to a user, or applied to all users in a role.
+
+The following protections are supported:
+
+ * Username
+ * E-mail address
+ * Password
+ * Status
+ * Roles
+ * Edit operation (user/X/edit)
+ * Delete operation (user/X/cancel)
+
+ * For a full description of the module visit:
+   https://www.drupal.org/project/userprotect
+
+ * To submit bug reports and feature suggestions, or to track changes visit:
+   https://www.drupal.org/project/issues/userprotect
+
+
+REQUIREMENTS
+------------
+
+This module requires no modules outside of Drupal core.
+
+
+INSTALLATION
 ------------
-by MegaChriz
-Previously (Drupal 7 and before) written by Chad Philips.
 
-This module provides various editing protection for users.
+ * Install the User Protect module as you would normally install a contributed
+   Drupal module. Visit https://www.drupal.org/node/1897420 for further
+   information.
+
+
+CONFIGURATION
+-------------
+
+    1. Navigate to Administration > Extend and enable the module.
+    2. Navigate to Administration > Configuration > People > User protect for
+       configurations.
+
+There are two types of protection rules:
+
+ * User based protection rules:
+   This user will be protected for all users except: "User 1" (admin), the
+   protected user itself, and users with the permissions to "Bypass all user
+   protections".
+ * Role based protection rules:
+   This role will be protected for all users except: "User 1" (admin), and users
+   with the permissions to "Bypass all user protections".
+
+A protection rule prevents any user to perform the selected editing operations
+(such as changing password or changing mail address) on the specified user.
+There are two exceptions in which a configured protection rule does not apply:
+
+ * The logged in user has permission to bypass the protection rule.
+
+ * The specified user is the current logged in user.
+   Protection rules don't count for the user itself. Instead, there are
+   permissions available to prevent an user from editing its own account,
+   username, e-mail address, or password.
+
+Protected fields will be disabled or hidden on the form at user/X/edit. The edit
+and delete operations are protected by controlling entity access for the
+operations 'update' and 'delete'.
+
+
+MAINTAINERS
+-----------
+
+ * Youri van Koppen (MegaChriz) - https://www.drupal.org/user/654114
diff --git a/web/modules/userprotect/composer.json b/web/modules/userprotect/composer.json
index 8a6b1edfbc89dbf251c8532fc257f5ec7cbf4b74..834032db32c2ab54173ac2f555987e63f5133d27 100644
--- a/web/modules/userprotect/composer.json
+++ b/web/modules/userprotect/composer.json
@@ -8,5 +8,8 @@
   "support": {
     "issues": "https://www.drupal.org/project/issues/userprotect",
     "source": "http://cgit.drupalcode.org/userprotect"
+  },
+  "require-dev": {
+    "drupal/role_delegation": "^1.0"
   }
 }
diff --git a/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php b/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php
new file mode 100644
index 0000000000000000000000000000000000000000..a127d27cdc306f1d52b6f81681abf528260ad0ef
--- /dev/null
+++ b/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\userprotect\Access;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Routing\Access\AccessInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\user\UserInterface;
+
+/**
+ * Class UserProtectRoleAccessCheck.
+ *
+ * @package Drupal\userprotect\Access
+ */
+class UserProtectRoleAccessCheck implements AccessInterface {
+
+  /**
+   * Custom access check for the /user/%/roles.
+   *
+   * This check will only occur when role_delegation is enabled.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   Run access checks for this account.
+   * @param \Drupal\user\UserInterface $user
+   *   The user we are editing.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(AccountInterface $account, UserInterface $user) {
+    $access_result = $user->access('user_roles', $account) ? AccessResult::allowed() : AccessResult::forbidden();
+    return $access_result->cachePerUser()->addCacheableDependency($user);
+  }
+
+}
diff --git a/web/modules/userprotect/src/Annotation/UserProtection.php b/web/modules/userprotect/src/Annotation/UserProtection.php
index 37e53237cbad2f462a0cce2f5de38dc5f05f8740..325b5e25c264c385306d26f4bc2c5db039b496bf 100644
--- a/web/modules/userprotect/src/Annotation/UserProtection.php
+++ b/web/modules/userprotect/src/Annotation/UserProtection.php
@@ -21,32 +21,33 @@ class UserProtection extends Plugin {
   /**
    * The human-readable name of the protection.
    *
-   * @ingroup plugin_translatable
-   *
    * @var \Drupal\Core\Annotation\Translation
+   *
+   * @ingroup plugin_translatable
    */
   public $label;
 
   /**
    * A brief description of the protection.
    *
-   * @ingroup plugin_translatable
+   * @var \Drupal\Core\Annotation\Translation
    *
-   * @var \Drupal\Core\Annotation\Translation (optional)
+   * @ingroup plugin_translatable
    */
   public $description = '';
 
   /**
    * A default weight used for presentation in the user interface only.
    *
-   * @var int (optional)
+   * @var int
    */
   public $weight = 0;
 
   /**
    * Whether this protection is enabled or disabled by default.
    *
-   * @var bool (optional)
+   * @var bool
    */
   public $status = FALSE;
+
 }
diff --git a/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php b/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php
index b637a158de7e2d90f8c22d32e31e99b7d71a983d..487918a56007fcd827386c78de55a8136c9d4fe8 100644
--- a/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php
+++ b/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php
@@ -3,7 +3,7 @@
 namespace Drupal\userprotect\Controller;
 
 use Drupal\userprotect\Entity\ProtectionRuleInterface;
-use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Entity\EntityInterface;
 
@@ -11,6 +11,7 @@
  * Provides a listing of protection rules.
  */
 class ProtectionRuleListBuilder extends ConfigEntityListBuilder {
+
   /**
    * {@inheritdoc}
    */
@@ -26,13 +27,13 @@ public function buildHeader() {
    * {@inheritdoc}
    */
   public function buildRow(EntityInterface $entity) {
-    $row['label'] = $this->getLabel($entity);
+    $row['label'] = $entity->label();
     $protected_entity = $entity->getProtectedEntity();
     if ($protected_entity instanceof EntityInterface) {
       $row['entity'] = $protected_entity->label();
     }
     else {
-      $row['entity'] = SafeMarkup::format('%missing', array('%missing' => $this->t('Missing')));
+      $row['entity'] = new FormattableMarkup('%missing', ['%missing' => $this->t('Missing')]);
     }
     $row['type'] = $entity->getProtectedEntityTypeId();
     $row['protection'] = $this->getProtections($entity);
@@ -58,4 +59,5 @@ public function getProtections(ProtectionRuleInterface $entity) {
       return $item->label();
     }, $enabled_protections));
   }
+
 }
diff --git a/web/modules/userprotect/src/Entity/ProtectionRule.php b/web/modules/userprotect/src/Entity/ProtectionRule.php
index daf756ecbb2ecef9b610e39bf7f07536a56ef5d7..0fcbaa34f3803a69b6e84cc509e31bc8661bc300 100644
--- a/web/modules/userprotect/src/Entity/ProtectionRule.php
+++ b/web/modules/userprotect/src/Entity/ProtectionRule.php
@@ -9,10 +9,8 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\UserInterface;
-use Drupal\userprotect\Entity\ProtectionRuleInterface;
 use Drupal\userprotect\UserProtect;
 use Drupal\userprotect\Plugin\UserProtection\UserProtectionPluginCollection;
-use Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface;
 
 /**
  * Defines the Protection rule entity.
@@ -36,6 +34,14 @@
  *     "label" = "label",
  *     "uuid" = "uuid"
  *   },
+ *   config_export = {
+ *     "name",
+ *     "label",
+ *     "uuid",
+ *     "protectedEntityTypeId",
+ *     "protectedEntityId",
+ *     "protections"
+ *   },
  *   links = {
  *     "edit-form" = "/admin/config/people/userprotect/manage/{userprotect_rule}",
  *     "delete-form" = "/admin/config/people/userprotect/manage/{userprotect_rule}/delete"
@@ -86,7 +92,7 @@ class ProtectionRule extends ConfigEntityBase implements ProtectionRuleInterface
    *
    * @var array
    */
-  protected $protections = array();
+  protected $protections = [];
 
   /**
    * Holds the collection of protections that are used by this protection rule.
@@ -107,7 +113,7 @@ class ProtectionRule extends ConfigEntityBase implements ProtectionRuleInterface
    *
    * @var array
    */
-  protected $bypassRoles = array();
+  protected $bypassRoles = [];
 
   /**
    * Overrides Drupal\Core\Entity\Entity::id().
@@ -129,7 +135,7 @@ public function getProtectedEntityTypeId() {
   public function setProtectedEntityTypeId($entity_type_id) {
     // Check if given entity type exists. An InvalidArgumentException will be
     // thrown if not.
-    \Drupal::entityManager()->getDefinition($entity_type_id, TRUE);
+    \Drupal::entityTypeManager()->getDefinition($entity_type_id, TRUE);
 
     $this->protectedEntityTypeId = $entity_type_id;
     return $this;
@@ -140,7 +146,7 @@ public function setProtectedEntityTypeId($entity_type_id) {
    */
   public function getProtectedEntity() {
     if ($this->getProtectedEntityId()) {
-      return entity_load($this->getProtectedEntityTypeId(), $this->getProtectedEntityId());
+      return \Drupal::entityTypeManager()->getStorage($this->getProtectedEntityTypeId())->load($this->getProtectedEntityId());
     }
   }
 
@@ -180,7 +186,7 @@ public function getProtections() {
    * {@inheritdoc}
    */
   public function getPluginCollections() {
-    return array('protections' => $this->getProtections());
+    return ['protections' => $this->getProtections()];
   }
 
   /**
@@ -199,7 +205,7 @@ public function setPluginConfig($instance_id, array $configuration) {
    * {@inheritdoc}
    */
   public function enableProtection($instance_id) {
-    $this->setPluginConfig($instance_id, array('status' => TRUE));
+    $this->setPluginConfig($instance_id, ['status' => TRUE]);
     return $this;
   }
 
@@ -207,7 +213,7 @@ public function enableProtection($instance_id) {
    * {@inheritdoc}
    */
   public function disableProtection($instance_id) {
-    $this->setPluginConfig($instance_id, array('status' => FALSE));
+    $this->setPluginConfig($instance_id, ['status' => FALSE]);
     return $this;
   }
 
@@ -216,11 +222,11 @@ public function disableProtection($instance_id) {
    */
   public function toArray() {
     $properties = parent::toArray();
-    $names = array(
+    $names = [
       'protections',
       'protectedEntityTypeId',
       'protectedEntityId',
-    );
+    ];
     foreach ($names as $name) {
       $properties[$name] = $this->get($name);
     }
@@ -298,7 +304,7 @@ public function postSave(EntityStorageInterface $storage_controller, $update = T
     if ($roles && $permission) {
       foreach (user_roles() as $rid => $name) {
         $enabled = in_array($rid, $roles, TRUE);
-        user_role_change_permissions($rid, array($permission => $enabled));
+        user_role_change_permissions($rid, [$permission => $enabled]);
       }
     }
   }
@@ -364,4 +370,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account)
     // In all other cases, the operation is not protected by this rule.
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php b/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php
index c73c305268c1fa30153946efb6c1f5af9cc47e38..90ab7da2bb8e2436d3c794d335a6d4b47c0b8c7f 100644
--- a/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php
+++ b/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php
@@ -10,6 +10,7 @@
  * Provides an interface defining a userprotect_rule entity.
  */
 interface ProtectionRuleInterface extends ConfigEntityInterface {
+
   /**
    * Gets the protected entity type id.
    *
@@ -180,4 +181,5 @@ public function hasProtection($protection);
    *   FALSE if the operation is not protected by this rule.
    */
   public function isProtected(UserInterface $user, $op, AccountInterface $account);
+
 }
diff --git a/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php b/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php
index 3381e1e2158e45c93fd94fe78d2445078f7aaa47..44a6fb3777363f68e6b5bbe48d714964a695b63b 100644
--- a/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php
+++ b/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php
@@ -9,11 +9,16 @@
  * Provides a form controller for adding a protection rule.
  */
 class ProtectionRuleAddForm extends ProtectionRuleFormBase {
+
   /**
    * Overrides EntityFormController::buildForm().
    *
    * Sets protected entity type on protection rule entity.
    *
+   * @param array $form
+   *   Nested array of form elements that comprise the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $protected_entity_type_id
    *   (optional) The entity type to protect.
    *   Defaults to 'user_role'.
@@ -39,7 +44,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $protecte
    */
   public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
-    drupal_set_message($this->t('Added protection rule %name.', array('%name' => $this->entity->label())));
+    $this->messenger->addMessage($this->t('Added protection rule %name.', ['%name' => $this->entity->label()]));
   }
 
 }
diff --git a/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php b/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php
index 715360989d9b40769f834c610e6247b5af4bece9..4da60d6ca2bf8bf8b8d79b4807200c0c1335f59c 100644
--- a/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php
+++ b/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php
@@ -15,7 +15,7 @@ class ProtectionRuleDeleteForm extends EntityConfirmFormBase {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return $this->t('Are you sure you want to delete %name?', array('%name' => $this->entity->label()));
+    return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]);
   }
 
   /**
@@ -37,7 +37,7 @@ public function getConfirmText() {
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->entity->delete();
-    drupal_set_message($this->t('Protection rule %label has been deleted.', array('%label' => $this->entity->label())));
+    $this->messenger()->addMessage($this->t('Protection rule %label has been deleted.', ['%label' => $this->entity->label()]));
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
 
diff --git a/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php b/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php
index 8d682e0ab342cc290cd4baed0122f1c1f3f9d1bb..a4ebef263dcc9fb9184d34820c7ea76e3dc95f68 100644
--- a/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php
+++ b/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php
@@ -13,7 +13,7 @@ class ProtectionRuleEditForm extends ProtectionRuleFormBase {
    * {@inheritdoc}
    */
   public function form(array $form, FormStateInterface $form_state) {
-    $form['#title'] = $this->t('Edit protection rule %name', array('%name' => $this->entity->label()));
+    $form['#title'] = $this->t('Edit protection rule %name', ['%name' => $this->entity->label()]);
     $form = parent::form($form, $form_state);
     return $form;
   }
@@ -23,7 +23,7 @@ public function form(array $form, FormStateInterface $form_state) {
    */
   public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
-    drupal_set_message(t('Updated protection rule %name.', array('%name' => $this->entity->label())));
+    $this->messenger->addMessage($this->t('Updated protection rule %name.', ['%name' => $this->entity->label()]));
     return $this->entity;
   }
 
diff --git a/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php b/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php
index 15b480abb074996a775bb53db4325322422c4bd7..48498bd4cd0ad2d6cb9a71358528db7de55cf8d7 100644
--- a/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php
+++ b/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php
@@ -2,10 +2,11 @@
 
 namespace Drupal\userprotect\Form;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Entity\EntityForm;
+use Drupal\user\UserStorageInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\MessengerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -20,14 +21,38 @@ abstract class ProtectionRuleFormBase extends EntityForm {
    */
   protected $protectionRuleStorage;
 
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\user\UserStorageInterface
+   */
+  protected $userStorage;
+
+  /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
   /**
    * Constructs a base class for protection rule add and edit forms.
    *
    * @param \Drupal\Core\Entity\EntityStorageInterface $protection_rule_storage
    *   The protection rule entity storage controller.
+   * @param \Drupal\user\UserStorageInterface $user_storage
+   *   The user storage.
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger service.
    */
-  public function __construct(EntityStorageInterface $protection_rule_storage) {
+  public function __construct(
+    EntityStorageInterface $protection_rule_storage,
+    UserStorageInterface $user_storage,
+    MessengerInterface $messenger
+  ) {
     $this->protectionRuleStorage = $protection_rule_storage;
+    $this->userStorage = $user_storage;
+    $this->messenger = $messenger;
   }
 
   /**
@@ -35,7 +60,9 @@ public function __construct(EntityStorageInterface $protection_rule_storage) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager')->getStorage('userprotect_rule')
+      $container->get('entity_type.manager')->getStorage('userprotect_rule'),
+      $container->get('entity_type.manager')->getStorage('user'),
+      $container->get('messenger')
     );
   }
 
@@ -43,15 +70,15 @@ public static function create(ContainerInterface $container) {
    * Construct message for bypass permission.
    */
   protected function getBypassMessage($permission, $permission_label) {
-    $message = $this->t('Users with the permission "%permission".', array('%permission' => $permission_label));
+    $message = $this->t('Users with the permission "%permission".', ['%permission' => $permission_label]);
     $roles = user_role_names(FALSE, $permission);
     if (count($roles)) {
-      $message .= '<br /><div class="description">' . $this->t('Currently the following roles have this permission:  %roles.', array('%roles' => implode(', ', $roles))) . '</div>';
+      $message .= '<br /><div class="description">' . $this->t('Currently the following roles have this permission:  %roles.', ['%roles' => implode(', ', $roles)]) . '</div>';
     }
     else {
       $message .= '<br /><div class="description">' . $this->t('Currently no roles have this permission.') . '</div>';
     }
-    return array('#markup' => $message);
+    return ['#markup' => $message];
   }
 
   /**
@@ -61,31 +88,31 @@ public function form(array $form, FormStateInterface $form_state) {
     $protected_entity_type = $this->entity->getProtectedEntityTypeId();
 
     // Help text.
-    $items = array();
+    $items = [];
     // User 1.
-    $account = entity_load('user', 1);
+    $account = $this->userStorage->load(1);
     if (!empty($account)) {
-      $items[] = array(
-        '#markup' => $this->t('User @id (@name)', array(
+      $items[] = [
+        '#markup' => $this->t('User @id (@name)', [
           '@id' => $account->id(),
           '@name' => $account->label(),
-        )),
-      );
+        ]),
+      ];
     }
     // User in question (if protected entity type is "user").
     if ($protected_entity_type == 'user') {
       $account = $this->entity->getProtectedEntity();
       if (!empty($account)) {
-        $items[] = array(
-          '#markup' => $this->t('The protected user itself (@name)', array(
+        $items[] = [
+          '#markup' => $this->t('The protected user itself (@name)', [
             '@name' => $account->label(),
-          )),
-        );
+          ]),
+        ];
       }
       else {
-        $items[] = array(
+        $items[] = [
           '#markup' => $this->t('The protected user itself'),
-        );
+        ];
       }
     }
     // Bypass all protections.
@@ -95,97 +122,97 @@ public function form(array $form, FormStateInterface $form_state) {
     // Bypass this protection.
     $permission = $this->entity->getPermissionName();
     if ($permission && !$this->entity->isNew()) {
-      $permission_label = $this->t('Bypass user protection for @label', array('@label' => $this->entity->label()));
+      $permission_label = $this->t('Bypass user protection for @label', ['@label' => $this->entity->label()]);
       $items[] = $this->getBypassMessage($permission, $permission_label);
     }
     switch ($protected_entity_type) {
       case 'user':
-        $form['help'] = array(
+        $form['help'] = [
           '#markup' => $this->t('This user will be protected for all users except:'),
-        );
+        ];
         break;
 
       case 'user_role':
-        $form['help'] = array(
+        $form['help'] = [
           '#markup' => $this->t('This role will be protected for all users except:'),
-        );
+        ];
         break;
     }
 
-    $form['help']['list'] = array(
+    $form['help']['list'] = [
       '#theme' => 'item_list',
       '#items' => $items,
-    );
+    ];
 
-    $form['label'] = array(
+    $form['label'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Name'),
       '#default_value' => $this->entity->label(),
       '#required' => TRUE,
-    );
-    $form['name'] = array(
+    ];
+    $form['name'] = [
       '#type' => 'machine_name',
-      '#machine_name' => array(
-        'exists' => array($this->protectionRuleStorage, 'load'),
-      ),
+      '#machine_name' => [
+        'exists' => [$this->protectionRuleStorage, 'load'],
+      ],
       '#default_value' => $this->entity->id(),
       '#required' => TRUE,
-    );
+    ];
 
     switch ($protected_entity_type) {
       case 'user':
-        $form['entity_id'] = array(
+        $form['entity_id'] = [
           '#type' => 'entity_autocomplete',
           '#target_type' => 'user',
           '#title' => $this->t('User'),
           '#default_value' => $this->entity->getProtectedEntity(),
           '#required' => TRUE,
-        );
+        ];
         break;
 
       case 'user_role':
-        $entities = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names(TRUE));
-        $form['entity_id'] = array(
+        $entities = array_map('Drupal\Component\Utility\Html::escape', user_role_names(TRUE));
+        $form['entity_id'] = [
           '#type' => 'select',
           '#title' => $this->t('Role'),
           '#options' => $entities,
           '#default_value' => $this->entity->getProtectedEntityId(),
           '#required' => TRUE,
-        );
+        ];
         break;
     }
 
-    $protection_options = array();
-    $enabled_protections = array();
+    $protection_options = [];
+    $enabled_protections = [];
     foreach ($this->entity->getProtections()->getAll() as $name => $plugin) {
-      $protection_options[$name] = array(
-        'protection' => array(
-          'data' => array(
+      $protection_options[$name] = [
+        'protection' => [
+          'data' => [
             '#type' => 'item',
             '#markup' => $plugin->label(),
             '#description' => $plugin->description(),
-          ),
-        ),
-      );
+          ],
+        ],
+      ];
       if ($plugin->status) {
         $enabled_protections[$name] = TRUE;
       }
     }
-    $form['protection'] = array(
+    $form['protection'] = [
       '#type' => 'tableselect',
-      '#header' => array('protection' => $this->t('Protection')),
+      '#header' => ['protection' => $this->t('Protection')],
       '#options' => $protection_options,
       '#default_value' => $enabled_protections,
-    );
+    ];
 
-    $roles = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names());
-    $form['bypass_roles'] = array(
+    $roles = array_map('Drupal\Component\Utility\Html::escape', user_role_names());
+    $form['bypass_roles'] = [
       '#type' => 'checkboxes',
       '#title' => $this->t('Bypass for roles'),
       '#description' => $this->t('Note: this setting will be saved as user permissions.'),
       '#options' => $roles,
       '#default_value' => $this->entity->getBypassRoles(),
-    );
+    ];
 
     return parent::form($form, $form_state);
   }
@@ -211,7 +238,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     }
 
     // Set bypass roles.
-    $bypass_roles = array();
+    $bypass_roles = [];
     foreach ($form_state->getValue('bypass_roles') as $rid => $status) {
       if (!empty($status)) {
         $bypass_roles[] = $rid;
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Delete.php b/web/modules/userprotect/src/Plugin/UserProtection/Delete.php
index cbe0281338f6a3d2d3ade8b4edd496c957e2b95e..cae01a746a01ebd88543bebf34755f4f5e21eae5 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Delete.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Delete.php
@@ -15,6 +15,7 @@
  * )
  */
 class Delete extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -24,4 +25,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account)
     }
     return parent::isProtected($user, $op, $account);
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Edit.php b/web/modules/userprotect/src/Plugin/UserProtection/Edit.php
index 1a7995ff5689fb88138cce48fab0e75b6002ffcd..1856d95ad4b3ce70d00b62b8fa654bd799a20a80 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Edit.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Edit.php
@@ -15,6 +15,7 @@
  * )
  */
 class Edit extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -24,4 +25,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account)
     }
     return parent::isProtected($user, $op, $account);
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Mail.php b/web/modules/userprotect/src/Plugin/UserProtection/Mail.php
index 93202050f3e89d93fbe5f609bbde7effae9ad760..837346ead9aa5250013bd133f45089c52e210911 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Mail.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Mail.php
@@ -14,6 +14,7 @@
  * )
  */
 class Mail extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -28,4 +29,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for
     }
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Password.php b/web/modules/userprotect/src/Plugin/UserProtection/Password.php
index af07ec80776a4165d8130b3c4d1877920f9764ba..ad9eefddcb6a4f007a538912e9915775ba82d34e 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Password.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Password.php
@@ -14,6 +14,7 @@
  * )
  */
 class Password extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -43,4 +44,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for
 
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Roles.php b/web/modules/userprotect/src/Plugin/UserProtection/Roles.php
index 6056b13e53e652f713a203db52b5cc21572af5f0..240bed85faae9d21ac6b387a7fd8142bb561d537 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Roles.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Roles.php
@@ -14,14 +14,24 @@
  * )
  */
 class Roles extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
   public function applyAccountFormProtection(array &$form, FormStateInterface $form_state) {
+    // Make sure this module also works when role_delegation is enabled.
+    $applied = FALSE;
+    if (isset($form['role_change']['widget'])) {
+      $form['role_change']['widget']['#disabled'] = TRUE;
+      $applied = TRUE;
+    }
+
     if (isset($form['account']['roles'])) {
       $form['account']['roles']['#disabled'] = TRUE;
-      return TRUE;
+      $applied = TRUE;
     }
-    return FALSE;
+
+    return $applied;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Status.php b/web/modules/userprotect/src/Plugin/UserProtection/Status.php
index bcd7e5f9a2e4030713d7fed79fc9e7774806bb74..874d45cdadb185db0371e288b7dc4d60571d08f0 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Status.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Status.php
@@ -14,6 +14,7 @@
  * )
  */
 class Status extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -27,4 +28,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for
     }
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php
index 48c1d64b9b3cd98dbb2d0faee436ccc339ef4582..ddc1f7276504e58af14c4a756c27ef92662c59e9 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php
@@ -60,11 +60,11 @@ public function getWeight() {
    * {@inheritdoc}
    */
   public function getConfiguration() {
-    return array(
+    return [
       'id' => $this->getPluginId(),
       'provider' => $this->pluginDefinition['provider'],
       'status' => $this->status,
-    );
+    ];
   }
 
   /**
@@ -81,14 +81,14 @@ public function setConfiguration(array $configuration) {
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return array();
+    return [];
   }
 
   /**
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    return array();
+    return [];
   }
 
   /**
@@ -115,4 +115,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account)
   public function applyAccountFormProtection(array &$form, FormStateInterface $form_state) {
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php
index 753901cd0a78981f01943339e776847bf3450731..8fa2e0992b577a391a458e11b3cff021778db69b 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php
@@ -3,7 +3,8 @@
 namespace Drupal\userprotect\Plugin\UserProtection;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\DependentPluginInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\UserInterface;
@@ -11,7 +12,8 @@
 /**
  * Defines the interface for user protection plugins.
  */
-interface UserProtectionInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
+interface UserProtectionInterface extends PluginInspectionInterface, ConfigurableInterface, DependentPluginInterface {
+
   /**
    * Returns the user protection label.
    *
@@ -66,12 +68,13 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account)
    *
    * @param array $form
    *   Nested array of form elements that comprise the form.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return bool
    *   TRUE if the protection was applied.
    *   FALSE otherwise.
    */
   public function applyAccountFormProtection(array &$form, FormStateInterface $form_state);
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php
index f4ddcfec0310ff740faf8eb28a7149d7c36bfde4..28fc150ac78390e3624ef07ad16052a890cb8562 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php
@@ -17,16 +17,6 @@ class UserProtectionPluginCollection extends DefaultLazyPluginCollection {
    */
   protected $definitions;
 
-  /**
-   * {@inheritdoc}
-   *
-   * @return \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface
-   *   An instance of UserProtectionInterface.
-   */
-  public function &get($instance_id) {
-    return parent::get($instance_id);
-  }
-
   /**
    * Retrieves all user protection plugin instances.
    *
@@ -47,7 +37,7 @@ public function getAll() {
     }
 
     // Sort plugins.
-    uasort($this->pluginInstances, array($this, 'pluginInstancesSort'));
+    uasort($this->pluginInstances, [$this, 'pluginInstancesSort']);
 
     return $this->pluginInstances;
   }
@@ -60,7 +50,7 @@ public function getAll() {
    */
   public function getEnabledPlugins() {
     $instances = $this->getAll();
-    $enabled = array();
+    $enabled = [];
     foreach ($this->configurations as $instance_id => $configuration) {
       if ($configuration['status']) {
         $enabled[] = $instances[$instance_id];
@@ -68,7 +58,7 @@ public function getEnabledPlugins() {
     }
 
     // Sort plugins.
-    uasort($enabled, array($this, 'pluginInstancesSort'));
+    uasort($enabled, [$this, 'pluginInstancesSort']);
 
     return $enabled;
   }
@@ -89,9 +79,9 @@ protected function initializePlugin($instance_id) {
   /**
    * Sorts plugin instances based on weight, label, provider or id.
    *
-   * @param Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $a
+   * @param \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $a
    *   The first plugin in the comparison.
-   * @param Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $b
+   * @param \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $b
    *   The second plugin in the comparison.
    *
    * @return int
@@ -99,7 +89,7 @@ protected function initializePlugin($instance_id) {
    *   1 if $b should go first.
    *   0 if it's unknown which should go first.
    */
-  public function pluginInstancesSort($a, $b) {
+  public function pluginInstancesSort(UserProtectionInterface $a, UserProtectionInterface $b) {
     if ($a->getWeight() != $b->getWeight()) {
       return $a->getWeight() < $b->getWeight() ? -1 : 1;
     }
@@ -125,4 +115,5 @@ public function getConfiguration() {
     }
     return $configuration;
   }
+
 }
diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Username.php b/web/modules/userprotect/src/Plugin/UserProtection/Username.php
index 8e2cfd18cd0836ded7be989a8a08464ee4737795..371fd0d1c86b185bff00cdd39bb721fa9289bf0d 100644
--- a/web/modules/userprotect/src/Plugin/UserProtection/Username.php
+++ b/web/modules/userprotect/src/Plugin/UserProtection/Username.php
@@ -14,6 +14,7 @@
  * )
  */
 class Username extends UserProtectionBase {
+
   /**
    * {@inheritdoc}
    */
@@ -21,11 +22,12 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for
     $build_info = $form_state->getBuildInfo();
     $account = $build_info['callback_object']->getEntity();
     // If for some reason the account has no username, then don't protect it.
-    if ($account->getUsername() && isset($form['account']['name'])) {
+    if ($account->getAccountName() && isset($form['account']['name'])) {
       $form['account']['name']['#disabled'] = TRUE;
-      $form['account']['name']['#value'] = $account->getUsername();
+      $form['account']['name']['#value'] = $account->getAccountName();
       return TRUE;
     }
     return FALSE;
   }
+
 }
diff --git a/web/modules/userprotect/src/Routing/RouteSubscriber.php b/web/modules/userprotect/src/Routing/RouteSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d68e36c06eb1b89a0015c16b9153d2425cf5fd2
--- /dev/null
+++ b/web/modules/userprotect/src/Routing/RouteSubscriber.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\userprotect\Routing;
+
+use Drupal\Core\Routing\RouteSubscriberBase;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Class RouteSubscriber.
+ *
+ * @package Drupal\userprotect\Routing
+ */
+class RouteSubscriber extends RouteSubscriberBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function alterRoutes(RouteCollection $collection) {
+    if ($route = $collection->get('role_delegation.edit_form')) {
+      $route->setRequirement('_userprotect_role_access_check', 'TRUE');
+    }
+  }
+
+}
diff --git a/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php b/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php
deleted file mode 100644
index 66932976fc5cf581cfa500c85adfe02d53076edc..0000000000000000000000000000000000000000
--- a/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-namespace Drupal\userprotect\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests module installation and uninstallation.
- *
- * @group userprotect
- */
-class ModuleInstallUninstallWebTest extends WebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
-
-  /**
-   * Test installation and uninstallation.
-   */
-  protected function testInstallationAndUninstallation() {
-    /** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
-    $module_installer = \Drupal::service('module_installer');
-    $module_handler = \Drupal::moduleHandler();
-    $this->assertTrue($module_handler->moduleExists('userprotect'));
-
-    // Test default configuration.
-    $account = $this->drupalCreateUser();
-    $this->assertTrue($account->hasPermission('userprotect.mail.edit'), 'Authenticated user can edit own mail address.');
-    $this->assertTrue($account->hasPermission('userprotect.pass.edit'), 'Authenticated user can edit own password.');
-    $this->assertTrue($account->hasPermission('userprotect.account.edit'), 'Authenticated user can edit own account.');
-
-    // Ensure an authenticated user can edit its own account.
-    $this->drupalLogin($account);
-    $this->drupalGet('user/' . $account->id() . '/edit');
-    $this->assertResponse(200, 'Authenticated user has access to edit page of own account.');
-
-    $module_installer->uninstall(array('userprotect'));
-    $this->assertFalse($module_handler->moduleExists('userprotect'));
-  }
-}
diff --git a/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php b/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php
deleted file mode 100644
index ee81d7e863eb9eeb8df8f9e549e31e0d9fb6cec4..0000000000000000000000000000000000000000
--- a/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-namespace Drupal\userprotect\Tests;
-
-/**
- * Tests if protection rules are cleaned up upon entity deletion.
- *
- * @group userprotect
- */
-class ProtectedEntityDeleteTest extends UserProtectWebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
-
-  /**
-   * Tests reaction upon user deletion.
-   *
-   * Tests if an user based protection rule is cleaned up when the protected
-   * user is deleted.
-   */
-  protected function testUserDelete() {
-    // Create a user.
-    $account = $this->drupalCreateUser();
-
-    // Protect this user.
-    $protection_rule = $this->createProtectionRule($account->id(), array(), 'user');
-    $protection_rule->save();
-
-    // Assert that the rule was saved.
-    $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE);
-    $this->assertNotNull($protection_rule, 'The protection rule was saved.');
-
-    // Now delete the account.
-    $account->delete();
-
-    // Assert that the rule no longer exists.
-    $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE);
-    $this->assertNull($protection_rule, 'The protection rule was deleted.');
-  }
-
-  /**
-   * Tests reaction upon role deletion.
-   *
-   * Tests if a role based protection rule is cleaned up when the protected
-   * role is deleted.
-   */
-  protected function testRoleDelete() {
-    // Create a role.
-    $rid = $this->drupalCreateRole(array());
-
-    // Protect this role.
-    $protection_rule = $this->createProtectionRule($rid, array(), 'user_role');
-    $protection_rule->save();
-
-    // Assert that the rule was saved.
-    $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE);
-    $this->assertNotNull($protection_rule, 'The protection rule was saved.');
-
-    // Now delete the role.
-    $role = entity_load('user_role', $rid);
-    $role->delete();
-
-    // Assert that the rule no longer exists.
-    $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE);
-    $this->assertNull($protection_rule, 'The protection rule was deleted.');
-  }
-
-  /**
-   * Tests UI for non-existent protected users.
-   *
-   * Tests if there are no PHP errors in the UI when a protection rule for a
-   * non-existent user still exists.
-   */
-  protected function testNonExistentProtectedUser() {
-    // Create a protection rule for a non-existent user.
-    $fake_uid = 10;
-    $protection_rule = $this->createProtectionRule($fake_uid, array(), 'user');
-    $protection_rule->save();
-
-    // Check user interface.
-    $account = $this->drupalCreateUser(array('userprotect.administer'));
-    $this->drupalLogin($account);
-    $this->drupalGet('admin/config/people/userprotect');
-    $this->assertText(t('Missing'));
-  }
-
-  /**
-   * Tests UI for non-existent protected roles.
-   *
-   * Tests if there are no PHP errors in the UI when a protection rule for a
-   * non-existent role still exists.
-   */
-  protected function testNonExistentProtectedRole() {
-    // Create a protection rule for a non-existent user.
-    $protection_rule = $this->createProtectionRule('non-existent role', array(), 'user_role');
-    $protection_rule->save();
-
-    // Check user interface.
-    $account = $this->drupalCreateUser(array('userprotect.administer'));
-    $this->drupalLogin($account);
-    $this->drupalGet('admin/config/people/userprotect');
-    $this->assertText(t('Missing'));
-  }
-}
diff --git a/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php b/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php
deleted file mode 100644
index b828ee417010b574500957cf18a0884a7900a466..0000000000000000000000000000000000000000
--- a/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php
+++ /dev/null
@@ -1,185 +0,0 @@
-<?php
-
-namespace Drupal\userprotect\Tests;
-
-use Drupal\userprotect\Entity\ProtectionRuleInterface;
-
-/**
- * Tests creating, editing and deleting protection rules through the UI.
- *
- * @group userprotect
- */
-class ProtectionRuleCrudWebTest extends UserProtectWebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
-
-  /**
-   * The operating account.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $account;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->account = $this->drupalCreateUser(array('userprotect.administer'));
-    $this->drupalLogin($this->account);
-  }
-
-  /**
-   * Tests if role based protection rules can be created through the UI.
-   */
-  protected function testCrudRoleProtectionRule() {
-    $rid = $this->drupalCreateRole(array());
-    $rule_id = strtolower($this->randomMachineName());
-    $label = $this->randomMachineName();
-
-    // Create rule.
-    $edit = array(
-      'label' => $label,
-      'name' => $rule_id,
-      'entity_id' => $rid,
-      'protection[user_mail]' => TRUE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save'));
-
-    // Assert that the rule was created.
-    $protection_rule = entity_load('userprotect_rule', $rule_id);
-    $this->assertTrue(($protection_rule instanceof ProtectionRuleInterface), 'A protection rule was created through the UI.');
-
-    // Stop the test if rule is not an instance of ProtectionRuleInterface.
-    if (!($protection_rule instanceof ProtectionRuleInterface)) {
-      return;
-    }
-
-    // Assert that the rule has the expected values.
-    $this->assertEqual($rule_id, $protection_rule->id());
-    $this->assertEqual($label, $protection_rule->label);
-    $this->assertEqual('user_role', $protection_rule->getProtectedEntityTypeId());
-    $this->assertEqual($rid, $protection_rule->getProtectedEntityId());
-    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
-    $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.');
-    $plugin = reset($enabled_plugins);
-    $this->assertEqual('user_mail', $plugin->getPluginId());
-
-    // Edit rule.
-    $edit = array(
-      'protection[user_name]' => TRUE,
-      'protection[user_mail]' => FALSE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save'));
-
-    // Assert that the rule was updated with the expected values.
-    $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE);
-    $this->assertEqual($rule_id, $protection_rule->id());
-    $this->assertEqual($label, $protection_rule->label);
-    $this->assertEqual('user_role', $protection_rule->getProtectedEntityTypeId());
-    $this->assertEqual($rid, $protection_rule->getProtectedEntityId());
-    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
-    $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.');
-    $plugin = reset($enabled_plugins);
-    $this->assertEqual('user_name', $plugin->getPluginId());
-
-    // Attempt to create a rule with the same name.
-    $edit = array(
-      'label' => $label,
-      'name' => $rule_id,
-      'entity_id' => $rid,
-      'protection[user_mail]' => TRUE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save'));
-    $this->assertText('The machine-readable name is already in use. It must be unique.');
-
-    // Assert only one protection rule exists.
-    $entities = entity_load_multiple('userprotect_rule', NULL, TRUE);
-    $this->assertEqual(1, count($entities), 'Only one protection rule exists.');
-
-    // Delete rule.
-    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', array(), t('Delete'));
-    // Assert the rule no longer exists.
-    $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE);
-    $this->assertFalse($protection_rule, 'The protection rule was deleted.');
-  }
-
-  /**
-   * Tests if user based protection rules can be created through the UI.
-   */
-  protected function testCrudUserProtectionRule() {
-    $account = $this->drupalCreateUser();
-    $rule_id = strtolower($this->randomMachineName());
-    $label = $this->randomMachineName();
-
-    // Create rule.
-    $edit = array(
-      'label' => $label,
-      'name' => $rule_id,
-      'entity_id' => $account->getUsername(),
-      'protection[user_mail]' => TRUE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save'));
-
-    // Assert that the rule was created.
-    $protection_rule = entity_load('userprotect_rule', $rule_id);
-    $this->assertTrue(($protection_rule instanceof ProtectionRuleInterface), 'A protection rule was created through the UI.');
-
-    // Stop the test if rule is not an instance of ProtectionRuleInterface.
-    if (!($protection_rule instanceof ProtectionRuleInterface)) {
-      return;
-    }
-
-    // Assert that the rule has the expected values.
-    $this->assertEqual($rule_id, $protection_rule->id());
-    $this->assertEqual($label, $protection_rule->label);
-    $this->assertEqual('user', $protection_rule->getProtectedEntityTypeId());
-    $this->assertEqual($account->id(), $protection_rule->getProtectedEntityId());
-    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
-    $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.');
-    $plugin = reset($enabled_plugins);
-    $this->assertEqual('user_mail', $plugin->getPluginId());
-
-    // Edit rule.
-    $edit = array(
-      'protection[user_name]' => TRUE,
-      'protection[user_mail]' => FALSE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save'));
-
-    // Assert that the rule was updated with the expected values.
-    $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE);
-    $this->assertEqual($rule_id, $protection_rule->id());
-    $this->assertEqual($label, $protection_rule->label);
-    $this->assertEqual('user', $protection_rule->getProtectedEntityTypeId());
-    $this->assertEqual($account->id(), $protection_rule->getProtectedEntityId());
-    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
-    $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.');
-    $plugin = reset($enabled_plugins);
-    $this->assertEqual('user_name', $plugin->getPluginId());
-
-    // Attempt to create a rule with the same name.
-    $edit = array(
-      'label' => $label,
-      'name' => $rule_id,
-      'entity_id' => $account->getUsername(),
-      'protection[user_mail]' => TRUE,
-    );
-    $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save'));
-    $this->assertText('The machine-readable name is already in use. It must be unique.');
-
-    // Assert only one protection rule exists.
-    $entities = entity_load_multiple('userprotect_rule', NULL, TRUE);
-    $this->assertEqual(1, count($entities), 'Only one protection rule exists.');
-
-    // Delete rule.
-    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', array(), t('Delete'));
-    // Assert the rule no longer exists.
-    $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE);
-    $this->assertFalse($protection_rule, 'The protection rule was deleted.');
-  }
-}
diff --git a/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php b/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php
deleted file mode 100644
index f7a163bf4246fee552a7646f22f4b365ae879a6a..0000000000000000000000000000000000000000
--- a/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php
+++ /dev/null
@@ -1,190 +0,0 @@
-<?php
-
-namespace Drupal\userprotect\Tests;
-
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\userprotect\Entity\ProtectionRuleInterface;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Base class for User protect web tests.
- */
-abstract class UserProtectWebTestBase extends WebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
-
-  /**
-   * Creates a protected role.
-   *
-   * @param array $protections
-   *   (optional) The active protections.
-   *   Defaults to an empty array.
-   *
-   * @return string
-   *   The ID of the created role.
-   */
-  protected function createProtectedRole(array $protections = array()) {
-    // Create a role.
-    $rid = $this->drupalCreateRole(array());
-
-    // Protect this role.
-    $protection_rule = $this->createProtectionRule($rid, $protections);
-    $protection_rule->save();
-    // Reset available permissions.
-    drupal_static_reset('checkPermissions');
-
-    return $rid;
-  }
-
-  /**
-   * Creates a protected user.
-   *
-   * @param array $protections
-   *   (optional) The active protections.
-   *   Defaults to an empty array.
-   *
-   * @return object
-   *   The created user.
-   */
-  protected function createProtectedUser(array $protections = array()) {
-    // Create a user.
-    $account = $this->drupalCreateUser();
-
-    // Protect this user.
-    $protection_rule = $this->createProtectionRule($account->id(), $protections, 'user');
-    $protection_rule->save();
-    // Reset available permissions.
-    drupal_static_reset('checkPermissions');
-
-    return $account;
-  }
-
-  /**
-   * Creates an user with a protected role.
-   *
-   * @param array $protections
-   *   (optional) The active protections.
-   *   Defaults to an empty array.
-   *
-   * @return object
-   *   The created user.
-   */
-  protected function createUserWithProtectedRole(array $protections = array()) {
-    // Create a protected role.
-    $rid = $this->createProtectedRole($protections);
-
-    // Create an account with this protected role.
-    $protected_account = $this->drupalCreateUser();
-    $protected_account->addRole($rid);
-    $protected_account->save();
-
-    return $protected_account;
-  }
-
-  /**
-   * Creates protection rule.
-   *
-   * @param int|string $entity_id
-   *   The id of the entity to protect.
-   * @param array $protections
-   *   (optional) The active protections.
-   *   Defaults to an empty array.
-   * @param string $entity_type
-   *   (optional) The protected entity type.
-   *   Defaults to "user_role".
-   * @param array $values
-   *   (optional) Extra values of the protection rule.
-   *
-   * @return \Drupal\userprotect\Entity\ProtectionRuleInterface
-   *   An instance of ProtectionRuleInterface.
-   */
-  protected function createProtectionRule($entity_id, array $protections = array(), $entity_type = 'user_role', array $values = array()) {
-    // Setup default values.
-    $values += array(
-      'name' => 'dummy',
-      'label' => 'Dummy',
-      'protections' => array(),
-      'protectedEntityTypeId' => $entity_type,
-      'protectedEntityId' => $entity_id,
-    );
-    // Define protections.
-    foreach ($protections as $key) {
-      $values['protections'][$key] = array(
-        'status' => TRUE,
-      );
-    }
-
-    // Create protection rule.
-    $protection_rule = entity_create('userprotect_rule', $values);
-    $this->assertTrue($protection_rule instanceof ProtectionRuleInterface, SafeMarkup::format('Created protection rule %rule.', array('%rule' => $protection_rule->id())));
-    return $protection_rule;
-  }
-
-  /**
-   * Executes a form submission, but does not require all fields to be present.
-   *
-   * @param NULL|string $path
-   *   Location of the post form.
-   * @param array $edit
-   *   Field data in an associative array.
-   * @param string $submit
-   *   Value of the submit button whose click is to be emulated.
-   * @param array $options
-   *   (optional) Options to be forwarded to the url generator.
-   * @param array $headers
-   *   (optional) An array containing additional HTTP request headers.
-   * @param string $form_html_id
-   *   (optional) HTML ID of the form to be submitted.
-   *
-   * @return NULL|string
-   *   Result of CURL in case form could be posted.
-   *   NULL otherwise.
-   */
-  protected function userprotectPostForm($path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL) {
-    if (isset($path)) {
-      $this->drupalGet($path, $options);
-    }
-    if ($this->parse()) {
-      $edit_save = $edit;
-      // Let's iterate over all the forms.
-      $xpath = "//form";
-      if (!empty($form_html_id)) {
-        $xpath .= "[@id='" . $form_html_id . "']";
-      }
-      $forms = $this->xpath($xpath);
-      foreach ($forms as $form) {
-        // We try to set the fields of this form as specified in $edit.
-        $edit = $edit_save;
-        $post = array();
-        $upload = array();
-        $submit_matches = $this->handleForm($post, $edit, $upload, $submit, $form);
-        $action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl();
-
-        if ($submit_matches) {
-          $post = array_merge($post, $edit);
-          $out = $this->curlExec(array(
-            CURLOPT_URL => $action,
-            CURLOPT_POST => TRUE,
-            CURLOPT_POSTFIELDS => $post,
-            CURLOPT_HTTPHEADER => $headers,
-          ));
-
-          $verbose = 'POST request to: ' . $path;
-          $verbose .= '<hr />Ending URL: ' . $this->getUrl();
-          if ($this->dumpHeaders) {
-            $verbose .= '<hr />Headers: <pre>' . SafeMarkup::checkPlain(var_export(array_map('trim', $this->headers), TRUE)) . '</pre>';
-          }
-          $verbose .= '<hr />Fields: ' . highlight_string('<?php ' . var_export($post, TRUE), TRUE);
-          $verbose .= '<hr />' . $out;
-
-          $this->verbose($verbose);
-          return $out;
-        }
-      }
-      $this->fail(SafeMarkup::format('Found the requested form fields at @path', array('@path' => $path)));
-    }
-  }
-}
diff --git a/web/modules/userprotect/src/Tests/UserProtectionWebTest.php b/web/modules/userprotect/src/Tests/UserProtectionWebTest.php
deleted file mode 100644
index 14de81fea8e3807440f11351c3f723f89b53662d..0000000000000000000000000000000000000000
--- a/web/modules/userprotect/src/Tests/UserProtectionWebTest.php
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-
-namespace Drupal\userprotect\Tests;
-
-/**
- * Tests each UserProtection plugin in action.
- *
- * @group userprotect
- * @todo Assert protection messages.
- */
-class UserProtectionWebTest extends UserProtectWebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
-
-  /**
-   * The operating account.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $account;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->account = $this->drupalCreateUser(array('administer users', 'administer permissions'));
-    $this->drupalLogin($this->account);
-  }
-
-  /**
-   * Tests if the user's name field has the expected protection.
-   */
-  protected function testNameProtection() {
-    $protected_account = $this->createProtectedUser(array('user_name'));
-
-    // Remember the user's name.
-    $expected_name = $protected_account->getUsername();
-
-    $edit = array(
-      'name' => $this->randomMachineName(),
-    );
-    $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save'));
-
-    // Re-load the user and check the user name didn't change.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    $this->assertEqual($expected_name, $protected_account->getUsername());
-  }
-
-  /**
-   * Tests if the user's mail address field has the expected protection.
-   */
-  protected function testMailProtection() {
-    $protected_account = $this->createProtectedUser(array('user_mail'));
-
-    // Remember the user's mail address.
-    $expected_mail = $protected_account->getEmail();
-
-    $edit = array(
-      'mail' => $this->randomMachineName() . '@example.com',
-    );
-    $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save'));
-
-    // Re-load the user and check the user mail address didn't change.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    $this->assertEqual($expected_mail, $protected_account->getEmail());
-  }
-
-  /**
-   * Tests if the user's password field has the expected protection.
-   */
-  protected function testPassProtection() {
-    $protected_account = $this->createProtectedUser(array('user_pass'));
-
-    // Remember the user's pass.
-    $expected_pass = $protected_account->pass_raw;
-
-    $new_pass = $this->randomMachineName();
-    $edit = array(
-      'pass[pass1]' => $new_pass,
-      'pass[pass2]' => $new_pass,
-    );
-    $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save'));
-
-    // Try to login as this user with the expected password.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    $protected_account->pass_raw = $expected_pass;
-    $this->drupalLogout();
-    $this->drupalLogin($protected_account);
-  }
-
-  /**
-   * Tests if the user's status field has the expected protection.
-   */
-  protected function testStatusProtection() {
-    $protected_account = $this->createProtectedUser(array('user_status'));
-
-    // Try to deactivate user's status.
-    $edit = array(
-      'status' => '0',
-    );
-    $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save'));
-
-    // Re-load the user and check the user is still active.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    $this->assertTrue($protected_account->isActive());
-  }
-
-  /**
-   * Tests if the user's roles field has the expected protection.
-   */
-  protected function testRolesProtection() {
-    $protected_account = $this->createProtectedUser(array('user_roles'));
-
-    // Add a role to the protected account.
-    $rid1 = $this->drupalCreateRole(array());
-    $protected_account->addRole($rid1);
-    $protected_account->save();
-
-    // Add another role. We try to add this role to the user form later.
-    $rid2 = $this->drupalCreateRole(array());
-
-    // Re-load the user and check its roles.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    // Assert the protected account's roles.
-    $this->assertTrue($protected_account->hasRole($rid1));
-    $this->assertFalse($protected_account->hasRole($rid2));
-
-    // Try to add the second role to this user.
-    $edit = array(
-      'roles[' . $rid2 . ']' => $rid2,
-    );
-    $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save'));
-
-    // Re-load the user and assert the roles it has are still the same.
-    $protected_account = entity_load('user', $protected_account->id(), TRUE);
-    $this->assertTrue($protected_account->hasRole($rid1));
-    $this->assertFalse($protected_account->hasRole($rid2));
-  }
-}
diff --git a/web/modules/userprotect/src/UserProtectPermissions.php b/web/modules/userprotect/src/UserProtectPermissions.php
index d3d535357c30d8f0abd0794300ff80248a0b8a8a..f4961de38f2d4d3bfa53147c995a92188f1d8e19 100644
--- a/web/modules/userprotect/src/UserProtectPermissions.php
+++ b/web/modules/userprotect/src/UserProtectPermissions.php
@@ -3,12 +3,12 @@
 namespace Drupal\userprotect;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Provides dynamic permissions of the filter module.
+ * Provides dynamic permissions for bypassing user protect rules.
  */
 class UserProtectPermissions implements ContainerInjectionInterface {
 
@@ -17,25 +17,25 @@ class UserProtectPermissions implements ContainerInjectionInterface {
   /**
    * The entity manager.
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
-  protected $entityManager;
+  protected $entityTypeManager;
 
   /**
    * Constructs a new UserProtectPermissions instance.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
-    $this->entityManager = $entity_manager;
+  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
-    return new static($container->get('entity.manager'));
+    return new static($container->get('entity_type.manager'));
   }
 
   /**
@@ -48,7 +48,7 @@ public function permissions() {
     $permissions = [];
     // For each protection rule, create a permission to bypass the rule.
     /** @var \Drupal\userprotect\Entity\ProtectionRuleInterface[] $rules */
-    $rules = $this->entityManager->getStorage('userprotect_rule')->loadMultiple();
+    $rules = $this->entityTypeManager->getStorage('userprotect_rule')->loadMultiple();
     uasort($rules, 'Drupal\Core\Config\Entity\ConfigEntityBase::sort');
     foreach ($rules as $rule) {
       $vars = [
diff --git a/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b5b1ca38b4003c00f848b7d6d511232321cfb310
--- /dev/null
+++ b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml
@@ -0,0 +1,13 @@
+name: User protect test
+type: module
+description: 'Support module for the User protect tests.'
+package: Testing
+core: 8.x
+core_version_requirement: ^8 || ^9
+dependencies:
+  - userprotect
+
+# Information added by Drupal.org packaging script on 2020-01-06
+version: '8.x-1.1'
+project: 'userprotect'
+datestamp: 1578341587
diff --git a/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..05361f64c234379fd016e02ae9790d685d2131f9
--- /dev/null
+++ b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Support module for the User protect tests.
+ */
+
+/**
+ * Implements hook_user_format_name_alter().
+ *
+ * Alters the display name of an user to test when the user's display name must
+ * be used and when the raw account name.
+ */
+function userprotect_test_user_format_name_alter(&$name, $account) {
+  $name .= '-userprotect';
+}
diff --git a/web/modules/userprotect/tests/src/Functional/InstallTest.php b/web/modules/userprotect/tests/src/Functional/InstallTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2e19d1ee5a62f72e7759aac45e742c1d7b253d5
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/InstallTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests module installation and uninstallation.
+ *
+ * @group userprotect
+ */
+class InstallTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [];
+
+  /**
+   * Module handler to ensure installed modules.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Module installer.
+   *
+   * @var \Drupal\Core\Extension\ModuleInstallerInterface
+   */
+  protected $moduleInstaller;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->moduleHandler = $this->container->get('module_handler');
+    $this->moduleInstaller = $this->container->get('module_installer');
+  }
+
+  /**
+   * Test installation and uninstallation.
+   */
+  public function testInstallationAndUninstallation() {
+    // Install userprotect.
+    $this->assertFalse($this->moduleHandler->moduleExists('userprotect'));
+    $this->assertTrue($this->moduleInstaller->install(['userprotect']));
+    $this->assertTrue($this->moduleHandler->moduleExists('userprotect'));
+
+    // Test default configuration.
+    $account = $this->drupalCreateUser();
+    $this->assertTrue($account->hasPermission('userprotect.mail.edit'), 'Authenticated user can edit own mail address.');
+    $this->assertTrue($account->hasPermission('userprotect.pass.edit'), 'Authenticated user can edit own password.');
+    $this->assertTrue($account->hasPermission('userprotect.account.edit'), 'Authenticated user can edit own account.');
+
+    // Ensure an authenticated user can edit its own account.
+    $this->drupalLogin($account);
+    $this->drupalGet('user/' . $account->id() . '/edit');
+    $this->assertResponse(200, 'Authenticated user has access to edit page of own account.');
+
+    // Uninstall userprotect.
+    $this->moduleInstaller->uninstall(['userprotect']);
+
+    // Workaround https://www.drupal.org/node/2021959
+    // See \Drupal\Core\Test\FunctionalTestSetupTrait::rebuildContainer.
+    unset($this->moduleHandler);
+    $this->rebuildContainer();
+    $this->moduleHandler = $this->container->get('module_handler');
+
+    // Assert that userprotect is uninstalled.
+    $this->assertFalse($this->moduleHandler->moduleExists('userprotect'));
+  }
+
+}
diff --git a/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php b/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..58e77f7f55f4f707710af5c49bb4c3d911dcd36d
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional;
+
+/**
+ * Tests if protection rules are cleaned up upon entity deletion.
+ *
+ * @group userprotect
+ */
+class ProtectedEntityDeleteTest extends UserProtectBrowserTestBase {
+
+  /**
+   * Tests UI for non-existent protected users.
+   *
+   * Tests if there are no PHP errors in the UI when a protection rule for a
+   * non-existent user still exists.
+   */
+  public function testNonExistentProtectedUser() {
+    // Create a protection rule for a non-existent user.
+    $fake_uid = 10;
+    $protection_rule = $this->createProtectionRule($fake_uid, [], 'user');
+    $protection_rule->save();
+
+    // Check user interface.
+    $account = $this->drupalCreateUser(['userprotect.administer']);
+    $this->drupalLogin($account);
+    $this->drupalGet('admin/config/people/userprotect');
+    $this->assertSession()->pageTextContains('Missing');
+  }
+
+  /**
+   * Tests UI for non-existent protected roles.
+   *
+   * Tests if there are no PHP errors in the UI when a protection rule for a
+   * non-existent role still exists.
+   */
+  public function testNonExistentProtectedRole() {
+    // Create a protection rule for a non-existent user.
+    $protection_rule = $this->createProtectionRule('non-existent role', [], 'user_role');
+    $protection_rule->save();
+
+    // Check user interface.
+    $account = $this->drupalCreateUser(['userprotect.administer']);
+    $this->drupalLogin($account);
+    $this->drupalGet('admin/config/people/userprotect');
+    $this->assertSession()->pageTextContains('Missing');
+  }
+
+}
diff --git a/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php b/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..40a2309e005e135444b81e117c445eb959f7b096
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php
@@ -0,0 +1,172 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional;
+
+use Drupal\userprotect\Entity\ProtectionRule;
+use Drupal\userprotect\Entity\ProtectionRuleInterface;
+
+/**
+ * Tests creating, editing and deleting protection rules through the UI.
+ *
+ * @group userprotect
+ */
+class ProtectionRuleCrudTest extends UserProtectBrowserTestBase {
+
+  /**
+   * The operating account.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $account;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->account = $this->drupalCreateUser(['userprotect.administer']);
+    $this->drupalLogin($this->account);
+  }
+
+  /**
+   * Tests if role based protection rules can be created through the UI.
+   */
+  public function testCrudRoleProtectionRule() {
+    $rid = $this->drupalCreateRole([]);
+    $rule_id = strtolower($this->randomMachineName());
+    $label = $this->randomMachineName();
+
+    // Create rule.
+    $edit = [
+      'label' => $label,
+      'name' => $rule_id,
+      'entity_id' => $rid,
+      'protection[user_mail]' => TRUE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save'));
+
+    // Assert that the rule was created.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule, 'A protection rule was created through the UI.');
+
+    // Assert that the rule has the expected values.
+    $this->assertEquals($rule_id, $protection_rule->id());
+    $this->assertEquals($label, $protection_rule->label);
+    $this->assertEquals('user_role', $protection_rule->getProtectedEntityTypeId());
+    $this->assertEquals($rid, $protection_rule->getProtectedEntityId());
+    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
+    $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.');
+    $plugin = reset($enabled_plugins);
+    $this->assertEquals('user_mail', $plugin->getPluginId());
+
+    // Edit rule.
+    $edit = [
+      'protection[user_name]' => TRUE,
+      'protection[user_mail]' => FALSE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save'));
+
+    // Assert that the rule was updated with the expected values.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertEquals($rule_id, $protection_rule->id());
+    $this->assertEquals($label, $protection_rule->label);
+    $this->assertEquals('user_role', $protection_rule->getProtectedEntityTypeId());
+    $this->assertEquals($rid, $protection_rule->getProtectedEntityId());
+    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
+    $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.');
+    $plugin = reset($enabled_plugins);
+    $this->assertEquals('user_name', $plugin->getPluginId());
+
+    // Attempt to create a rule with the same name.
+    $edit = [
+      'label' => $label,
+      'name' => $rule_id,
+      'entity_id' => $rid,
+      'protection[user_mail]' => TRUE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save'));
+    $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.');
+
+    // Assert only one protection rule exists.
+    $entities = ProtectionRule::loadMultiple(NULL);
+    $this->assertCount(1, $entities, 'Only one protection rule exists.');
+
+    // Delete rule.
+    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', [], t('Delete'));
+    // Assert the rule no longer exists.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertEmpty($protection_rule, 'The protection rule was deleted.');
+  }
+
+  /**
+   * Tests if user based protection rules can be created through the UI.
+   */
+  public function testCrudUserProtectionRule() {
+    $account = $this->drupalCreateUser();
+    $rule_id = strtolower($this->randomMachineName());
+    $label = $this->randomMachineName();
+
+    // Create rule.
+    $edit = [
+      'label' => $label,
+      'name' => $rule_id,
+      'entity_id' => $account->getAccountName(),
+      'protection[user_mail]' => TRUE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save'));
+
+    // Assert that the rule was created.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule, 'A protection rule was created through the UI.');
+
+    // Assert that the rule has the expected values.
+    $this->assertEquals($rule_id, $protection_rule->id());
+    $this->assertEquals($label, $protection_rule->label);
+    $this->assertEquals('user', $protection_rule->getProtectedEntityTypeId());
+    $this->assertEquals($account->id(), $protection_rule->getProtectedEntityId());
+    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
+    $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.');
+    $plugin = reset($enabled_plugins);
+    $this->assertEquals('user_mail', $plugin->getPluginId());
+
+    // Edit rule.
+    $edit = [
+      'protection[user_name]' => TRUE,
+      'protection[user_mail]' => FALSE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save'));
+
+    // Assert that the rule was updated with the expected values.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertEquals($rule_id, $protection_rule->id());
+    $this->assertEquals($label, $protection_rule->label);
+    $this->assertEquals('user', $protection_rule->getProtectedEntityTypeId());
+    $this->assertEquals($account->id(), $protection_rule->getProtectedEntityId());
+    $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins();
+    $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.');
+    $plugin = reset($enabled_plugins);
+    $this->assertEquals('user_name', $plugin->getPluginId());
+
+    // Attempt to create a rule with the same name.
+    $edit = [
+      'label' => $label,
+      'name' => $rule_id,
+      'entity_id' => $account->getAccountName(),
+      'protection[user_mail]' => TRUE,
+    ];
+    $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save'));
+    $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.');
+
+    // Assert only one protection rule exists.
+    $entities = ProtectionRule::loadMultiple(NULL);
+    $this->assertCount(1, $entities, 'Only one protection rule exists.');
+
+    // Delete rule.
+    $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', [], t('Delete'));
+    // Assert the rule no longer exists.
+    $protection_rule = ProtectionRule::load($rule_id);
+    $this->assertEmpty($protection_rule, 'The protection rule was deleted.');
+  }
+
+}
diff --git a/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php b/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..71f7f5cb03fd5f43d21b29511b42423e40e98dab
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php
@@ -0,0 +1,209 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional\RoleDelegation;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\userprotect\Entity\ProtectionRule;
+
+/**
+ * Functional tests for integration with role_delegation.
+ *
+ * @group userprotect
+ */
+class RoleDelegationIntegrationTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['userprotect', 'user', 'role_delegation'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Role ID.
+   *
+   * @var string
+   */
+  protected $rid1;
+
+  /**
+   * Role ID.
+   *
+   * @var string
+   */
+  protected $rid2;
+
+  /**
+   * An admin user.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $adminUser;
+
+  /**
+   * User with 'assign [role] role' permission'.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $roleDelegatedAdminUser;
+
+  /**
+   * User with 'administer permissions' permission.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $regularRolesAdminUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $admin_role = $this->createAdminRole();
+    $this->adminUser = $this->createUser();
+    $this->adminUser->addRole($admin_role);
+    $this->adminUser->save();
+
+    $this->rid1 = $this->drupalCreateRole([]);
+    $this->rid2 = $this->drupalCreateRole([]);
+
+    $this->roleDelegatedAdminUser = $this->drupalCreateUser([
+      'administer users',
+      sprintf('assign %s role', $this->rid1),
+      sprintf('assign %s role', $this->rid2),
+    ]);
+
+    $this->regularRolesAdminUser = $this->drupalCreateUser([
+      'administer users',
+      'administer permissions',
+    ]);
+
+    // Create a protection rule to protect users with the admin role.
+    ProtectionRule::create([
+      'name' => 'protect_admin_role',
+      'label' => 'Protect admin role',
+      'protections' => [
+        'user_roles' => [
+          'status' => TRUE,
+        ],
+      ],
+      'protectedEntityTypeId' => 'user_role',
+      'protectedEntityId' => $admin_role,
+    ])->save();
+  }
+
+  /**
+   * Ensure the roles element is only accessible for the right users.
+   */
+  public function testUserEditPage() {
+    // Login as the delegated admin user. This user has permission to assign
+    // roles 1 and 2 to users.
+    $this->drupalLogin($this->roleDelegatedAdminUser);
+
+    // Check if the delegated admin user can edit roles 1 and 2 on its own
+    // account page. Also check if the roles are presented by Role Delegation,
+    // not by Drupal core.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid1));
+    $this->assertSession()->fieldExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid2));
+    $this->assertSession()->fieldExists(sprintf('role_change[%s]', $this->rid2));
+
+    // The admin user, having the admin role, has role protection. Ensure that
+    // the delegated admin user cannot edit its roles.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id()));
+    $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid2));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2));
+
+    // Login as roles admin user. This user has permission to assign all roles.
+    $this->drupalLogin($this->regularRolesAdminUser);
+
+    // The delegated admin user does not have a protected role. Check if the
+    // roles admin user may edit its roles. Since the roles admin user has the
+    // specific Drupal core permission for assigning roles - 'administer
+    // permissions' - the roles should be presented by Drupal Core, not Role
+    // Delegation.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2));
+
+    // Since the admin user has role protection, ensure that the roles admin
+    // user cannot edit its roles.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id()));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->elementAttributeContains('css', sprintf('[name="roles[%s]"]', $this->rid1), 'disabled', 'disabled');
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2));
+    $this->assertSession()->elementAttributeContains('css', sprintf('[name="roles[%s]"]', $this->rid2), 'disabled', 'disabled');
+
+    // Login as an user with the admin role. This user has all privileges.
+    $this->drupalLogin($this->adminUser);
+
+    // Ensure the admin user can edit the roles of the delegated admin user.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2));
+
+    // Ensure the admin user can edit its own roles.
+    $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id()));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1));
+    $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2));
+    $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2));
+  }
+
+  /**
+   * Test that user protect rules are also enabled on /user/%user/roles.
+   */
+  public function testRolesPage() {
+    // Ensure that an anonymous user cannot access teh user protect settings
+    // page.
+    $this->drupalGet('admin/config/people/userprotect/manage/protect_admin_role');
+
+    // Login as the delegated admin user. This user has permission to assign
+    // roles 1 and 2 to users.
+    $this->drupalLogin($this->roleDelegatedAdminUser);
+
+    // Ensure that the delegated admin user can access its own roles edit page.
+    $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->statusCodeEquals(200);
+
+    // Ensure that the delegated admin user cannot access the roles edit page of
+    // the admin user, since that user has a protected role.
+    $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id()));
+    $this->assertSession()->statusCodeEquals(403);
+
+    // Login as roles admin user. This user has permission to assign all roles.
+    $this->drupalLogin($this->regularRolesAdminUser);
+
+    // Ensure that the roles admin user cannot access any roles edit pages, as
+    // that requires specific Roles Delegation permissions.
+    $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->statusCodeEquals(403);
+
+    $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id()));
+    $this->assertSession()->statusCodeEquals(403);
+
+    // Login as an user with the admin role. This user has all privileges.
+    $this->drupalLogin($this->adminUser);
+
+    // Ensure the admin user can access the roles edit page of all users.
+    $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id()));
+    $this->assertSession()->statusCodeEquals(200);
+
+    $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id()));
+    $this->assertSession()->statusCodeEquals(200);
+  }
+
+}
diff --git a/web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php b/web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php
similarity index 66%
rename from web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php
rename to web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php
index 2247369086bb8c613749cfbf735ab58420aaa0e1..bd35f4f15a22a3913e07b7ba24567f4a0b4f37a5 100644
--- a/web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php
+++ b/web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php
@@ -1,20 +1,18 @@
 <?php
 
-namespace Drupal\userprotect\Tests;
+namespace Drupal\Tests\userprotect\Functional;
 
 use Drupal\user\Entity\User;
 
 /**
- * Tests field access for a user that has not been saved, such as when a user
- * is created via REST POST.
+ * Tests field access for an unsaved user.
+ *
+ * Field access checks could for example be performed on new users when created
+ * via REST POST.
  *
  * @group userprotect
  */
-class UnsavedUserFieldAccessWebTest extends UserProtectWebTestBase {
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = ['userprotect'];
+class UnsavedUserFieldAccessTest extends UserProtectBrowserTestBase {
 
   /**
    * The operating account.
@@ -36,7 +34,7 @@ protected function setUp() {
   /**
    * Tests if userprotect doesn't interfere with creating users.
    */
-  protected function testUserCreate() {
+  public function testUserCreate() {
     // Create an account using the user interface.
     $name = $this->randomMachineName();
     $edit = [
@@ -47,30 +45,30 @@ protected function testUserCreate() {
       'notify' => FALSE,
     ];
     $this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
-    $this->assertText(t('Created a new user account for @name. No email has been sent.', ['@name' => $edit['name']]), 'User created');
+    $this->assertSession()->pageTextContains(t('Created a new user account for @name. No email has been sent.', ['@name' => $edit['name']]), 'User created');
 
     // Try to create an user with the same name and assert that it doesn't
     // result into a fatal error.
-    $edit = array(
+    $edit = [
       'name' => $name,
       'mail' => $this->randomMachineName() . '@example.com',
       'pass[pass1]' => $pass = $this->randomString(),
       'pass[pass2]' => $pass,
       'notify' => FALSE,
-    );
+    ];
     $this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
-    $this->assertText(t('The username @name is already taken.', ['@name' => $edit['name']]));
+    $this->assertSession()->pageTextContains(t('The username @name is already taken.', ['@name' => $edit['name']]));
   }
 
   /**
    * Tests field access for an unsaved user's name.
    */
-  protected function testNameAccessForUnsavedUser() {
-    $module_handler = \Drupal::moduleHandler();
-    $module_installer = \Drupal::service('module_installer');
+  public function testNameAccessForUnsavedUser() {
+    $module_handler = $this->container->get('module_handler');
+    $module_installer = $this->container->get('module_installer');
 
     // Create an unsaved user entity.
-    $unsavedUserEntity = User::Create([]);
+    $unsavedUserEntity = User::create([]);
 
     // The logged in user should have the privileges to edit the unsaved user's
     // name.
@@ -79,10 +77,16 @@ protected function testNameAccessForUnsavedUser() {
 
     // Uninstall userprotect and verify that logged in user has privileges to
     // edit the unsaved user's name.
-    $module_installer->uninstall(['userprotect']);
+    $module_installer->uninstall(['userprotect_test', 'userprotect']);
+
+    // Workaround https://www.drupal.org/node/2021959
+    // See \Drupal\Core\Test\FunctionalTestSetupTrait::rebuildContainer.
+    $this->rebuildContainer();
+    $module_handler = $this->container->get('module_handler');
 
     $this->assertFalse($module_handler->moduleExists('userprotect'), 'Userprotect uninstalled successfully.');
     $this->assertTrue($unsavedUserEntity->isAnonymous(), 'Unsaved user is considered anonymous when userprotect is uninstalled.');
     $this->assertTrue($unsavedUserEntity->get('name')->access('edit'), 'Logged in user is allowed to edit name field when userprotect is uninstalled.');
   }
+
 }
diff --git a/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php b/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..a0f6d8ed7c8f1b0e540a8a4699d2c405f4ba2492
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\userprotect\Traits\UserProtectCreationTrait;
+
+/**
+ * Provides a base class for User Protect functional tests.
+ */
+abstract class UserProtectBrowserTestBase extends BrowserTestBase {
+
+  use UserProtectCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['userprotect', 'userprotect_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Reloads an entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to reload.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   The reloaded entity.
+   */
+  protected function reloadEntity(EntityInterface $entity) {
+    /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
+    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
+    $storage->resetCache([$entity->id()]);
+    return $storage->load($entity->id());
+  }
+
+}
diff --git a/web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php b/web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php
similarity index 58%
rename from web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php
rename to web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php
index 0d577e3ba7df5d934ae35ebe71fcbb3c5636d42e..5b618eb191a0a7f23927f5ec1059bb66fa8ffb2f 100644
--- a/web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php
+++ b/web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\userprotect\Tests;
+namespace Drupal\Tests\userprotect\Functional;
 
-use Drupal\userprotect\Entity\ProtectionRuleInterface;
+use Drupal\Core\Session\AccountInterface;
 
 /**
- * Tests if permissions "Change own e-mail", "Change own password" and "Change own account" are respected.
+ * Tests if "change own" User Protect permissions are respected.
+ *
+ * The test includes coverage for the following permissions:
+ * - Change own e-mail (userprotect.mail.edit);
+ * - Change own password (userprotect.pass.edit);
+ * - Change own account (userprotect.account.edit).
  *
  * @group userprotect
  */
-class UserProtectionPermissionsWebTest extends UserProtectWebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
+class UserProtectionPermissionsTest extends UserProtectBrowserTestBase {
 
   /**
    * The operating account.
@@ -32,7 +32,7 @@ protected function setUp() {
     // Revoke default permissions on the authenticated user role that are
     // installed by the userprotect module.
     // @see userprotect_install().
-    $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
+    $role = \Drupal::entityTypeManager()->getStorage('user_role')->load(AccountInterface::AUTHENTICATED_ROLE);
     $role->revokePermission('userprotect.mail.edit');
     $role->revokePermission('userprotect.pass.edit');
     $role->revokePermission('userprotect.account.edit');
@@ -45,41 +45,35 @@ protected function setUp() {
    * Tests if an user with the permission "userprotect.mail.edit" can edit its
    * own mail.
    */
-  protected function testEditOwnMail() {
+  public function testEditOwnMail() {
     // Create account that may edit its own mail address.
-    $account = $this->drupalCreateUser(array('userprotect.mail.edit', 'userprotect.account.edit'));
+    $account = $this->drupalCreateUser(['userprotect.mail.edit', 'userprotect.account.edit']);
     $this->drupalLogin($account);
 
-    $edit = array(
+    $edit = [
       'mail' => $this->randomMachineName() . '@example.com',
-    );
+    ];
     $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save'));
 
     // Assert the mail address changed.
-    $account = entity_load('user', $account->id(), TRUE);
-    $this->assertEqual($edit['mail'], $account->getEmail(), "The user has changed its own mail address.");
+    $account = $this->reloadEntity($account);
+    $this->assertEquals($edit['mail'], $account->getEmail(), "The user has changed its own mail address.");
   }
 
   /**
    * Tests edit mail without permission "userprotect.mail.edit".
    *
-   * Tests if an user without the permission "userprotect.mail.edit" can not
+   * Tests if an user without the permission "userprotect.mail.edit" cannot
    * edit its own mail address.
    */
-  protected function testNoEditOwnMail() {
+  public function testNoEditOwnMail() {
     // Create account that may NOT edit its own mail address.
-    $account = $this->drupalCreateUser(array('userprotect.account.edit'));
+    $account = $this->drupalCreateUser(['userprotect.account.edit']);
     $expected_mail = $account->getEmail();
     $this->drupalLogin($account);
 
-    $edit = array(
-      'mail' => $this->randomMachineName() . '@example.com',
-    );
-    $this->userprotectPostForm('user/' . $account->id() . '/edit', $edit, t('Save'));
-
-    // Assert the mail address changed.
-    $account = entity_load('user', $account->id(), TRUE);
-    $this->assertEqual($expected_mail, $account->getEmail(), "The user's mail address was NOT changed.");
+    $this->drupalGet('user/' . $account->id() . '/edit');
+    $this->assertSession()->fieldDisabled('mail');
   }
 
   /**
@@ -88,22 +82,22 @@ protected function testNoEditOwnMail() {
    * Tests if an user with the permission "userprotect.pass.edit" can edit its
    * own password.
    */
-  protected function testEditOwnPass() {
+  public function testEditOwnPass() {
     // Create account that may edit its own password.
-    $account = $this->drupalCreateUser(array('userprotect.pass.edit', 'userprotect.account.edit'));
+    $account = $this->drupalCreateUser(['userprotect.pass.edit', 'userprotect.account.edit']);
     $this->drupalLogin($account);
 
     $new_pass = $this->randomMachineName();
-    $edit = array(
+    $edit = [
       'current_pass' => $account->pass_raw,
       'pass[pass1]' => $new_pass,
       'pass[pass2]' => $new_pass,
-    );
+    ];
     $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save'));
 
     // Assert the password changed.
-    $account = entity_load('user', $account->id(), TRUE);
-    $account->pass_raw = $new_pass;
+    $account = $this->reloadEntity($account);
+    $account->passRaw = $new_pass;
     $this->drupalLogout();
     $this->drupalLogin($account);
   }
@@ -111,28 +105,18 @@ protected function testEditOwnPass() {
   /**
    * Tests edit password without permission "userprotect.pass.edit".
    *
-   * Tests if an user without the permission "userprotect.pass.edit" can not
+   * Tests if an user without the permission "userprotect.pass.edit" cannot
    * edit its own password.
    */
-  protected function testNoEditOwnPass() {
+  public function testNoEditOwnPass() {
     // Create account that may NOT edit its own password.
-    $account = $this->drupalCreateUser(array('userprotect.account.edit'));
+    $account = $this->drupalCreateUser(['userprotect.account.edit']);
     $expected_pass = $account->pass_raw;
     $this->drupalLogin($account);
 
-    $new_pass = $this->randomMachineName();
-    $edit = array(
-      'current_pass' => $account->pass_raw,
-      'pass[pass1]' => $new_pass,
-      'pass[pass2]' => $new_pass,
-    );
-    $this->userprotectPostForm('user/' . $account->id() . '/edit', $edit, t('Save'));
-
-    // Assert the password did not change.
-    $account = entity_load('user', $account->id(), TRUE);
-    $account->pass_raw = $expected_pass;
-    $this->drupalLogout();
-    $this->drupalLogin($account);
+    $this->drupalGet('user/' . $account->id() . '/edit');
+    $this->assertSession()->fieldNotExists('pass[pass1]');
+    $this->assertSession()->fieldNotExists('pass[pass2]');
   }
 
   /**
@@ -141,9 +125,9 @@ protected function testNoEditOwnPass() {
    * Tests if an user with the permission "userprotect.account.edit" can edit
    * its own account.
    */
-  protected function testEditOwnAccount() {
+  public function testEditOwnAccount() {
     // Create an account that may edit its own account.
-    $account = $this->drupalCreateUser(array('userprotect.account.edit'));
+    $account = $this->drupalCreateUser(['userprotect.account.edit']);
     $this->drupalLogin($account);
 
     // Assert the user can edit its own account.
@@ -157,7 +141,7 @@ protected function testEditOwnAccount() {
    * Tests if an user without the permission "userprotect.account.edit" can
    * not edit its own account.
    */
-  protected function testNoEditOwnAccount() {
+  public function testNoEditOwnAccount() {
     // Create an account that may NOT edit its own account.
     $account = $this->drupalCreateUser();
     $this->drupalLogin($account);
@@ -166,4 +150,5 @@ protected function testNoEditOwnAccount() {
     $this->drupalGet('user/' . $account->id() . '/edit');
     $this->assertResponse(403, "The user may NOT edit its own account.");
   }
+
 }
diff --git a/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php b/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..72edbfeea25a76416425b04fde1f120987ff996f
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Functional;
+
+/**
+ * Tests each UserProtection plugin in action.
+ *
+ * @group userprotect
+ * @todo Assert protection messages.
+ */
+class UserProtectionTest extends UserProtectBrowserTestBase {
+
+  /**
+   * The operating account.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $account;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->account = $this->drupalCreateUser(['administer users', 'administer permissions']);
+    $this->drupalLogin($this->account);
+  }
+
+  /**
+   * Tests if the user's name field has the expected protection.
+   */
+  public function testNameProtection() {
+    $protected_account = $this->createProtectedUser(['user_name']);
+
+    $this->drupalGet('user/' . $protected_account->id() . '/edit');
+    $this->assertSession()->fieldNotExists('name');
+  }
+
+  /**
+   * Tests if the user's mail address field has the expected protection.
+   */
+  public function testMailProtection() {
+    $protected_account = $this->createProtectedUser(['user_mail']);
+
+    $this->drupalGet('user/' . $protected_account->id() . '/edit');
+    $this->assertSession()->fieldDisabled('mail');
+  }
+
+  /**
+   * Tests if the user's password field has the expected protection.
+   */
+  public function testPassProtection() {
+    $protected_account = $this->createProtectedUser(['user_pass']);
+
+    $this->drupalGet('user/' . $protected_account->id() . '/edit');
+    $this->assertSession()->fieldNotExists('pass[pass1]');
+    $this->assertSession()->fieldNotExists('pass[pass2]');
+  }
+
+  /**
+   * Tests if the user's status field has the expected protection.
+   */
+  public function testStatusProtection() {
+    $protected_account = $this->createProtectedUser(['user_status']);
+
+    $this->drupalGet('user/' . $protected_account->id() . '/edit');
+    $this->assertSession()->fieldNotExists('status');
+  }
+
+  /**
+   * Tests if the user's roles field has the expected protection.
+   */
+  public function testRolesProtection() {
+    $protected_account = $this->createProtectedUser(['user_roles']);
+
+    // Add a role to the protected account.
+    $rid1 = $this->drupalCreateRole([]);
+    $protected_account->addRole($rid1);
+    $protected_account->save();
+
+    // Add another role. We try to add this role to the user form later.
+    $rid2 = $this->drupalCreateRole([]);
+
+    // Reload the user and check its roles.
+    $protected_account = $this->reloadEntity($protected_account);
+    // Assert the protected account's roles.
+    $this->assertTrue($protected_account->hasRole($rid1));
+    $this->assertFalse($protected_account->hasRole($rid2));
+
+    // Ensure a checkbox for the second role is not available.
+    $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $rid2));
+  }
+
+}
diff --git a/web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php b/web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php
similarity index 66%
rename from web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php
rename to web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php
index aee4ee1010b2282ea5907538611a49aba4e13445..8a9f599b65a0cc33c457971750f4790eaad369cb 100644
--- a/web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php
+++ b/web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php
@@ -1,21 +1,28 @@
 <?php
 
-namespace Drupal\userprotect\Tests\Entity;
+namespace Drupal\Tests\userprotect\Kernel\Entity;
 
+use Drupal\user\Entity\User;
 use Drupal\Core\Session\UserSession;
+use Drupal\userprotect\Entity\ProtectionRule;
 use Drupal\userprotect\Entity\ProtectionRuleInterface;
 use Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface;
 use Drupal\userprotect\UserProtect;
 use Drupal\userprotect\Plugin\UserProtection\UserProtectionPluginCollection;
-use Drupal\simpletest\KernelTestBase;
+use Drupal\KernelTests\KernelTestBase;
 
 /**
- * \Drupal\userprotect\Entity\ProtectionRule unit test.
+ * Various unit tests for protection rules.
  *
  * @group userprotect
  */
 class ProtectionRuleUnitTest extends KernelTestBase {
 
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['user', 'userprotect', 'field'];
+
   /**
    * The user protection plugin manager.
    *
@@ -23,11 +30,6 @@ class ProtectionRuleUnitTest extends KernelTestBase {
    */
   protected $manager;
 
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('user', 'userprotect', 'field');
-
   /**
    * The protection rule to test on.
    *
@@ -41,98 +43,98 @@ class ProtectionRuleUnitTest extends KernelTestBase {
   protected function setUp() {
     parent::setUp();
     $this->manager = UserProtect::pluginManager();
-    $this->protectionRule = entity_create('userprotect_rule', array(
+    $this->protectionRule = ProtectionRule::create([
       'name' => 'dummy',
       'label' => 'Dummy',
-      'protections' => array(
-        'user_mail' => array(
+      'protections' => [
+        'user_mail' => [
           'status' => TRUE,
-        ),
-      ),
+        ],
+      ],
       'protectedEntityTypeId' => 'user_role',
       'protectedEntityId' => 'administrator',
-    ));
+    ]);
   }
 
   /**
    * Tests id().
    */
-  protected function testId() {
+  public function testId() {
     $this->assertIdentical('dummy', $this->protectionRule->id());
   }
 
   /**
    * Tests setProtectedEntityTypeId() and getProtectedEntityTypeId().
    */
-  protected function testProtectedEntityTypeId() {
+  public function testProtectedEntityTypeId() {
     $this->assertIdentical('user_role', $this->protectionRule->getProtectedEntityTypeId());
     $entity_type = 'user';
-    $this->assertTrue($this->protectionRule->setProtectedEntityTypeId($entity_type) instanceof ProtectionRuleInterface);
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setProtectedEntityTypeId($entity_type));
     $this->assertIdentical($entity_type, $this->protectionRule->getProtectedEntityTypeId());
   }
 
   /**
    * Tests setProtectedEntityId() and getProtectedEntityId().
    */
-  protected function testProtectedEntityId() {
+  public function testProtectedEntityId() {
     $this->assertIdentical('administrator', $this->protectionRule->getProtectedEntityId());
     $entity_id = 'authenticated';
-    $this->assertTrue($this->protectionRule->setProtectedEntityId($entity_id) instanceof ProtectionRuleInterface);
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setProtectedEntityId($entity_id));
     $this->assertIdentical($entity_id, $this->protectionRule->getProtectedEntityId());
   }
 
   /**
    * Tests setBypassRoles() and getBypassRoles().
    */
-  protected function testBypassRoles() {
-    $this->assertIdentical(array(), $this->protectionRule->getBypassRoles());
-    $roles = array('administrator');
-    $this->assertTrue($this->protectionRule->setBypassRoles($roles) instanceof ProtectionRuleInterface);
+  public function testBypassRoles() {
+    $this->assertIdentical([], $this->protectionRule->getBypassRoles());
+    $roles = ['administrator'];
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setBypassRoles($roles));
     $this->assertIdentical($roles, $this->protectionRule->getBypassRoles());
   }
 
   /**
    * Tests getProtection().
    */
-  protected function testGetProtection() {
-    $this->assertTrue($this->protectionRule->getProtection('user_mail') instanceof UserProtectionInterface);
+  public function testGetProtection() {
+    $this->assertInstanceOf(UserProtectionInterface::class, $this->protectionRule->getProtection('user_mail'));
   }
 
   /**
    * Tests getProtections().
    */
-  protected function testGetProtections() {
-    $this->assertTrue($this->protectionRule->getProtections() instanceof UserProtectionPluginCollection);
+  public function testGetProtections() {
+    $this->assertInstanceOf(UserProtectionPluginCollection::class, $this->protectionRule->getProtections());
   }
 
   /**
    * Tests enableProtection().
    */
-  protected function testEnableProtection() {
-    $this->assertTrue($this->protectionRule->enableProtection('user_name') instanceof ProtectionRuleInterface);
+  public function testEnableProtection() {
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->enableProtection('user_name'));
     $this->assertTrue($this->protectionRule->hasProtection('user_name'));
   }
 
   /**
    * Tests disableProtection().
    */
-  protected function testDisableProtection() {
-    $this->assertTrue($this->protectionRule->disableProtection('user_mail') instanceof ProtectionRuleInterface);
+  public function testDisableProtection() {
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->disableProtection('user_mail'));
     $this->assertFalse($this->protectionRule->hasProtection('user_mail'));
   }
 
   /**
    * Tests toArray().
    */
-  protected function testToArray() {
+  public function testToArray() {
     $array = $this->protectionRule->toArray();
     $this->assertIdentical('dummy', $array['name']);
     $this->assertIdentical('Dummy', $array['label']);
-    $expected_protections = array(
-      'user_mail' => array(
+    $expected_protections = [
+      'user_mail' => [
         'status' => TRUE,
-      ),
-    );
+      ],
+    ];
     $this->assertIdentical($expected_protections, $array['protections']);
     $this->assertIdentical('user_role', $array['protectedEntityTypeId']);
     $this->assertIdentical('administrator', $array['protectedEntityId']);
@@ -141,30 +143,30 @@ protected function testToArray() {
   /**
    * Tests getPermissionName().
    */
-  protected function testGetPermissionName() {
+  public function testGetPermissionName() {
     $this->assertIdentical('userprotect.dummy.bypass', $this->protectionRule->getPermissionName());
   }
 
   /**
    * Tests appliesTo().
    */
-  protected function testAppliesTo() {
+  public function testAppliesTo() {
     // Create an user with administrator role.
-    $values = array(
+    $values = [
       'uid' => 3,
       'name' => 'lorem',
-      'roles' => array(
+      'roles' => [
         'administrator',
-      ),
-    );
-    $lorem = entity_create('user', $values);
+      ],
+    ];
+    $lorem = User::create($values);
 
     // Create an authenticated user.
-    $values = array(
+    $values = [
       'uid' => 4,
       'name' => 'ipsum',
-    );
-    $ipsum = entity_create('user', $values);
+    ];
+    $ipsum = User::create($values);
 
     // Assert that the protection rule applies to the user with the
     // administrator role and not to the authenticated user.
@@ -172,17 +174,17 @@ protected function testAppliesTo() {
     $this->assertFalse($this->protectionRule->appliesTo($ipsum));
 
     // Create an user based protection rule.
-    $user_protection_rule = entity_create('userprotect_rule', array(
+    $user_protection_rule = ProtectionRule::create([
       'name' => 'dummy',
       'label' => 'Dummy',
-      'protections' => array(
-        'user_mail' => array(
+      'protections' => [
+        'user_mail' => [
           'status' => TRUE,
-        ),
-      ),
+        ],
+      ],
       'protectedEntityTypeId' => 'user',
       'protectedEntityId' => 4,
-    ));
+    ]);
 
     // Assert that the protection rule applies to "ipsum", but no to "lorem".
     $this->assertFalse($user_protection_rule->appliesTo($lorem));
@@ -192,7 +194,7 @@ protected function testAppliesTo() {
   /**
    * Tests hasProtection().
    */
-  protected function testHasProtection() {
+  public function testHasProtection() {
     // The protection rule was created with only the protection "user_mail"
     // enabled.
     $this->assertTrue($this->protectionRule->hasProtection('user_mail'));
@@ -203,23 +205,23 @@ protected function testHasProtection() {
   /**
    * Tests isProtected().
    */
-  protected function testIsProtected() {
+  public function testIsProtected() {
     // Create an user with administrator role.
-    $values = array(
+    $values = [
       'uid' => 3,
       'name' => 'lorem',
-      'roles' => array(
+      'roles' => [
         'administrator',
-      ),
-    );
-    $lorem = entity_create('user', $values);
+      ],
+    ];
+    $lorem = User::create($values);
 
     // Create an authenticated user.
-    $values = array(
+    $values = [
       'uid' => 4,
       'name' => 'ipsum',
-    );
-    $ipsum = entity_create('user', $values);
+    ];
+    $ipsum = User::create($values);
 
     // Create an operating account.
     $account = new UserSession();
@@ -229,4 +231,5 @@ protected function testIsProtected() {
     $this->assertTrue($this->protectionRule->isProtected($lorem, 'user_mail', $account));
     $this->assertFalse($this->protectionRule->isProtected($ipsum, 'user_mail', $account));
   }
+
 }
diff --git a/web/modules/userprotect/src/Tests/FieldAccessWebTest.php b/web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php
similarity index 54%
rename from web/modules/userprotect/src/Tests/FieldAccessWebTest.php
rename to web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php
index 4ecd50ab08ae2ec6d4e430fefd009ee49fb401ab..1e132254a78648f2f524d4acb0df8e3c67e63781 100644
--- a/web/modules/userprotect/src/Tests/FieldAccessWebTest.php
+++ b/web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php
@@ -1,24 +1,20 @@
 <?php
 
-namespace Drupal\userprotect\Tests;
+namespace Drupal\Tests\userprotect\Kernel;
 
 /**
  * Tests field access for each UserProtection plugin that protects a field.
  *
  * @group userprotect
  */
-class FieldAccessWebTest extends UserProtectWebTestBase {
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
+class FieldAccessTest extends UserProtectKernelTestBase {
 
   /**
-   * The operating account.
+   * The user admin.
    *
    * @var \Drupal\user\UserInterface
    */
-  protected $account;
+  protected $userAdmin;
 
   /**
    * {@inheritdoc}
@@ -26,82 +22,87 @@ class FieldAccessWebTest extends UserProtectWebTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->account = $this->drupalCreateUser(array('administer users', 'administer permissions'));
-    $this->drupalLogin($this->account);
+    // Create an user who administer users. Explicitly set user ID to '2'
+    // because user 1 would have all permissions.
+    $perm = ['administer users', 'administer permissions'];
+    $this->userAdmin = $this->drupalCreateUser($perm, NULL, FALSE, [
+      'uid' => 2,
+    ]);
   }
 
   /**
    * Tests field access for the user's name.
    */
-  protected function testNameAccess() {
+  public function testNameAccess() {
     // Create an account with no protection. The logged in user should have the
     // privileges to edit this account's name.
     $account = $this->drupalCreateUser();
-    $this->assertTrue($account->name->access('edit', $this->account));
+    $this->assertTrue($account->name->access('edit', $this->userAdmin), 'User admin can edit account name of non-protected user.');
 
     // Create a protected account. The logged in user should NOT have the
     // privileges to edit this account's name.
-    $protected_account = $this->createProtectedUser(array('user_name'));
-    $this->assertFalse($protected_account->name->access('edit', $this->account));
+    $protected_account = $this->createProtectedUser(['user_name']);
+    $this->assertFalse($protected_account->name->access('edit', $this->userAdmin), 'User admin cannot edit account name of protected user.');
   }
 
   /**
    * Tests field access for the user's mail address.
    */
-  protected function testMailAccess() {
+  public function testMailAccess() {
     // Create an account with no protection. The logged in user should have the
     // privileges to edit this account's mail address.
     $account = $this->drupalCreateUser();
-    $this->assertTrue($account->mail->access('edit', $this->account));
+    $this->assertTrue($account->mail->access('edit', $this->userAdmin), 'User admin can edit mail address of non-protected user.');
 
     // Create a protected account. The logged in user should NOT have the
     // privileges to edit this account's mail address.
-    $protected_account = $this->createProtectedUser(array('user_mail'));
-    $this->assertFalse($protected_account->mail->access('edit', $this->account));
+    $protected_account = $this->createProtectedUser(['user_mail']);
+    $this->assertFalse($protected_account->mail->access('edit', $this->userAdmin), 'User admin cannot edit mail address of protected user.');
   }
 
   /**
    * Tests field access for the user's password.
    */
-  protected function testPassAccess() {
+  public function testPassAccess() {
     // Create an account with no protection. The logged in user should have the
     // privileges to edit this account's password.
     $account = $this->drupalCreateUser();
-    $this->assertTrue($account->pass->access('edit', $this->account));
+    $this->assertTrue($account->pass->access('edit', $this->userAdmin), 'User admin can edit password of non-protected user.');
 
     // Create a protected account. The logged in user should NOT have the
     // privileges to edit this account's password.
-    $protected_account = $this->createProtectedUser(array('user_pass'));
-    $this->assertFalse($protected_account->pass->access('edit', $this->account));
+    $protected_account = $this->createProtectedUser(['user_pass']);
+    $this->assertFalse($protected_account->pass->access('edit', $this->userAdmin), 'User admin cannot edit password of protected user.');
   }
 
   /**
    * Tests field access for the user's status.
    */
-  protected function testStatusAccess() {
+  public function testStatusAccess() {
     // Create an account with no protection. The logged in user should have the
     // privileges to edit this account's status.
     $account = $this->drupalCreateUser();
-    $this->assertTrue($account->status->access('edit', $this->account));
+    $this->assertTrue($account->status->access('edit', $this->userAdmin), 'User admin can edit status of non-protected user.');
 
     // Create a protected account. The logged in user should NOT have the
     // privileges to edit this account's status.
-    $protected_account = $this->createProtectedUser(array('user_status'));
-    $this->assertFalse($protected_account->status->access('edit', $this->account));
+    $protected_account = $this->createProtectedUser(['user_status']);
+    $this->assertFalse($protected_account->status->access('edit', $this->userAdmin), 'User admin cannot edit status of protected user.');
   }
 
   /**
    * Tests field access for the user's roles.
    */
-  protected function testRolesAccess() {
+  public function testRolesAccess() {
     // Create an account with no protection. The logged in user should have the
     // privileges to edit this account's roles.
     $account = $this->drupalCreateUser();
-    $this->assertTrue($account->roles->access('edit', $this->account));
+    $this->assertTrue($account->roles->access('edit', $this->userAdmin), 'User admin can edit roles of non-protected user.');
 
     // Create a protected account. The logged in user should NOT have the
     // privileges to edit this account's roles.
-    $protected_account = $this->createProtectedUser(array('user_roles'));
-    $this->assertFalse($protected_account->roles->access('edit', $this->account));
+    $protected_account = $this->createProtectedUser(['user_roles']);
+    $this->assertFalse($protected_account->roles->access('edit', $this->userAdmin), 'User admin cannot edit roles of protected user.');
   }
+
 }
diff --git a/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php b/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..73731c9c6ded2e88be567049cc188754f69ddb6e
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Kernel;
+
+/**
+ * Tests if protection rules are cleaned up upon entity deletion.
+ *
+ * @group userprotect
+ */
+class ProtectedEntityDeleteTest extends UserProtectKernelTestBase {
+
+  /**
+   * Tests reaction upon user deletion.
+   *
+   * Tests if an user based protection rule is cleaned up when the protected
+   * user is deleted.
+   */
+  public function testUserDelete() {
+    // Create a user.
+    $account = $this->drupalCreateUser();
+
+    // Protect this user.
+    $protection_rule = $this->createProtectionRule($account->id(), [], 'user');
+    $protection_rule->save();
+
+    // Assert that the rule was saved.
+    $protection_rule = $this->reloadEntity($protection_rule);
+    $this->assertNotNull($protection_rule, 'The protection rule was saved.');
+
+    // Now delete the account.
+    $account->delete();
+
+    // Assert that the rule no longer exists.
+    $protection_rule = $this->reloadEntity($protection_rule);
+    $this->assertNull($protection_rule, 'The protection rule was deleted.');
+  }
+
+  /**
+   * Tests reaction upon role deletion.
+   *
+   * Tests if a role based protection rule is cleaned up when the protected
+   * role is deleted.
+   */
+  public function testRoleDelete() {
+    // Create a role.
+    $rid = $this->drupalCreateRole([]);
+
+    // Protect this role.
+    $protection_rule = $this->createProtectionRule($rid, [], 'user_role');
+    $protection_rule->save();
+
+    // Assert that the rule was saved.
+    $protection_rule = $this->reloadEntity($protection_rule);
+    $this->assertNotNull($protection_rule, 'The protection rule was saved.');
+
+    // Now delete the role.
+    $role = \Drupal::entityTypeManager()->getStorage('user_role')->load($rid);
+    $role->delete();
+
+    // Assert that the rule no longer exists.
+    $protection_rule = $this->reloadEntity($protection_rule);
+    $this->assertNull($protection_rule, 'The protection rule was deleted.');
+  }
+
+}
diff --git a/web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php b/web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php
similarity index 70%
rename from web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php
rename to web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php
index 65880c0e3c96a2c3c6bcc0752b33e700eca18275..20eacbc6d7236fd8a5764d21d1610c0afedeaa77 100644
--- a/web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php
+++ b/web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\userprotect\Tests;
+namespace Drupal\Tests\userprotect\Kernel;
 
 /**
  * Tests bypassing protection rules.
@@ -8,12 +8,7 @@
  * @group userprotect
  * @todo add bypass test for 'all' protection rules.
  */
-class ProtectionRuleBypassWebTest extends UserProtectWebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array('userprotect');
+class ProtectionRuleBypassTest extends UserProtectKernelTestBase {
 
   /**
    * The user access controller.
@@ -28,41 +23,41 @@ class ProtectionRuleBypassWebTest extends UserProtectWebTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->accessController = \Drupal::entityManager()->getAccessControlHandler('user');
+    $this->accessController = \Drupal::entityTypeManager()->getAccessControlHandler('user');
   }
 
   /**
    * Tests if bypassing role name edit protection is respected.
    */
-  protected function testRoleNameEditProtectionBypass() {
+  public function testRoleNameEditProtectionBypass() {
     $this->doRoleProtectionBypassTest('user_name', 'user_name');
   }
 
   /**
    * Tests if bypassing role mail edit protection is respected.
    */
-  protected function testRoleMailEditProtectionBypass() {
+  public function testRoleMailEditProtectionBypass() {
     $this->doRoleProtectionBypassTest('user_mail', 'user_mail');
   }
 
   /**
    * Tests if bypassing role password edit protection is respected.
    */
-  protected function testRolePassEditProtectionBypass() {
+  public function testRolePassEditProtectionBypass() {
     $this->doRoleProtectionBypassTest('user_pass', 'user_pass');
   }
 
   /**
    * Tests if bypassing role edit protection is respected.
    */
-  protected function testRoleEditProtectionBypass() {
+  public function testRoleEditProtectionBypass() {
     $this->doRoleProtectionBypassTest('user_edit', 'update');
   }
 
   /**
    * Tests if bypassing role delete protection is respected.
    */
-  protected function testRoleDeleteProtectionBypass() {
+  public function testRoleDeleteProtectionBypass() {
     $this->doRoleProtectionBypassTest('user_delete', 'delete');
   }
 
@@ -76,51 +71,51 @@ protected function testRoleDeleteProtectionBypass() {
    */
   protected function doRoleProtectionBypassTest($plugin, $operation) {
     // Create a protected role.
-    $rid = $this->createProtectedRole(array($plugin));
+    $rid = $this->createProtectedRole([$plugin]);
 
     // Create an account with this protected role.
     $protected_account = $this->drupalCreateUser();
     $protected_account->addRole($rid);
 
     // Create operating account.
-    $account = $this->drupalCreateUser(array('administer users', 'userprotect.dummy.bypass'));
+    $account = $this->drupalCreateUser(['administer users', 'userprotect.dummy.bypass']);
 
     // Test if account has the expected access.
-    $this->assertTrue($this->accessController->access($protected_account, $operation, NULL, $account));
+    $this->assertTrue($this->accessController->access($protected_account, $operation, $account));
   }
 
   /**
    * Tests if bypassing user name edit protection is respected.
    */
-  protected function testUserNameEditProtectionBypass() {
+  public function testUserNameEditProtectionBypass() {
     $this->doUserProtectionBypassTest('user_name', 'user_name');
   }
 
   /**
    * Tests if bypassing user mail edit protection is respected.
    */
-  protected function testUserMailEditProtectionBypass() {
+  public function testUserMailEditProtectionBypass() {
     $this->doUserProtectionBypassTest('user_mail', 'user_mail');
   }
 
   /**
    * Tests if bypassing user password edit protection is respected.
    */
-  protected function testUserPassEditProtectionBypass() {
+  public function testUserPassEditProtectionBypass() {
     $this->doUserProtectionBypassTest('user_pass', 'user_pass');
   }
 
   /**
    * Tests if bypassing user edit protection is respected.
    */
-  protected function testUserEditProtectionBypass() {
+  public function testUserEditProtectionBypass() {
     $this->doUserProtectionBypassTest('user_edit', 'update');
   }
 
   /**
    * Tests if bypassing user delete protection is respected.
    */
-  protected function testUserDeleteProtectionBypass() {
+  public function testUserDeleteProtectionBypass() {
     $this->doUserProtectionBypassTest('user_delete', 'delete');
   }
 
@@ -134,12 +129,13 @@ protected function testUserDeleteProtectionBypass() {
    */
   protected function doUserProtectionBypassTest($plugin, $operation) {
     // Create a protected user.
-    $protected_account = $this->createProtectedUser(array($plugin));
+    $protected_account = $this->createProtectedUser([$plugin]);
 
     // Create operating account.
-    $account = $this->drupalCreateUser(array('administer users', 'userprotect.dummy.bypass'));
+    $account = $this->drupalCreateUser(['administer users', 'userprotect.dummy.bypass']);
 
     // Test if account has the expected access.
-    $this->assertTrue($this->accessController->access($protected_account, $operation, NULL, $account));
+    $this->assertTrue($this->accessController->access($protected_account, $operation, $account));
   }
+
 }
diff --git a/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php b/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..b5b099fbf9ca844604b407fd58e47a2082b8343b
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Kernel;
+
+use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+use Drupal\Tests\userprotect\Traits\UserProtectCreationTrait;
+
+/**
+ * Provides a base class for User Protect kernel tests.
+ */
+abstract class UserProtectKernelTestBase extends EntityKernelTestBase {
+
+  use UserProtectCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['userprotect'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('user', ['users_data']);
+  }
+
+}
diff --git a/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php b/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..cbc6bbbd67f968a2b99bd43b8055c75a9af5ddb1
--- /dev/null
+++ b/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Drupal\Tests\userprotect\Traits;
+
+use Drupal\userprotect\Entity\ProtectionRule;
+use Drupal\userprotect\Entity\ProtectionRuleInterface;
+
+/**
+ * Provides methods to create protection rules.
+ *
+ * This trait is meant to be used only by test classes.
+ */
+trait UserProtectCreationTrait {
+
+  /**
+   * Creates a protected role.
+   *
+   * @param array $protections
+   *   (optional) The active protections.
+   *   Defaults to an empty array.
+   *
+   * @return string
+   *   The ID of the created role.
+   */
+  protected function createProtectedRole(array $protections = []) {
+    // Create a role.
+    $rid = $this->drupalCreateRole([]);
+
+    // Protect this role.
+    $protection_rule = $this->createProtectionRule($rid, $protections);
+    $protection_rule->save();
+    // Reset available permissions.
+    drupal_static_reset('checkPermissions');
+
+    return $rid;
+  }
+
+  /**
+   * Creates a protected user.
+   *
+   * @param array $protections
+   *   (optional) The active protections.
+   *   Defaults to an empty array.
+   *
+   * @return object
+   *   The created user.
+   */
+  protected function createProtectedUser(array $protections = []) {
+    // Create a user.
+    $account = $this->drupalCreateUser();
+
+    // Protect this user.
+    $protection_rule = $this->createProtectionRule($account->id(), $protections, 'user');
+    $protection_rule->save();
+    // Reset available permissions.
+    drupal_static_reset('checkPermissions');
+
+    return $account;
+  }
+
+  /**
+   * Creates an user with a protected role.
+   *
+   * @param array $protections
+   *   (optional) The active protections.
+   *   Defaults to an empty array.
+   *
+   * @return object
+   *   The created user.
+   */
+  protected function createUserWithProtectedRole(array $protections = []) {
+    // Create a protected role.
+    $rid = $this->createProtectedRole($protections);
+
+    // Create an account with this protected role.
+    $protected_account = $this->drupalCreateUser();
+    $protected_account->addRole($rid);
+    $protected_account->save();
+
+    return $protected_account;
+  }
+
+  /**
+   * Creates protection rule.
+   *
+   * @param int|string $entity_id
+   *   The id of the entity to protect.
+   * @param array $protections
+   *   (optional) The active protections.
+   *   Defaults to an empty array.
+   * @param string $entity_type
+   *   (optional) The protected entity type.
+   *   Defaults to "user_role".
+   * @param array $values
+   *   (optional) Extra values of the protection rule.
+   *
+   * @return \Drupal\userprotect\Entity\ProtectionRuleInterface
+   *   An instance of ProtectionRuleInterface.
+   */
+  protected function createProtectionRule($entity_id, array $protections = [], $entity_type = 'user_role', array $values = []) {
+    // Setup default values.
+    $values += [
+      'name' => 'dummy',
+      'label' => 'Dummy',
+      'protections' => [],
+      'protectedEntityTypeId' => $entity_type,
+      'protectedEntityId' => $entity_id,
+    ];
+    // Define protections.
+    foreach ($protections as $key) {
+      $values['protections'][$key] = [
+        'status' => TRUE,
+      ];
+    }
+
+    // Create protection rule.
+    $protection_rule = ProtectionRule::create($values);
+    $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule);
+    return $protection_rule;
+  }
+
+}
diff --git a/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php b/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php
index d1ae1fae5b66c7f2960aefdfc1ac76bad24d27b0..904fc1dac84199e58947911d6570235dc804e536 100644
--- a/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php
+++ b/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php
@@ -29,13 +29,13 @@ class UserProtectionBaseUnitTest extends UnitTestCase {
    *
    * @var array
    */
-  protected $pluginDefinition = array(
+  protected $pluginDefinition = [
     'id' => 'dummy',
     'label' => 'Dummy',
     'description' => 'This is a dummy plugin definition.',
     'provider' => '',
     'status' => FALSE,
-  );
+  ];
 
   /**
    * {@inheritdoc}
@@ -43,16 +43,16 @@ class UserProtectionBaseUnitTest extends UnitTestCase {
   public function setUp() {
     parent::setUp();
 
-    $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler = $this->createMock('\Drupal\Core\Extension\ModuleHandlerInterface');
 
     $this->plugin = $this->getMockBuilder('\Drupal\userprotect\Plugin\UserProtection\UserProtectionBase')
-      ->setConstructorArgs(array(
-        array(),
+      ->setConstructorArgs([
+        [],
         '',
         $this->pluginDefinition,
         $this->moduleHandler,
-      ))
-      ->setMethods(array('t'))
+      ])
+      ->setMethods(['t'])
       ->getMock();
     $this->plugin->expects($this->any())
       ->method('t')
@@ -78,9 +78,9 @@ public function testDescription() {
    * @covers ::getConfiguration
    */
   public function testGetConfiguration() {
-    $configuration = array(
+    $configuration = [
       'status' => TRUE,
-    );
+    ];
     $this->assertInstanceOf('\Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface', $this->plugin->setConfiguration($configuration));
     $saved_configuration = $this->plugin->getConfiguration();
     $this->assertSame($configuration['status'], $saved_configuration['status']);
@@ -92,4 +92,5 @@ public function testGetConfiguration() {
   public function testDefaultConfiguration() {
     $this->assertInternalType('array', $this->plugin->defaultConfiguration());
   }
+
 }
diff --git a/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php b/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php
index 14d65d21f41ac5f8239240221e4e3abb507f3f00..c871a628e71f48d89fd53fd845d91e1867a131c0 100644
--- a/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php
+++ b/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php
@@ -17,9 +17,10 @@ class UserProtectUnitTest extends UnitTestCase {
    */
   public function testPluginManager() {
     $container = new Container();
-    $plugin_manager = $this->getMock('\Drupal\Component\Plugin\PluginManagerInterface');
+    $plugin_manager = $this->createMock('\Drupal\Component\Plugin\PluginManagerInterface');
     $container->set('plugin.manager.userprotect.user_protection', $plugin_manager);
     \Drupal::setContainer($container);
     $this->assertSame($plugin_manager, UserProtect::pluginManager());
   }
+
 }
diff --git a/web/modules/userprotect/userprotect.info.yml b/web/modules/userprotect/userprotect.info.yml
index b42cf5ea8fd817d52974a366ef4dc929cf17e7c8..e384e9eadd9f90e4a962a33253af2fd5f86abe1f 100644
--- a/web/modules/userprotect/userprotect.info.yml
+++ b/web/modules/userprotect/userprotect.info.yml
@@ -1,13 +1,14 @@
-name: User protect
+name: User Protect
 type: module
 description: 'Allows admins to protect users from being edited or cancelled, on a per-user basis.'
-# core: 8.x
+core: 8.x
+core_version_requirement: ^8 || ^9
 configure: userprotect.rule_list
 dependencies:
-  - user
+  - drupal:system (>=8.7.0)
+  - drupal:user
 
-# Information added by Drupal.org packaging script on 2016-10-29
-version: '8.x-1.0'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-01-06
+version: '8.x-1.1'
 project: 'userprotect'
-datestamp: 1477741140
+datestamp: 1578341587
diff --git a/web/modules/userprotect/userprotect.install b/web/modules/userprotect/userprotect.install
index 45e7aaf037d3f9a63b59c6225b1c37e07cb7e139..a4a2c463ee75e90f9cb751aadc14a9101651c4b5 100644
--- a/web/modules/userprotect/userprotect.install
+++ b/web/modules/userprotect/userprotect.install
@@ -5,13 +5,15 @@
  * Install, update and uninstall functions for the userprotect module.
  */
 
+use Drupal\Core\Session\AccountInterface;
+
 /**
  * Implements hook_install().
  *
  * Installs default userprotect permissions for authenticated users.
  */
 function userprotect_install() {
-  $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
+  $role = \Drupal::entityTypeManager()->getStorage('user_role')->load(AccountInterface::AUTHENTICATED_ROLE);
   $role->grantPermission('userprotect.mail.edit');
   $role->grantPermission('userprotect.pass.edit');
   $role->grantPermission('userprotect.account.edit');
diff --git a/web/modules/userprotect/userprotect.module b/web/modules/userprotect/userprotect.module
index 6902b869342ad4b6cb9a85c94b05bf96a94b4518..72d069c5d34c6f8011a8338d5da4dae18662411e 100644
--- a/web/modules/userprotect/userprotect.module
+++ b/web/modules/userprotect/userprotect.module
@@ -2,8 +2,7 @@
 
 /**
  * @file
- * Allows admins to protect users from being edited or cancelled, on a per-user
- * basis.
+ * Allows admins to protect users from being edited or cancelled.
  */
 
 use Drupal\Core\Access\AccessResult;
@@ -23,14 +22,11 @@
  *   An instance of an userprotect_rule entity.
  */
 function userprotect_rule_load($name) {
-  return entity_load('userprotect_rule', $name);
+  return \Drupal::entityTypeManager()->getStorage('userprotect_rule')->load($name);
 }
 
 /**
  * Implements hook_ENTITY_TYPE_access() for entity type "user".
- *
- * @param \Drupal\user\UserInterface $entity
- *   The user object to check access for.
  */
 function userprotect_user_access(UserInterface $entity, $op, AccountInterface $account) {
   // Check if the account has the permission "userprotect.bypass_all".
@@ -118,8 +114,8 @@ function userprotect_user_access(UserInterface $entity, $op, AccountInterface $a
  */
 function userprotect_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemList $items = NULL) {
   if (is_null($items)) {
-    // Sometimes no field item list is passed. In this case, there is nothing for
-    // userprotect to check.
+    // Sometimes no field item list is passed. In this case, there is nothing
+    // for userprotect to check.
     return AccessResult::neutral();
   }
 
@@ -152,6 +148,11 @@ function userprotect_entity_field_access($operation, FieldDefinitionInterface $f
       // userprotect_user_access().
       $entity_operation = 'user_' . $name;
       return ($entity->access($entity_operation, $account)) ? AccessResult::neutral() : AccessResult::forbidden();
+
+    // Make sure this module also works when role_delegation is enabled.
+    case 'role_change':
+      $entity_operation = 'user_roles';
+      return ($entity->access($entity_operation, $account)) ? AccessResult::neutral() : AccessResult::forbidden();
   }
 
   // The field is not one of the fields that userprotect supports.
@@ -171,7 +172,9 @@ function userprotect_user_delete($account) {
     ->execute();
   // Delete protection rules.
   if (!empty($entity_ids)) {
-    entity_delete_multiple('userprotect_rule', $entity_ids);
+    $storage_handler = \Drupal::entityTypeManager()->getStorage('userprotect_rule');
+    $entities = $storage_handler->loadMultiple($entity_ids);
+    $storage_handler->delete($entities);
   }
 }
 
@@ -188,7 +191,9 @@ function userprotect_user_role_delete($role) {
     ->execute();
   // Delete protection rules.
   if (!empty($entity_ids)) {
-    entity_delete_multiple('userprotect_rule', $entity_ids);
+    $storage_handler = \Drupal::entityTypeManager()->getStorage('userprotect_rule');
+    $entities = $storage_handler->loadMultiple($entity_ids);
+    $storage_handler->delete($entities);
   }
 }
 
@@ -214,7 +219,7 @@ function userprotect_form_user_form_alter(&$form, &$form_state) {
 
   // For each protection plugin, check if the current user has access
   // to the element the plugin protects. If not, apply the protection.
-  $applied = array();
+  $applied = [];
   foreach ($protection_definitions as $protection_definition) {
     if (!$entity->access($protection_definition['id'], $account)) {
       // Apply protection.
@@ -229,11 +234,11 @@ function userprotect_form_user_form_alter(&$form, &$form_state) {
   // Display a message about the applied protections if there were protections
   // applied and if the current user is an admin user.
   if (count($applied) && $account->hasPermission('administer users')) {
-    $message = t('%user has been protected from the following editing operations: @operations', array(
-      '%user' => $entity->getUsername(),
+    $message = t('%user has been protected from the following editing operations: @operations', [
+      '%user' => $entity->getAccountName(),
       '@operations' => implode(', ', $applied),
-    ));
-    drupal_set_message($message);
+    ]);
+    \Drupal::messenger()->addMessage($message);
   }
 }
 
@@ -261,5 +266,5 @@ function userprotect_get_user_protection_rules(UserInterface $account) {
   $entity_ids = $query
     ->condition($group)
     ->execute();
-  return entity_load_multiple('userprotect_rule', $entity_ids);
+  return \Drupal::entityTypeManager()->getStorage('userprotect_rule')->loadMultiple($entity_ids);
 }
diff --git a/web/modules/userprotect/userprotect.services.yml b/web/modules/userprotect/userprotect.services.yml
index cd707c3f77769cb3da3e931e1605df6cd37145dc..0d689587e4dc9e55b7e87b3164c9718e3e8cc6e6 100644
--- a/web/modules/userprotect/userprotect.services.yml
+++ b/web/modules/userprotect/userprotect.services.yml
@@ -2,3 +2,11 @@ services:
   plugin.manager.userprotect.user_protection:
     class: Drupal\userprotect\Plugin\UserProtection\UserProtectionManager
     parent: default_plugin_manager
+  userprotect.route_subscriber:
+    class: Drupal\userprotect\Routing\RouteSubscriber
+    tags:
+      - { name: event_subscriber }
+  access_check.user_protect.role_access:
+    class: Drupal\userprotect\Access\UserProtectRoleAccessCheck
+    tags:
+      - { name: access_check, applies_to: _userprotect_role_access_check }