diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index e9d8d6686e..f9f97ecaa8 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -6,11 +6,13 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Development\ConfigSchemaChecker;
+use Drupal\Core\Database\Database;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\MissingDependencyException;
 use Drupal\Core\Serialization\Yaml;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Yaml\Yaml as SymfonyYaml;
@@ -448,4 +450,210 @@ protected function rebuildAll() {
     $this->container->get('stream_wrapper_manager')->register();
   }
 
+  /**
+   * Returns the parameters that will be used when Simpletest installs Drupal.
+   *
+   * @see install_drupal()
+   * @see install_state_defaults()
+   *
+   * @return array
+   *   Array of parameters for use in install_drupal().
+   */
+  protected function installParameters() {
+    $connection_info = Database::getConnectionInfo();
+    $driver = $connection_info['default']['driver'];
+    $connection_info['default']['prefix'] = $connection_info['default']['prefix']['default'];
+    unset($connection_info['default']['driver']);
+    unset($connection_info['default']['namespace']);
+    unset($connection_info['default']['pdo']);
+    unset($connection_info['default']['init_commands']);
+    // Remove database connection info that is not used by SQLite.
+    if ($driver === 'sqlite') {
+      unset($connection_info['default']['username']);
+      unset($connection_info['default']['password']);
+      unset($connection_info['default']['host']);
+      unset($connection_info['default']['port']);
+    }
+    $parameters = [
+      'interactive' => FALSE,
+      'parameters' => [
+        'profile' => $this->profile,
+        'langcode' => 'en',
+      ],
+      'forms' => [
+        'install_settings_form' => [
+          'driver' => $driver,
+          $driver => $connection_info['default'],
+        ],
+        'install_configure_form' => [
+          'site_name' => 'Drupal',
+          'site_mail' => 'simpletest@example.com',
+          'account' => [
+            'name' => $this->rootUser->name,
+            'mail' => $this->rootUser->getEmail(),
+            'pass' => [
+              'pass1' => isset($this->rootUser->pass_raw) ? $this->rootUser->pass_raw : $this->rootUser->passRaw,
+              'pass2' => isset($this->rootUser->pass_raw) ? $this->rootUser->pass_raw : $this->rootUser->passRaw,
+            ],
+          ],
+          // form_type_checkboxes_value() requires NULL instead of FALSE values
+          // for programmatic form submissions to disable a checkbox.
+          'enable_update_status_module' => NULL,
+          'enable_update_status_emails' => NULL,
+        ],
+      ],
+    ];
+
+    // If we only have one db driver available, we cannot set the driver.
+    include_once DRUPAL_ROOT . '/core/includes/install.inc';
+    if (count($this->getDatabaseTypes()) == 1) {
+      unset($parameters['forms']['install_settings_form']['driver']);
+    }
+    return $parameters;
+  }
+
+  /**
+   * Sets up the base URL based upon the environment variable.
+   *
+   * @throws \Exception
+   *   Thrown when no SIMPLETEST_BASE_URL environment variable is provided.
+   */
+  protected function setupBaseUrl() {
+    global $base_url;
+
+    // Get and set the domain of the environment we are running our test
+    // coverage against.
+    $base_url = getenv('SIMPLETEST_BASE_URL');
+    if (!$base_url) {
+      throw new \Exception(
+        'You must provide a SIMPLETEST_BASE_URL environment variable to run some PHPUnit based functional tests.'
+      );
+    }
+
+    // Setup $_SERVER variable.
+    $parsed_url = parse_url($base_url);
+    $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '');
+    $path = isset($parsed_url['path']) ? rtrim(rtrim($parsed_url['path']), '/') : '';
+    $port = isset($parsed_url['port']) ? $parsed_url['port'] : 80;
+
+    $this->baseUrl = $base_url;
+
+    // If the passed URL schema is 'https' then setup the $_SERVER variables
+    // properly so that testing will run under HTTPS.
+    if ($parsed_url['scheme'] === 'https') {
+      $_SERVER['HTTPS'] = 'on';
+    }
+    $_SERVER['HTTP_HOST'] = $host;
+    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+    $_SERVER['SERVER_ADDR'] = '127.0.0.1';
+    $_SERVER['SERVER_PORT'] = $port;
+    $_SERVER['SERVER_SOFTWARE'] = NULL;
+    $_SERVER['SERVER_NAME'] = 'localhost';
+    $_SERVER['REQUEST_URI'] = $path . '/';
+    $_SERVER['REQUEST_METHOD'] = 'GET';
+    $_SERVER['SCRIPT_NAME'] = $path . '/index.php';
+    $_SERVER['SCRIPT_FILENAME'] = $path . '/index.php';
+    $_SERVER['PHP_SELF'] = $path . '/index.php';
+    $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
+  }
+
+  /**
+   * Prepares the current environment for running the test.
+   *
+   * Also sets up new resources for the testing environment, such as the public
+   * filesystem and configuration directories.
+   *
+   * This method is private as it must only be called once by
+   * BrowserTestBase::setUp() (multiple invocations for the same test would have
+   * unpredictable consequences) and it must not be callable or overridable by
+   * test classes.
+   */
+  protected function prepareEnvironment() {
+    // Bootstrap Drupal so we can use Drupal's built in functions.
+    $this->classLoader = require __DIR__ . '/../../../../../autoload.php';
+    $request = Request::createFromGlobals();
+    $kernel = TestRunnerKernel::createFromRequest($request, $this->classLoader);
+    // TestRunnerKernel expects the working directory to be DRUPAL_ROOT.
+    chdir(DRUPAL_ROOT);
+    $kernel->prepareLegacyRequest($request);
+    $this->prepareDatabasePrefix();
+
+    $this->originalSite = $kernel->findSitePath($request);
+
+    // Create test directory ahead of installation so fatal errors and debug
+    // information can be logged during installation process.
+    file_prepare_directory($this->siteDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+    // Prepare filesystem directory paths.
+    $this->publicFilesDirectory = $this->siteDirectory . '/files';
+    $this->privateFilesDirectory = $this->siteDirectory . '/private';
+    $this->tempFilesDirectory = $this->siteDirectory . '/temp';
+    $this->translationFilesDirectory = $this->siteDirectory . '/translations';
+
+    // Ensure the configImporter is refreshed for each test.
+    $this->configImporter = NULL;
+
+    // Unregister all custom stream wrappers of the parent site.
+    $wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers(StreamWrapperInterface::ALL);
+    foreach ($wrappers as $scheme => $info) {
+      stream_wrapper_unregister($scheme);
+    }
+
+    // Reset statics.
+    drupal_static_reset();
+
+    $this->container = NULL;
+
+    // Unset globals.
+    unset($GLOBALS['config_directories']);
+    unset($GLOBALS['config']);
+    unset($GLOBALS['conf']);
+
+    // Log fatal errors.
+    ini_set('log_errors', 1);
+    ini_set('error_log', DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
+
+    // Change the database prefix.
+    $this->changeDatabasePrefix();
+
+    // After preparing the environment and changing the database prefix, we are
+    // in a valid test environment.
+    drupal_valid_test_ua($this->databasePrefix);
+
+    // Reset settings.
+    new Settings([
+      // For performance, simply use the database prefix as hash salt.
+      'hash_salt' => $this->databasePrefix,
+    ]);
+
+    drupal_set_time_limit($this->timeLimit);
+
+    // Save and clean the shutdown callbacks array because it is static cached
+    // and will be changed by the test run. Otherwise it will contain callbacks
+    // from both environments and the testing environment will try to call the
+    // handlers defined by the original one.
+    $callbacks = &drupal_register_shutdown_function();
+    $this->originalShutdownCallbacks = $callbacks;
+    $callbacks = [];
+  }
+
+  /**
+   * Returns all supported database driver installer objects.
+   *
+   * This wraps drupal_get_database_types() for use without a current container.
+   *
+   * @return \Drupal\Core\Database\Install\Tasks[]
+   *   An array of available database driver installer objects.
+   */
+  protected function getDatabaseTypes() {
+    if ($this->originalContainer) {
+      \Drupal::setContainer($this->originalContainer);
+    }
+    $database_types = drupal_get_database_types();
+    if ($this->originalContainer) {
+      \Drupal::unsetContainer();
+    }
+    return $database_types;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Test/TestSetupTrait.php b/core/lib/Drupal/Core/Test/TestSetupTrait.php
index ea9137e479..44409078db 100644
--- a/core/lib/Drupal/Core/Test/TestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/TestSetupTrait.php
@@ -141,7 +141,7 @@ public static function getDatabaseConnection() {
    * @see \Drupal\simpletest\TestBase::prepareEnvironment()
    * @see drupal_valid_test_ua()
    */
-  private function prepareDatabasePrefix() {
+  protected function prepareDatabasePrefix() {
     $test_db = new TestDatabase();
     $this->siteDirectory = $test_db->getTestSitePath();
     $this->databasePrefix = $test_db->getDatabasePrefix();
@@ -150,7 +150,7 @@ private function prepareDatabasePrefix() {
   /**
    * Changes the database connection to the prefixed one.
    */
-  private function changeDatabasePrefix() {
+  protected function changeDatabasePrefix() {
     if (empty($this->databasePrefix)) {
       $this->prepareDatabasePrefix();
     }
@@ -158,7 +158,7 @@ private function changeDatabasePrefix() {
     // If the test is run with argument dburl then use it.
     $db_url = getenv('SIMPLETEST_DB');
     if (!empty($db_url)) {
-      $database = Database::convertDbUrlToConnectionInfo($db_url, DRUPAL_ROOT);
+      $database = Database::convertDbUrlToConnectionInfo($db_url, isset($this->root) ? $this->root : DRUPAL_ROOT);
       Database::addConnectionInfo('default', 'default', $database);
     }
 
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 975d95bd9a..3fbcfe4023 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -8,7 +8,6 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Core\Database\Database;
 use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
 use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
 use Drupal\Core\Session\AccountInterface;
@@ -390,69 +389,6 @@ protected function setUp() {
   }
 
   /**
-   * Returns the parameters that will be used when Simpletest installs Drupal.
-   *
-   * @see install_drupal()
-   * @see install_state_defaults()
-   *
-   * @return array
-   *   Array of parameters for use in install_drupal().
-   */
-  protected function installParameters() {
-    $connection_info = Database::getConnectionInfo();
-    $driver = $connection_info['default']['driver'];
-    $connection_info['default']['prefix'] = $connection_info['default']['prefix']['default'];
-    unset($connection_info['default']['driver']);
-    unset($connection_info['default']['namespace']);
-    unset($connection_info['default']['pdo']);
-    unset($connection_info['default']['init_commands']);
-    // Remove database connection info that is not used by SQLite.
-    if ($driver == 'sqlite') {
-      unset($connection_info['default']['username']);
-      unset($connection_info['default']['password']);
-      unset($connection_info['default']['host']);
-      unset($connection_info['default']['port']);
-    }
-    $parameters = [
-      'interactive' => FALSE,
-      'parameters' => [
-        'profile' => $this->profile,
-        'langcode' => 'en',
-      ],
-      'forms' => [
-        'install_settings_form' => [
-          'driver' => $driver,
-          $driver => $connection_info['default'],
-        ],
-        'install_configure_form' => [
-          'site_name' => 'Drupal',
-          'site_mail' => 'simpletest@example.com',
-          'account' => [
-            'name' => $this->rootUser->name,
-            'mail' => $this->rootUser->getEmail(),
-            'pass' => [
-              'pass1' => $this->rootUser->pass_raw,
-              'pass2' => $this->rootUser->pass_raw,
-            ],
-          ],
-          // \Drupal\Core\Render\Element\Checkboxes::valueCallback() requires
-          // NULL instead of FALSE values for programmatic form submissions to
-          // disable a checkbox.
-          'enable_update_status_module' => NULL,
-          'enable_update_status_emails' => NULL,
-        ],
-      ],
-    ];
-
-    // If we only have one db driver available, we cannot set the driver.
-    include_once DRUPAL_ROOT . '/core/includes/install.inc';
-    if (count($this->getDatabaseTypes()) == 1) {
-      unset($parameters['forms']['install_settings_form']['driver']);
-    }
-    return $parameters;
-  }
-
-  /**
    * Preserve the original batch, and instantiate the test batch.
    */
   protected function setBatch() {
@@ -480,21 +416,6 @@ protected function restoreBatch() {
   }
 
   /**
-   * Returns all supported database driver installer objects.
-   *
-   * This wraps drupal_get_database_types() for use without a current container.
-   *
-   * @return \Drupal\Core\Database\Install\Tasks[]
-   *   An array of available database driver installer objects.
-   */
-  protected function getDatabaseTypes() {
-    \Drupal::setContainer($this->originalContainer);
-    $database_types = drupal_get_database_types();
-    \Drupal::unsetContainer();
-    return $database_types;
-  }
-
-  /**
    * Queues custom translations to be written to settings.php.
    *
    * Use WebTestBase::writeCustomTranslations() to apply and write the queued
diff --git a/core/modules/system/src/Tests/Update/DbUpdatesTrait.php b/core/modules/system/src/Tests/Update/DbUpdatesTrait.php
index 2218568250..8a8ae84680 100644
--- a/core/modules/system/src/Tests/Update/DbUpdatesTrait.php
+++ b/core/modules/system/src/Tests/Update/DbUpdatesTrait.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\system\Tests\Update;
 
+@trigger_error(__NAMESPACE__ . '\DbUpdatesTrait is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use \Drupal\FunctionalTests\Update\DbUpdatesTrait instead. See https://www.drupal.org/node/2896640.', E_USER_DEPRECATED);
+
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
 
@@ -10,6 +12,10 @@
  * pending db updates through the Update UI.
  *
  * This should be used only by classes extending \Drupal\simpletest\WebTestBase.
+ *
+ * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0.
+ *   Use \Drupal\FunctionalTests\Update\DbUpdatesTrait.
+ * @see https://www.drupal.org/node/2896640
  */
 trait DbUpdatesTrait {
 
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index f7f88c6486..16a4295e6c 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\system\Tests\Update;
 
+@trigger_error(__NAMESPACE__ . '\UpdatePathTestBase is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use \Drupal\FunctionalTests\Update\UpdatePathTestBase instead. See https://www.drupal.org/node/2896640.', E_USER_DEPRECATED);
+
 use Drupal\Component\Utility\Crypt;
 use Drupal\Tests\SchemaCheckTestTrait;
 use Drupal\Core\Database\Database;
@@ -34,6 +36,10 @@
  *
  * @ingroup update_api
  *
+ * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0.
+ *   Use \Drupal\FunctionalTests\Update\UpdatePathTestBase.
+ * @see https://www.drupal.org/node/2896640
+ *
  * @see hook_update_N()
  */
 abstract class UpdatePathTestBase extends WebTestBase {
diff --git a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php b/core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithAutomatedCronTest.php
similarity index 77%
rename from core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php
rename to core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithAutomatedCronTest.php
index a2f480ed51..50926c935c 100644
--- a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php
+++ b/core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithAutomatedCronTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Ensures that the automated cron module is installed on update.
@@ -14,7 +16,7 @@ class AutomatedCronUpdateWithAutomatedCronTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php b/core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
similarity index 69%
rename from core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
rename to core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
index 9f76ebd9a4..d4ac71188e 100644
--- a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
+++ b/core/modules/system/tests/src/Functional/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Ensures that the automated cron module is not installed on update.
@@ -14,8 +16,8 @@ class AutomatedCronUpdateWithoutAutomatedCronTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.without_automated_cron.php',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.without_automated_cron.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/ConfigOverridesUpdateTest.php b/core/modules/system/tests/src/Functional/Update/ConfigOverridesUpdateTest.php
similarity index 89%
rename from core/modules/system/src/Tests/Update/ConfigOverridesUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/ConfigOverridesUpdateTest.php
index 6efa3182d6..bab7d49417 100644
--- a/core/modules/system/src/Tests/Update/ConfigOverridesUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/ConfigOverridesUpdateTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_update_8200().
@@ -16,8 +18,8 @@ class ConfigOverridesUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.filled.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.config-override-fix.php',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.config-override-fix.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/DbUpdatesTrait.php b/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
similarity index 92%
copy from core/modules/system/src/Tests/Update/DbUpdatesTrait.php
copy to core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
index 2218568250..cb6ae4bd47 100644
--- a/core/modules/system/src/Tests/Update/DbUpdatesTrait.php
+++ b/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
@@ -9,7 +9,7 @@
  * Provides methods to conditionally enable db update functions and apply
  * pending db updates through the Update UI.
  *
- * This should be used only by classes extending \Drupal\simpletest\WebTestBase.
+ * This should be used only by classes extending \Drupal\Tests\BrowserTestBase.
  */
 trait DbUpdatesTrait {
 
diff --git a/core/modules/system/src/Tests/Update/DependencyHookInvocationTest.php b/core/modules/system/tests/src/Functional/Update/DependencyHookInvocationTest.php
similarity index 89%
rename from core/modules/system/src/Tests/Update/DependencyHookInvocationTest.php
rename to core/modules/system/tests/src/Functional/Update/DependencyHookInvocationTest.php
index ef22f0e1b3..8ff7b883db 100644
--- a/core/modules/system/src/Tests/Update/DependencyHookInvocationTest.php
+++ b/core/modules/system/tests/src/Functional/Update/DependencyHookInvocationTest.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that the hook invocation for determining update dependencies works
@@ -10,7 +10,7 @@
  *
  * @group Update
  */
-class DependencyHookInvocationTest extends WebTestBase {
+class DependencyHookInvocationTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/core/modules/system/src/Tests/Update/DependencyMissingTest.php b/core/modules/system/tests/src/Functional/Update/DependencyMissingTest.php
similarity index 89%
rename from core/modules/system/src/Tests/Update/DependencyMissingTest.php
rename to core/modules/system/tests/src/Functional/Update/DependencyMissingTest.php
index 407ef33608..6ae4dc40c8 100644
--- a/core/modules/system/src/Tests/Update/DependencyMissingTest.php
+++ b/core/modules/system/tests/src/Functional/Update/DependencyMissingTest.php
@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that missing update dependencies are correctly flagged.
  *
  * @group Update
  */
-class DependencyMissingTest extends WebTestBase {
+class DependencyMissingTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/core/modules/system/src/Tests/Update/DependencyOrderingTest.php b/core/modules/system/tests/src/Functional/Update/DependencyOrderingTest.php
similarity index 93%
rename from core/modules/system/src/Tests/Update/DependencyOrderingTest.php
rename to core/modules/system/tests/src/Functional/Update/DependencyOrderingTest.php
index 8616fb6ba9..8cafaaddba 100644
--- a/core/modules/system/src/Tests/Update/DependencyOrderingTest.php
+++ b/core/modules/system/tests/src/Functional/Update/DependencyOrderingTest.php
@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that update functions are run in the proper order.
  *
  * @group Update
  */
-class DependencyOrderingTest extends WebTestBase {
+class DependencyOrderingTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/core/modules/system/src/Tests/Update/FieldSchemaDataUninstallUpdateTest.php b/core/modules/system/tests/src/Functional/Update/FieldSchemaDataUninstallUpdateTest.php
similarity index 77%
rename from core/modules/system/src/Tests/Update/FieldSchemaDataUninstallUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/FieldSchemaDataUninstallUpdateTest.php
index 6c5d2f2448..782e3410f9 100644
--- a/core/modules/system/src/Tests/Update/FieldSchemaDataUninstallUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/FieldSchemaDataUninstallUpdateTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the upgrade path after fixing field schema data uninstallation.
@@ -16,9 +18,9 @@ class FieldSchemaDataUninstallUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.block-content-uninstall.php',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.field-schema-data-uninstall-2573667.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.block-content-uninstall.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.field-schema-data-uninstall-2573667.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/FilterHtmlUpdateTest.php b/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
similarity index 89%
rename from core/modules/system/src/Tests/Update/FilterHtmlUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
index 892b279b70..09e40aa983 100644
--- a/core/modules/system/src/Tests/Update/FilterHtmlUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\filter\Entity\FilterFormat;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests that the allowed html configutations are updated with attributes.
@@ -16,7 +17,7 @@ class FilterHtmlUpdateTest extends UpdatePathTestBase {
    */
   public function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/InstallProfileSystemInstall8300Test.php b/core/modules/system/tests/src/Functional/Update/InstallProfileSystemInstall8300Test.php
similarity index 87%
rename from core/modules/system/src/Tests/Update/InstallProfileSystemInstall8300Test.php
rename to core/modules/system/tests/src/Functional/Update/InstallProfileSystemInstall8300Test.php
index f0eabd62ec..623f88047e 100644
--- a/core/modules/system/src/Tests/Update/InstallProfileSystemInstall8300Test.php
+++ b/core/modules/system/tests/src/Functional/Update/InstallProfileSystemInstall8300Test.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\Site\Settings;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_update_8300().
@@ -16,7 +17,7 @@ class InstallProfileSystemInstall8300Test extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/InvalidUpdateHookTest.php b/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
similarity index 89%
rename from core/modules/system/src/Tests/Update/InvalidUpdateHookTest.php
rename to core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
index 59c64f6240..44d4832dd2 100644
--- a/core/modules/system/src/Tests/Update/InvalidUpdateHookTest.php
+++ b/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that a module implementing hook_update_8000() causes an error to be
@@ -10,7 +10,7 @@
  *
  * @group Update
  */
-class InvalidUpdateHookTest extends WebTestBase {
+class InvalidUpdateHookTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/core/modules/system/src/Tests/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php b/core/modules/system/tests/src/Functional/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php
similarity index 90%
rename from core/modules/system/src/Tests/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php
index ee47a81d52..a54bb6d1de 100644
--- a/core/modules/system/src/Tests/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/LocalActionsAndTasksConvertedIntoBlocksUpdateTest.php
@@ -1,7 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 use Drupal\node\Entity\Node;
 
 /**
@@ -18,8 +19,8 @@ class LocalActionsAndTasksConvertedIntoBlocksUpdateTest extends UpdatePathTestBa
    */
   public function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.local-actions-tasks-into-blocks-507488.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.local-actions-tasks-into-blocks-507488.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleFilledTest.php b/core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleFilledTest.php
similarity index 65%
rename from core/modules/system/src/Tests/Update/MenuTreeSerializationTitleFilledTest.php
rename to core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleFilledTest.php
index 35f1151cc7..5bf07d8492 100644
--- a/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleFilledTest.php
+++ b/core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleFilledTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 /**
  * Runs MenuTreeSerializationTitleTest with a dump filled with content.
@@ -14,7 +14,7 @@ class MenuTreeSerializationTitleFilledTest extends MenuTreeSerializationTitleTes
    */
   protected function setDatabaseDumpFiles() {
     parent::setDatabaseDumpFiles();
-    $this->databaseDumpFiles[0] = __DIR__ . '/../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
+    $this->databaseDumpFiles[0] = __DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
   }
 
 }
diff --git a/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php b/core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleTest.php
similarity index 90%
rename from core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php
rename to core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleTest.php
index cc019dc284..0df71482ba 100644
--- a/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php
+++ b/core/modules/system/tests/src/Functional/Update/MenuTreeSerializationTitleTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_update_8001().
@@ -16,7 +17,7 @@ class MenuTreeSerializationTitleTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php b/core/modules/system/tests/src/Functional/Update/PageTitleConvertedIntoBlockUpdateTest.php
similarity index 87%
rename from core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/PageTitleConvertedIntoBlockUpdateTest.php
index 6a81566ea3..2f7306a7c5 100644
--- a/core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/PageTitleConvertedIntoBlockUpdateTest.php
@@ -1,7 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 use Drupal\node\Entity\Node;
 
 /**
@@ -18,8 +19,8 @@ class PageTitleConvertedIntoBlockUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/RecalculatedDependencyTest.php b/core/modules/system/tests/src/Functional/Update/RecalculatedDependencyTest.php
similarity index 92%
rename from core/modules/system/src/Tests/Update/RecalculatedDependencyTest.php
rename to core/modules/system/tests/src/Functional/Update/RecalculatedDependencyTest.php
index 56a010c020..6eb51a2a51 100644
--- a/core/modules/system/src/Tests/Update/RecalculatedDependencyTest.php
+++ b/core/modules/system/tests/src/Functional/Update/RecalculatedDependencyTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_post_update_recalculate_dependencies_for_installed_config_entities().
@@ -14,7 +16,7 @@ class RecalculatedDependencyTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php b/core/modules/system/tests/src/Functional/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php
similarity index 81%
rename from core/modules/system/src/Tests/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php
rename to core/modules/system/tests/src/Functional/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php
index 143b5c6ae4..b2ccfe6795 100644
--- a/core/modules/system/src/Tests/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php
+++ b/core/modules/system/tests/src/Functional/Update/RemoveResponseGzipFromSystemPerformanceConfigurationTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Ensures that response.gzip is removed from system.performance configuration.
@@ -14,7 +16,7 @@ class RemoveResponseGzipFromSystemPerformanceConfigurationTest extends UpdatePat
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/RouterIndexOptimizationFilledTest.php b/core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationFilledTest.php
similarity index 65%
rename from core/modules/system/src/Tests/Update/RouterIndexOptimizationFilledTest.php
rename to core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationFilledTest.php
index 264fa05430..afb48108f5 100644
--- a/core/modules/system/src/Tests/Update/RouterIndexOptimizationFilledTest.php
+++ b/core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationFilledTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 /**
  * Runs RouterIndexOptimizationTest with a dump filled with content.
@@ -14,7 +14,7 @@ class RouterIndexOptimizationFilledTest extends RouterIndexOptimizationTest {
    */
   protected function setDatabaseDumpFiles() {
     parent::setDatabaseDumpFiles();
-    $this->databaseDumpFiles[0] = __DIR__ . '/../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
+    $this->databaseDumpFiles[0] = __DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
   }
 
 }
diff --git a/core/modules/system/src/Tests/Update/RouterIndexOptimizationTest.php b/core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationTest.php
similarity index 78%
rename from core/modules/system/src/Tests/Update/RouterIndexOptimizationTest.php
rename to core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationTest.php
index 0bede3a2a4..a3bfad2562 100644
--- a/core/modules/system/src/Tests/Update/RouterIndexOptimizationTest.php
+++ b/core/modules/system/tests/src/Functional/Update/RouterIndexOptimizationTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_update_8002().
@@ -13,7 +15,7 @@ class RouterIndexOptimizationTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php b/core/modules/system/tests/src/Functional/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php
similarity index 82%
rename from core/modules/system/src/Tests/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php
index b61cf20d4b..341b37be12 100644
--- a/core/modules/system/src/Tests/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the upgrade path for converting seven secondary local tasks into a block.
@@ -16,8 +18,8 @@ class SevenSecondaryLocalTasksConvertedIntoBlockUpdateTest extends UpdatePathTes
    */
   public function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.seven-secondary-local-tasks-block-2569529.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.seven-secondary-local-tasks-block-2569529.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/SiteBrandingConvertedIntoBlockUpdateTest.php b/core/modules/system/tests/src/Functional/Update/SiteBrandingConvertedIntoBlockUpdateTest.php
similarity index 86%
rename from core/modules/system/src/Tests/Update/SiteBrandingConvertedIntoBlockUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/SiteBrandingConvertedIntoBlockUpdateTest.php
index c60c2b0dc8..d904e10ed1 100644
--- a/core/modules/system/src/Tests/Update/SiteBrandingConvertedIntoBlockUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/SiteBrandingConvertedIntoBlockUpdateTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the upgrade path for page site variables being converted into a block.
@@ -14,8 +16,8 @@ class SiteBrandingConvertedIntoBlockUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.site-branding-into-block-2005546.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.site-branding-into-block-2005546.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/StableBaseThemeUpdateTest.php b/core/modules/system/tests/src/Functional/Update/StableBaseThemeUpdateTest.php
similarity index 78%
rename from core/modules/system/src/Tests/Update/StableBaseThemeUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/StableBaseThemeUpdateTest.php
index b71d47bfc8..326bbbb9a6 100644
--- a/core/modules/system/src/Tests/Update/StableBaseThemeUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/StableBaseThemeUpdateTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the upgrade path for introducing the Stable base theme.
@@ -23,8 +25,8 @@ class StableBaseThemeUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.stable-base-theme-2575421.php',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.stable-base-theme-2575421.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/UpdateEntityDisplayTest.php b/core/modules/system/tests/src/Functional/Update/UpdateEntityDisplayTest.php
similarity index 88%
rename from core/modules/system/src/Tests/Update/UpdateEntityDisplayTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdateEntityDisplayTest.php
index 0a2cbf45bb..698d331099 100644
--- a/core/modules/system/src/Tests/Update/UpdateEntityDisplayTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateEntityDisplayTest.php
@@ -1,9 +1,10 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests system_post_update_add_region_to_entity_displays().
@@ -17,7 +18,7 @@ class UpdateEntityDisplayTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseFilledTest.php
similarity index 98%
rename from core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseFilledTest.php
index 9ee6d0cd4d..7573fc4a92 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseFilledTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
@@ -18,7 +18,7 @@ class UpdatePathRC1TestBaseFilledTest extends UpdatePathRC1TestBaseTest {
    */
   protected function setDatabaseDumpFiles() {
     parent::setDatabaseDumpFiles();
-    $this->databaseDumpFiles[0] = __DIR__ . '/../../../tests/fixtures/update/drupal-8-rc1.filled.standard.php.gz';
+    $this->databaseDumpFiles[0] = __DIR__ . '/../../../../tests/fixtures/update/drupal-8-rc1.filled.standard.php.gz';
   }
 
   /**
@@ -89,7 +89,7 @@ public function testUpdatedSite() {
 
     // Log in as user 1.
     $account = User::load(1);
-    $account->pass_raw = 'drupal';
+    $account->passRaw = 'drupal';
     $this->drupalLogin($account);
 
     // Make sure we can see the access-restricted entity reference field
diff --git a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseTest.php
similarity index 92%
rename from core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseTest.php
index a4f99e685c..4077a07d2b 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathRC1TestBaseTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Component\Render\FormattableMarkup;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the update path base class with the RC1 database dump.
@@ -21,7 +22,7 @@ class UpdatePathRC1TestBaseTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathTestBaseFilledTest.php
similarity index 98%
rename from core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathTestBaseFilledTest.php
index 3c5aab057e..2ed58fbabc 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathTestBaseFilledTest.php
@@ -1,7 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
+use Drupal\FunctionalTests\Update\UpdatePathTestBaseTest;
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
 use Drupal\user\Entity\User;
@@ -18,7 +19,7 @@ class UpdatePathTestBaseFilledTest extends UpdatePathTestBaseTest {
    */
   protected function setDatabaseDumpFiles() {
     parent::setDatabaseDumpFiles();
-    $this->databaseDumpFiles[0] = __DIR__ . '/../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
+    $this->databaseDumpFiles[0] = __DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
   }
 
   /**
@@ -89,7 +90,7 @@ public function testUpdatedSite() {
 
     // Log in as user 1.
     $account = User::load(1);
-    $account->pass_raw = 'drupal';
+    $account->passRaw = 'drupal';
     $this->drupalLogin($account);
 
     // Make sure we can see the access-restricted entity reference field
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestJavaScriptTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathTestJavaScriptTest.php
similarity index 79%
rename from core/modules/system/src/Tests/Update/UpdatePathTestJavaScriptTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathTestJavaScriptTest.php
index 90f3387a6c..e30915e76e 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestJavaScriptTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathTestJavaScriptTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the presence of JavaScript at update.php.
@@ -14,7 +16,7 @@ class UpdatePathTestJavaScriptTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
     ];
   }
 
@@ -35,12 +37,12 @@ protected function doSelectionTest() {
     $scripts = $this->xpath('//script');
     $found = FALSE;
     foreach ($scripts as $script) {
-      if (!isset($script['src'])) {
+      if (!$script->getAttribute('src')) {
         continue;
       }
       // Source is a root-relative URL. Transform it to an absolute URL to allow
       // file_get_contents() to access the file.
-      $src = preg_replace('#^' . $GLOBALS['base_path'] . '(.*)#i', $GLOBALS['base_url'] . '/' . '${1}', (string) $script['src']);
+      $src = preg_replace('#^' . $GLOBALS['base_path'] . '(.*)#i', $GLOBALS['base_url'] . '/' . '${1}', $script->getAttribute('src'));
       $file_content = file_get_contents($src);
 
       if (strpos($file_content, 'window.drupalSettings =') !== FALSE) {
diff --git a/core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingFilledTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingFilledTest.php
similarity index 65%
rename from core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingFilledTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingFilledTest.php
index 147c8c0482..0e81ad479f 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingFilledTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingFilledTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 /**
  * Runs UpdatePathWithBrokenRoutingTest with a dump filled with content.
@@ -14,7 +14,7 @@ class UpdatePathWithBrokenRoutingFilledTest extends UpdatePathWithBrokenRoutingT
    */
   protected function setDatabaseDumpFiles() {
     parent::setDatabaseDumpFiles();
-    $this->databaseDumpFiles[0] = __DIR__ . '/../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
+    $this->databaseDumpFiles[0] = __DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz';
   }
 
 }
diff --git a/core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingTest.php
similarity index 56%
rename from core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingTest.php
index e710a4ecaf..1c8493d946 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathWithBrokenRoutingTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePathWithBrokenRoutingTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests the update path with a broken router.
@@ -14,8 +16,8 @@ class UpdatePathWithBrokenRoutingTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.broken_routing.php',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.broken_routing.php',
     ];
   }
 
@@ -30,16 +32,6 @@ public function testWithBrokenRouting() {
     $this->drupalGet('<front>');
     $this->assertResponse(500);
 
-    // The exceptions are expected. Do not interpret them as a test failure.
-    // Not using File API; a potential error must trigger a PHP warning.
-    unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
-    foreach ($this->assertions as $key => $assertion) {
-      if (strpos($assertion['message'], 'core/modules/system/tests/modules/update_script_test/src/PathProcessor/BrokenInboundPathProcessor.php') !== FALSE) {
-        unset($this->assertions[$key]);
-        $this->deleteAssert($assertion['message_id']);
-      }
-    }
-
     $this->runUpdates();
 
     // Remove the simulation of the broken router, and make sure we can get to
diff --git a/core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateFailingTest.php
similarity index 74%
rename from core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePostUpdateFailingTest.php
index dba67eaaec..03b5d7b0ec 100644
--- a/core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateFailingTest.php
@@ -1,6 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests hook_post_update() when there are failing update hooks.
@@ -14,8 +16,8 @@ class UpdatePostUpdateFailingTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php',
     ];
   }
 
@@ -32,7 +34,7 @@ public function testPostUpdate() {
     $this->assertIdentical([], \Drupal::state()->get('post_update_test_execution', []));
 
     $key_value = \Drupal::keyValue('update__post_update');
-    $this->assertEqual([], $key_value->get('existing_updates'));
+    $this->assertEqual([], $key_value->get('existing_updates', []));
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Update/UpdatePostUpdateTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
similarity index 90%
rename from core/modules/system/src/Tests/Update/UpdatePostUpdateTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
index c50b1d45f4..1bba498d08 100644
--- a/core/modules/system/src/Tests/Update/UpdatePostUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Component\Render\FormattableMarkup;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests hook_post_update().
@@ -16,8 +17,8 @@ class UpdatePostUpdateTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.update-test-postupdate-enabled.php',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.update-test-postupdate-enabled.php',
     ];
   }
 
diff --git a/core/modules/system/src/Tests/Update/UpdateSchemaTest.php b/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
similarity index 91%
rename from core/modules/system/src/Tests/Update/UpdateSchemaTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
index 0e42c9d5e5..a42cbcb3c2 100644
--- a/core/modules/system/src/Tests/Update/UpdateSchemaTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
@@ -1,16 +1,16 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\Url;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that update hooks are properly run.
  *
  * @group Update
  */
-class UpdateSchemaTest extends WebTestBase {
+class UpdateSchemaTest extends BrowserTestBase {
 
   /**
    * {@inheritdoc}
@@ -57,6 +57,7 @@ public function testUpdateHooks() {
     $this->assertRaw('Schema version 8001.');
     // Run the update hooks.
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
 
     // Ensure schema has changed.
     $this->assertEqual(drupal_get_installed_schema_version('update_test_schema', TRUE), 8001);
diff --git a/core/modules/system/src/Tests/Update/UpdateScriptTest.php b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
similarity index 95%
rename from core/modules/system/src/Tests/Update/UpdateScriptTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
index ed076b8156..5f5ed800fa 100644
--- a/core/modules/system/src/Tests/Update/UpdateScriptTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
@@ -1,17 +1,17 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Core\Url;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests the update script access and functionality.
  *
  * @group Update
  */
-class UpdateScriptTest extends WebTestBase {
+class UpdateScriptTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
@@ -119,6 +119,7 @@ public function testRequirements() {
     $this->assertNoText('This is a requirements warning provided by the update_script_test module.');
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
     $this->assertText(t('The update_script_test_update_8001() update was executed successfully.'), 'End of update process was reached.');
     // Confirm that all caches were cleared.
     $this->assertText(t('hook_cache_flush() invoked for update_script_test.module.'), 'Caches were cleared after resolving a requirements warning and applying updates.');
@@ -167,7 +168,7 @@ public function testNoUpdateFunctionality() {
     $this->clickLink(t('Continue'));
     $this->assertText(t('No pending updates.'));
     $this->assertNoLink('Administration pages');
-    $this->assertNoLinkByHrefInMainRegion('update.php', 0);
+    $this->assertEmpty($this->xpath('//main//a[contains(@href, :href)]', [':href' => 'update.php']));
     $this->clickLink('Front page');
     $this->assertResponse(200);
 
@@ -178,7 +179,7 @@ public function testNoUpdateFunctionality() {
     $this->clickLink(t('Continue'));
     $this->assertText(t('No pending updates.'));
     $this->assertLink('Administration pages');
-    $this->assertNoLinkByHrefInMainRegion('update.php', 1);
+    $this->assertEmpty($this->xpath('//main//a[contains(@href, :href)]', [':href' => 'update.php']));
     $this->clickLink('Administration pages');
     $this->assertResponse(200);
   }
@@ -209,10 +210,11 @@ public function testSuccessfulUpdateFunctionality() {
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
     $this->assertText('Updates were attempted.');
     $this->assertLink('logged');
     $this->assertLink('Administration pages');
-    $this->assertNoLinkByHrefInMainRegion('update.php', 1);
+    $this->assertEmpty($this->xpath('//main//a[contains(@href, :href)]', [':href' => 'update.php']));
     $this->clickLink('Administration pages');
     $this->assertResponse(200);
   }
@@ -275,10 +277,11 @@ public function testSuccessfulMultilingualUpdateFunctionality() {
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
     $this->assertText('Updates were attempted.');
     $this->assertLink('logged');
     $this->assertLink('Administration pages');
-    $this->assertNoLinkByHrefInMainRegion('update.php', 1);
+    $this->assertEmpty($this->xpath('//main//a[contains(@href, :href)]', [':href' => 'update.php']));
     $this->clickLink('Administration pages');
     $this->assertResponse(200);
   }
@@ -306,6 +309,7 @@ protected function updateScriptTest($maintenance_mode) {
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
 
     // Verify that updates were completed successfully.
     $this->assertText('Updates were attempted.');
@@ -318,7 +322,7 @@ protected function updateScriptTest($maintenance_mode) {
 
     // Verify that there are no links to different parts of the workflow.
     $this->assertNoLink('Administration pages');
-    $this->assertNoLinkByHrefInMainRegion('update.php', 0);
+    $this->assertEmpty($this->xpath('//main//a[contains(@href, :href)]', [':href' => 'update.php']));
     $this->assertNoLink('logged');
 
     // Verify the front page can be visited following the upgrade.
diff --git a/core/modules/system/src/Tests/Update/UpdatesWith7xTest.php b/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
similarity index 91%
rename from core/modules/system/src/Tests/Update/UpdatesWith7xTest.php
rename to core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
index c2035d1335..2452264e37 100644
--- a/core/modules/system/src/Tests/Update/UpdatesWith7xTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\Tests\system\Functional\Update;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that the minimum schema version is correct even if only 7.x update
@@ -10,7 +10,7 @@
  *
  * @group Update
  */
-class UpdatesWith7xTest extends WebTestBase {
+class UpdatesWith7xTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
similarity index 73%
copy from core/modules/system/src/Tests/Update/UpdatePathTestBase.php
copy to core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index f7f88c6486..6b234afcd3 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -1,14 +1,20 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\FunctionalTests\Update;
 
+use Behat\Mink\Driver\GoutteDriver;
+use Behat\Mink\Mink;
+use Behat\Mink\Selector\SelectorsHandler;
+use Behat\Mink\Session;
 use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Test\TestRunnerKernel;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\HiddenFieldSelector;
 use Drupal\Tests\SchemaCheckTestTrait;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Url;
-use Drupal\simpletest\WebTestBase;
 use Drupal\user\Entity\User;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpFoundation\Request;
@@ -36,7 +42,7 @@
  *
  * @see hook_update_N()
  */
-abstract class UpdatePathTestBase extends WebTestBase {
+abstract class UpdatePathTestBase extends BrowserTestBase {
 
   use SchemaCheckTestTrait;
 
@@ -146,6 +152,16 @@ public function __construct($test_id = NULL) {
    * container that would normally be done via the installer.
    */
   protected function setUp() {
+    $request = Request::createFromGlobals();
+
+    // Boot up Drupal into a state where calling the database API is possible.
+    // This is used to initialize the database system, so we can load the dump
+    // files.
+    $autoloader = require $this->root . '/autoload.php';
+    $kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
+    $kernel->loadLegacyIncludes();
+
+    $this->changeDatabasePrefix();
     $this->runDbTasks();
     // Allow classes to set database dump files.
     $this->setDatabaseDumpFiles();
@@ -157,43 +173,122 @@ protected function setUp() {
       parent::setUp();
       return;
     }
-
     // Set the update url. This must be set here rather than in
     // self::__construct() or the old URL generator will leak additional test
     // sites.
     $this->updateUrl = Url::fromRoute('system.db_update');
 
-    // These methods are called from parent::setUp().
-    $this->setBatch();
-    $this->initUserSession();
-    $this->prepareSettings();
+    $this->setupBaseUrl();
 
-    // Load the database(s).
-    foreach ($this->databaseDumpFiles as $file) {
-      if (substr($file, -3) == '.gz') {
-        $file = "compress.zlib://$file";
+    // Install Drupal test site.
+    $this->prepareEnvironment();
+    $this->installDrupal();
+
+    // Add the config directories to settings.php.
+    drupal_install_config_directories();
+
+    // Set the container. parent::rebuildAll() would normally do this, but this
+    // not safe to do here, because the database has not been updated yet.
+    $this->container = \Drupal::getContainer();
+
+    $this->replaceUser1();
+
+    require_once \Drupal::root() . '/core/includes/update.inc';
+
+    // Setup Mink.
+    $session = $this->initMink();
+
+    $cookies = $this->extractCookiesFromRequest(\Drupal::request());
+    foreach ($cookies as $cookie_name => $values) {
+      foreach ($values as $value) {
+        $session->setCookie($cookie_name, $value);
       }
-      require $file;
     }
 
+    // Creates the directory to store browser output in if a file to write
+    // URLs to has been created by \Drupal\Tests\Listeners\HtmlOutputPrinter.
+    $browser_output_file = getenv('BROWSERTEST_OUTPUT_FILE');
+    $this->htmlOutputEnabled = is_file($browser_output_file);
+    if ($this->htmlOutputEnabled) {
+      $this->htmlOutputFile = $browser_output_file;
+      $this->htmlOutputClassName = str_replace("\\", "_", get_called_class());
+      $this->htmlOutputDirectory = DRUPAL_ROOT . '/sites/simpletest/browser_output';
+      if (file_prepare_directory($this->htmlOutputDirectory, FILE_CREATE_DIRECTORY) && !file_exists($this->htmlOutputDirectory . '/.htaccess')) {
+        file_put_contents($this->htmlOutputDirectory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n");
+      }
+      $this->htmlOutputCounterStorage = $this->htmlOutputDirectory . '/' . $this->htmlOutputClassName . '.counter';
+      $this->htmlOutputTestId = str_replace('sites/simpletest/', '', $this->siteDirectory);
+      if (is_file($this->htmlOutputCounterStorage)) {
+        $this->htmlOutputCounter = max(1, (int) file_get_contents($this->htmlOutputCounterStorage)) + 1;
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function installDrupal() {
+    $this->initUserSession();
+    $this->prepareSettings();
+    $this->doInstall();
     $this->initSettings();
+
     $request = Request::createFromGlobals();
     $container = $this->initKernel($request);
     $this->initConfig($container);
+  }
 
-    // Add the config directories to settings.php.
-    drupal_install_config_directories();
+  /**
+   * {@inheritdoc}
+   */
+  protected function doInstall() {
+    $this->runDbTasks();
+    // Allow classes to set database dump files.
+    $this->setDatabaseDumpFiles();
 
-    // Restore the original Simpletest batch.
-    $this->restoreBatch();
+    // Load the database(s).
+    foreach ($this->databaseDumpFiles as $file) {
+      if (substr($file, -3) == '.gz') {
+        $file = "compress.zlib://$file";
+      }
+      require $file;
+    }
+  }
 
-    // Set the container. parent::rebuildAll() would normally do this, but this
-    // not safe to do here, because the database has not been updated yet.
-    $this->container = \Drupal::getContainer();
+  /**
+   * {@inheritdoc}
+   */
+  protected function initMink() {
+    $driver = $this->getDefaultDriverInstance();
+
+    if ($driver instanceof GoutteDriver) {
+      // Turn off curl timeout. Having a timeout is not a problem in a normal
+      // test running, but it is a problem when debugging. Also, disable SSL
+      // peer verification so that testing under HTTPS always works.
+      /** @var \GuzzleHttp\Client $client */
+      $client = $this->container->get('http_client_factory')->fromOptions([
+        'timeout' => NULL,
+        'verify' => FALSE,
+      ]);
+
+      // Inject a Guzzle middleware to generate debug output for every request
+      // performed in the test.
+      $handler_stack = $client->getConfig('handler');
+      $handler_stack->push($this->getResponseLogHandler());
+
+      $driver->getClient()->setClient($client);
+    }
 
-    $this->replaceUser1();
+    $selectors_handler = new SelectorsHandler([
+      'hidden_field_selector' => new HiddenFieldSelector()
+    ]);
+    $session = new Session($driver, $selectors_handler);
+    $this->mink = new Mink();
+    $this->mink->registerSession('default', $session);
+    $this->mink->setDefaultSessionName('default');
+    $this->registerSessions();
 
-    require_once \Drupal::root() . '/core/includes/update.inc';
+    return $session;
   }
 
   /**
@@ -248,6 +343,7 @@ protected function runUpdates() {
     $this->doSelectionTest();
     // Run the update hooks.
     $this->clickLink(t('Apply pending updates'));
+    $this->checkForMetaRefresh();
 
     // Ensure there are no failed updates.
     if ($this->checkFailedUpdates) {
@@ -317,7 +413,7 @@ protected function runDbTasks() {
       ->addArgument(new Reference('language.default'));
     \Drupal::setContainer($container);
 
-    require_once __DIR__ . '/../../../../../includes/install.inc';
+    require_once __DIR__ . '/../../../../includes/install.inc';
     $connection = Database::getConnection();
     $errors = db_installer_object($connection->driver())->runTasks();
     if (!empty($errors)) {
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBaseTest.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
similarity index 92%
rename from core/modules/system/src/Tests/Update/UpdatePathTestBaseTest.php
rename to core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
index efff986085..911d523a0e 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBaseTest.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\system\Tests\Update;
+namespace Drupal\FunctionalTests\Update;
 
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\SafeMarkup;
@@ -22,8 +22,8 @@ class UpdatePathTestBaseTest extends UpdatePathTestBase {
    */
   protected function setDatabaseDumpFiles() {
     $this->databaseDumpFiles = [
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
-      __DIR__ . '/../../../tests/fixtures/update/drupal-8.update-test-schema-enabled.php',
+      __DIR__ . '/../../../../modules/system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../../modules/system/tests/fixtures/update/drupal-8.update-test-schema-enabled.php',
     ];
   }
 
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index bd50c23b48..5eda4e8eba 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -14,10 +14,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
-use Drupal\Core\Site\Settings;
-use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\Test\FunctionalTestSetupTrait;
-use Drupal\Core\Test\TestRunnerKernel;
 use Drupal\Core\Test\TestSetupTrait;
 use Drupal\Core\Url;
 use Drupal\Core\Utility\Error;
@@ -31,7 +28,6 @@
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Symfony\Component\CssSelector\CssSelectorConverter;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Provides a test case for functional Drupal tests.
@@ -262,6 +258,32 @@
   protected $metaRefreshCount = 0;
 
   /**
+   * The app root.
+   *
+   * @var string
+   */
+  protected $root;
+
+  /**
+   * The original container.
+   *
+   * Move this to \Drupal\Core\Test\FunctionalTestSetupTrait once TestBase no
+   * longer provides the same value.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected $originalContainer;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($name = NULL, array $data = [], $dataName = '') {
+    parent::__construct($name, $data, $dataName);
+
+    $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
+  }
+
+  /**
    * Initializes Mink sessions.
    */
   protected function initMink() {
@@ -400,43 +422,9 @@ protected function registerSessions() {}
    * {@inheritdoc}
    */
   protected function setUp() {
-    global $base_url;
     parent::setUp();
 
-    // Get and set the domain of the environment we are running our test
-    // coverage against.
-    $base_url = getenv('SIMPLETEST_BASE_URL');
-    if (!$base_url) {
-      throw new \Exception(
-        'You must provide a SIMPLETEST_BASE_URL environment variable to run some PHPUnit based functional tests.'
-      );
-    }
-
-    // Setup $_SERVER variable.
-    $parsed_url = parse_url($base_url);
-    $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '');
-    $path = isset($parsed_url['path']) ? rtrim(rtrim($parsed_url['path']), '/') : '';
-    $port = isset($parsed_url['port']) ? $parsed_url['port'] : 80;
-
-    $this->baseUrl = $base_url;
-
-    // If the passed URL schema is 'https' then setup the $_SERVER variables
-    // properly so that testing will run under HTTPS.
-    if ($parsed_url['scheme'] === 'https') {
-      $_SERVER['HTTPS'] = 'on';
-    }
-    $_SERVER['HTTP_HOST'] = $host;
-    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
-    $_SERVER['SERVER_ADDR'] = '127.0.0.1';
-    $_SERVER['SERVER_PORT'] = $port;
-    $_SERVER['SERVER_SOFTWARE'] = NULL;
-    $_SERVER['SERVER_NAME'] = 'localhost';
-    $_SERVER['REQUEST_URI'] = $path . '/';
-    $_SERVER['REQUEST_METHOD'] = 'GET';
-    $_SERVER['SCRIPT_NAME'] = $path . '/index.php';
-    $_SERVER['SCRIPT_FILENAME'] = $path . '/index.php';
-    $_SERVER['PHP_SELF'] = $path . '/index.php';
-    $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
+    $this->setupBaseUrl();
 
     // Install Drupal test site.
     $this->prepareEnvironment();
@@ -980,134 +968,6 @@ public function installDrupal() {
   }
 
   /**
-   * Returns the parameters that will be used when Simpletest installs Drupal.
-   *
-   * @see install_drupal()
-   * @see install_state_defaults()
-   */
-  protected function installParameters() {
-    $connection_info = Database::getConnectionInfo();
-    $driver = $connection_info['default']['driver'];
-    $connection_info['default']['prefix'] = $connection_info['default']['prefix']['default'];
-    unset($connection_info['default']['driver']);
-    unset($connection_info['default']['namespace']);
-    unset($connection_info['default']['pdo']);
-    unset($connection_info['default']['init_commands']);
-    $parameters = [
-      'interactive' => FALSE,
-      'parameters' => [
-        'profile' => $this->profile,
-        'langcode' => 'en',
-      ],
-      'forms' => [
-        'install_settings_form' => [
-          'driver' => $driver,
-          $driver => $connection_info['default'],
-        ],
-        'install_configure_form' => [
-          'site_name' => 'Drupal',
-          'site_mail' => 'simpletest@example.com',
-          'account' => [
-            'name' => $this->rootUser->name,
-            'mail' => $this->rootUser->getEmail(),
-            'pass' => [
-              'pass1' => $this->rootUser->pass_raw,
-              'pass2' => $this->rootUser->pass_raw,
-            ],
-          ],
-          // form_type_checkboxes_value() requires NULL instead of FALSE values
-          // for programmatic form submissions to disable a checkbox.
-          'enable_update_status_module' => NULL,
-          'enable_update_status_emails' => NULL,
-        ],
-      ],
-    ];
-    return $parameters;
-  }
-
-  /**
-   * Prepares the current environment for running the test.
-   *
-   * Also sets up new resources for the testing environment, such as the public
-   * filesystem and configuration directories.
-   *
-   * This method is private as it must only be called once by
-   * BrowserTestBase::setUp() (multiple invocations for the same test would have
-   * unpredictable consequences) and it must not be callable or overridable by
-   * test classes.
-   */
-  protected function prepareEnvironment() {
-    // Bootstrap Drupal so we can use Drupal's built in functions.
-    $this->classLoader = require __DIR__ . '/../../../../autoload.php';
-    $request = Request::createFromGlobals();
-    $kernel = TestRunnerKernel::createFromRequest($request, $this->classLoader);
-    // TestRunnerKernel expects the working directory to be DRUPAL_ROOT.
-    chdir(DRUPAL_ROOT);
-    $kernel->prepareLegacyRequest($request);
-    $this->prepareDatabasePrefix();
-
-    $this->originalSite = $kernel->findSitePath($request);
-
-    // Create test directory ahead of installation so fatal errors and debug
-    // information can be logged during installation process.
-    file_prepare_directory($this->siteDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
-
-    // Prepare filesystem directory paths.
-    $this->publicFilesDirectory = $this->siteDirectory . '/files';
-    $this->privateFilesDirectory = $this->siteDirectory . '/private';
-    $this->tempFilesDirectory = $this->siteDirectory . '/temp';
-    $this->translationFilesDirectory = $this->siteDirectory . '/translations';
-
-    // Ensure the configImporter is refreshed for each test.
-    $this->configImporter = NULL;
-
-    // Unregister all custom stream wrappers of the parent site.
-    $wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers(StreamWrapperInterface::ALL);
-    foreach ($wrappers as $scheme => $info) {
-      stream_wrapper_unregister($scheme);
-    }
-
-    // Reset statics.
-    drupal_static_reset();
-
-    // Ensure there is no service container.
-    $this->container = NULL;
-    \Drupal::unsetContainer();
-
-    // Unset globals.
-    unset($GLOBALS['config_directories']);
-    unset($GLOBALS['config']);
-    unset($GLOBALS['conf']);
-
-    // Log fatal errors.
-    ini_set('log_errors', 1);
-    ini_set('error_log', DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
-
-    // Change the database prefix.
-    $this->changeDatabasePrefix();
-
-    // After preparing the environment and changing the database prefix, we are
-    // in a valid test environment.
-    drupal_valid_test_ua($this->databasePrefix);
-
-    // Reset settings.
-    new Settings([
-      // For performance, simply use the database prefix as hash salt.
-      'hash_salt' => $this->databasePrefix,
-    ]);
-
-    drupal_set_time_limit($this->timeLimit);
-
-    // Save and clean the shutdown callbacks array because it is static cached
-    // and will be changed by the test run. Otherwise it will contain callbacks
-    // from both environments and the testing environment will try to call the
-    // handlers defined by the original one.
-    $callbacks = &drupal_register_shutdown_function();
-    $this->originalShutdownCallbacks = $callbacks;
-    $callbacks = [];
-  }
-
-  /**
    * Returns whether a given user account is logged in.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
