diff --git a/core/modules/user/src/Tests/UserCancelTest.php b/core/modules/user/tests/src/Functional/UserCancelTest.php
similarity index 98%
rename from core/modules/user/src/Tests/UserCancelTest.php
rename to core/modules/user/tests/src/Functional/UserCancelTest.php
index a74626e..e02c3de 100644
--- a/core/modules/user/src/Tests/UserCancelTest.php
+++ b/core/modules/user/tests/src/Functional/UserCancelTest.php
@@ -1,21 +1,23 @@
 <?php
 
-namespace Drupal\user\Tests;
+namespace Drupal\Tests\user\Functional;
 
-use Drupal\comment\Tests\CommentTestTrait;
-use Drupal\simpletest\WebTestBase;
 use Drupal\comment\CommentInterface;
 use Drupal\comment\Entity\Comment;
+use Drupal\comment\Tests\CommentTestTrait;
+use Drupal\Tests\BrowserTestBase;
 use Drupal\user\Entity\User;
+use Drupal\Tests\Traits\Core\MetaRefreshTrait;
 
 /**
  * Ensure that account cancellation methods work as expected.
  *
  * @group user
  */
-class UserCancelTest extends WebTestBase {
+class UserCancelTest extends BrowserTestBase {
 
   use CommentTestTrait;
+  use MetaRefreshTrait;
 
   /**
    * Modules to enable.
@@ -82,6 +84,7 @@ public function testUserCancelChangePermission() {
 
     // Delete regular user.
     $this->drupalPostForm('user_form_test_cancel/' . $account->id(), [], t('Cancel account'));
+    $this->waitBatchProccessToEnd();
 
     // Confirm deletion.
     $this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
@@ -210,6 +213,8 @@ public function testUserBlock() {
 
     // Confirm account cancellation request.
     $this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
+    $this->waitBatchProccessToEnd();
+
     $user_storage->resetCache([$account->id()]);
     $account = $user_storage->load($account->id());
     $this->assertTrue($account->isBlocked(), 'User has been blocked.');
@@ -268,6 +273,8 @@ public function testUserBlockUnpublish() {
 
     // Confirm account cancellation request.
     $this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
+    $this->waitBatchProccessToEnd();
+
     $user_storage->resetCache([$account->id()]);
     $account = $user_storage->load($account->id());
     $this->assertTrue($account->isBlocked(), 'User has been blocked.');
@@ -344,6 +351,8 @@ public function testUserAnonymize() {
 
     // Confirm account cancellation request.
     $this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
+    $this->waitBatchProccessToEnd();
+
     $user_storage->resetCache([$account->id()]);
     $this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
 
@@ -404,6 +413,8 @@ public function testUserAnonymizeBatch() {
 
     // Confirm account cancellation request.
     $this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
+    $this->waitBatchProccessToEnd();
+
     $user_storage->resetCache([$account->id()]);
     $this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
 
@@ -470,6 +481,8 @@ public function testUserDelete() {
 
     // Confirm account cancellation request.
     $this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
+    $this->waitBatchProccessToEnd();
+
     $user_storage->resetCache([$account->id()]);
     $this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
 
@@ -507,6 +520,8 @@ public function testUserCancelByAdmin() {
 
     // Confirm deletion.
     $this->drupalPostForm(NULL, NULL, t('Cancel account'));
+    $this->waitBatchProccessToEnd();
+
     $this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
     $this->assertFalse(User::load($account->id()), 'User is not found in the database.');
   }
@@ -535,6 +550,8 @@ public function testUserWithoutEmailCancelByAdmin() {
 
     // Confirm deletion.
     $this->drupalPostForm(NULL, NULL, t('Cancel account'));
+    $this->waitBatchProccessToEnd();
+
     $this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
     $this->assertFalse(User::load($account->id()), 'User is not found in the database.');
   }
@@ -575,9 +592,10 @@ public function testMassUserCancelByAdmin() {
 
     // Confirm deletion.
     $this->drupalPostForm(NULL, NULL, t('Cancel accounts'));
+    $this->waitBatchProccessToEnd();
+
     $status = TRUE;
     foreach ($users as $account) {
-      $status = $status && (strpos($this->content, $account->getUsername() . '</em> has been deleted.') !== FALSE);
       $user_storage->resetCache([$account->id()]);
       $status = $status && !$user_storage->load($account->id());
     }
diff --git a/core/tests/Drupal/Tests/Traits/Core/MetaRefreshTrait.php b/core/tests/Drupal/Tests/Traits/Core/MetaRefreshTrait.php
new file mode 100644
index 0000000..1d9dbb8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Traits/Core/MetaRefreshTrait.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Drupal\Tests\Traits\Core;
+
+use Drupal\Component\Utility\Html;
+
+/**
+ * Allows tests redirect on meta refresh tag found in page.
+ */
+trait MetaRefreshTrait {
+
+  /**
+   * The number of meta refresh redirects to follow, or NULL if unlimited.
+   *
+   * @var null|int
+   */
+  protected $maximumMetaRefreshCount = NULL;
+
+  /**
+   * The number of meta refresh redirects followed during ::drupalGet().
+   *
+   * @var int
+   */
+  protected $metaRefreshCount = 0;
+
+  /**
+   * Checks for meta refresh tag and if found call drupalGet() recursively.
+   *
+   * This function looks for the http-equiv attribute to be set to "Refresh" and
+   * is case-sensitive.
+   *
+   * @return string|false
+   *   Either the new page content or FALSE.
+   */
+  protected function checkForMetaRefresh() {
+    $refresh = $this->cssSelect('meta[http-equiv="Refresh"]');
+    if (!empty($refresh) && (!isset($this->maximumMetaRefreshCount) || $this->metaRefreshCount < $this->maximumMetaRefreshCount)) {
+      // Parse the content attribute of the meta tag for the format:
+      // "[delay]: URL=[page_to_redirect_to]".
+      if (preg_match('/\d+;\s*URL=(?<url>.*)/i', $refresh[0]->getAttribute('content'), $match)) {
+        $this->metaRefreshCount++;
+        return $this->drupalGet($this->getAbsoluteUrl(Html::decodeEntities($match['url'])));
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Wait until batch process finish.
+   */
+  protected function waitBatchProccessToEnd() {
+    while ($this->checkForMetaRefresh()) {
+      // Do nothing. checkForMetaRefresh will return FALSE once batch process
+      // have finshed.
+    }
+  }
+
+}
