diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 499f552..5dee0a0 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -25,7 +25,15 @@
  * @todo Move this to an appropriate autoloadable class. See
  *   https://www.drupal.org/project/drupal/issues/2908079
  */
-const DRUPAL_MINIMUM_PHP = '5.5.9';
+const DRUPAL_MINIMUM_PHP = '7.0.0';
+
+/**
+ * Updates cannot be run on versions of PHP older than this version.
+ *
+ * @todo Move this to an appropriate autoloadable class. See
+ *   https://www.drupal.org/project/drupal/issues/2908079
+ */
+const DRUPAL_MINIMUM_UPDATE_PHP = '5.5.9';
 
 /**
  * Minimum recommended version of PHP.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 70c82b4..13f0372 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -1116,7 +1116,7 @@ function install_profile_info($profile, $langcode = 'en') {
       'description' => '',
       'version' => NULL,
       'hidden' => FALSE,
-      'php' => DRUPAL_MINIMUM_PHP,
+      'php' => DRUPAL_MINIMUM_UPDATE_PHP,
       'config_install_path' => NULL,
     ];
     $profile_path = drupal_get_path('profile', $profile);
diff --git a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
index c8f492b..07a1d83 100644
--- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
@@ -28,7 +28,7 @@ class ModuleExtensionList extends ExtensionList {
     'description' => '',
     'package' => 'Other',
     'version' => NULL,
-    'php' => DRUPAL_MINIMUM_PHP,
+    'php' => DRUPAL_MINIMUM_UPDATE_PHP,
   ];
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/ProfileExtensionList.php b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
index 7c41516..bb054d0 100644
--- a/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
@@ -22,7 +22,7 @@ class ProfileExtensionList extends ExtensionList {
     'description' => '',
     'package' => 'Other',
     'version' => NULL,
-    'php' => DRUPAL_MINIMUM_PHP,
+    'php' => DRUPAL_MINIMUM_UPDATE_PHP,
   ];
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php b/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
index c4d39ef..aef0d4e 100644
--- a/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
@@ -21,7 +21,7 @@ class ThemeEngineExtensionList extends ExtensionList {
     'description' => '',
     'package' => 'Other',
     'version' => NULL,
-    'php' => DRUPAL_MINIMUM_PHP,
+    'php' => DRUPAL_MINIMUM_UPDATE_PHP,
   ];
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/ThemeExtensionList.php b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
index 07a2f3f..5468c3f 100644
--- a/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
@@ -48,7 +48,7 @@ class ThemeExtensionList extends ExtensionList {
       'comment_user_verification',
     ],
     'screenshot' => 'screenshot.png',
-    'php' => DRUPAL_MINIMUM_PHP,
+    'php' => DRUPAL_MINIMUM_UPDATE_PHP,
     'libraries' => [],
     'libraries_extend' => [],
     'libraries_override' => [],
diff --git a/core/modules/locale/tests/src/Functional/LocaleTranslatedSchemaDefinitionTest.php b/core/modules/locale/tests/src/Functional/LocaleTranslatedSchemaDefinitionTest.php
index 3e39f74..646eb4f 100644
--- a/core/modules/locale/tests/src/Functional/LocaleTranslatedSchemaDefinitionTest.php
+++ b/core/modules/locale/tests/src/Functional/LocaleTranslatedSchemaDefinitionTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Adds and configures languages to check field schema definition.
@@ -12,6 +13,8 @@
  */
 class LocaleTranslatedSchemaDefinitionTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   /**
    * Modules to enable.
    *
@@ -83,6 +86,8 @@ public function testTranslatedUpdate() {
     // markup and a link instead of specific text because text may be
     // translated.
     $this->drupalGet($update_url . '/selection', ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
+    $this->drupalGet($update_url . '/selection', ['external' => TRUE]);
     $this->assertRaw('messages--status', 'No pending updates.');
     $this->assertNoLinkByHref('fr/update.php/run', 'No link to run updates.');
   }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 960bb7d..d7bef10 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -186,24 +186,29 @@ function system_requirements($phase) {
     ];
   }
 
-  if (version_compare($phpversion, DRUPAL_MINIMUM_PHP) < 0) {
-    $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
+  $is_test_site = drupal_valid_test_ua() || getenv('DRUPAL_DEV_SITE_PATH');
+  if (version_compare($phpversion, DRUPAL_MINIMUM_UPDATE_PHP) < 0) {
+    $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_UPDATE_PHP]);
     $requirements['php']['severity'] = REQUIREMENT_ERROR;
-    // If PHP is old, it's not safe to continue with the requirements check.
     return $requirements;
   }
-  if ((version_compare($phpversion, DRUPAL_RECOMMENDED_PHP) < 0) && ($phase === 'install' || $phase === 'runtime')) {
-    // Warn if still on PHP 5. If at least PHP 7.0, relax from "warning" to
-    // "info", and show it at runtime only, to not scare users while installing.
-    if (version_compare($phpversion, '7.0') < 0) {
-      $requirements['php']['description'] = t('Drupal will drop support for this version on March 6, 2019. Upgrade to PHP version %recommended or higher to ensure your site can receive updates and remain secure. See <a href="http://php.net/supported-versions.php">PHP\'s version support documentation</a> and the <a href=":php_requirements">Drupal 8 PHP requirements handbook page</a> for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
+  if (version_compare($phpversion, DRUPAL_MINIMUM_PHP) < 0) {
+    // Allow test installations of Drupal on the minimum update PHP.
+    if ($phase === 'update') {
+      $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
       $requirements['php']['severity'] = REQUIREMENT_WARNING;
     }
-    else {
-      if ($phase === 'runtime') {
-        $requirements['php']['description'] = t('It is recommended to upgrade to PHP version %recommended or higher for the best ongoing support.  See <a href="http://php.net/supported-versions.php">PHP\'s version support documentation</a> and the <a href=":php_requirements">Drupal 8 PHP requirements handbook page</a> for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
-        $requirements['php']['severity'] = REQUIREMENT_INFO;
-      }
+    elseif (!$is_test_site) {
+      $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
+      $requirements['php']['severity'] = REQUIREMENT_ERROR;
+      // If PHP is old, it's not safe to continue with the requirements check.
+      return $requirements;
+    }
+  }
+  if (version_compare($phpversion, DRUPAL_RECOMMENDED_PHP) < 0) {
+    if ($phase === 'runtime') {
+      $requirements['php']['description'] = t('It is recommended to upgrade to PHP version %recommended or higher for the best ongoing support.  See <a href="http://php.net/supported-versions.php">PHP\'s version support documentation</a> and the <a href=":php_requirements">Drupal 8 PHP requirements handbook page</a> for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
+      $requirements['php']['severity'] = REQUIREMENT_INFO;
     }
   }
 
diff --git a/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php b/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
index 55f3a04..938b60a 100644
--- a/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
+++ b/core/modules/system/tests/src/Functional/Update/DbUpdatesTrait.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Provides methods to conditionally enable db update functions and apply
@@ -14,6 +15,7 @@
 trait DbUpdatesTrait {
 
   use StringTranslationTrait;
+  use RequirementsPageTrait;
 
   /**
    * Enables db updates until the specified index.
@@ -34,6 +36,7 @@ protected function enableUpdates($module, $group, $index) {
    */
   protected function applyUpdates() {
     $this->drupalGet(Url::fromRoute('system.db_update'));
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink($this->t('Continue'));
     $this->clickLink($this->t('Apply pending updates'));
     $this->checkForMetaRefresh();
diff --git a/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php b/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
index 85d041e..3e37d68 100644
--- a/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
+++ b/core/modules/system/tests/src/Functional/Update/InvalidUpdateHookTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Tests that a module implementing hook_update_8000() causes an error to be
@@ -12,6 +13,8 @@
  */
 class InvalidUpdateHookTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   /**
    * Modules to enable.
    *
@@ -45,6 +48,7 @@ public function testInvalidUpdateHook() {
     // Confirm that a module with hook_update_8000() cannot be updated.
     $this->drupalLogin($this->updateUser);
     $this->drupalGet($this->updateUrl);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertText(t('Some of the pending updates cannot be applied because their dependencies were not met.'));
   }
diff --git a/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
index fd9e011..f013988 100644
--- a/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatePostUpdateTest.php
@@ -78,6 +78,8 @@ public function testPostUpdate() {
     }
 
     $this->drupalGet('update.php/selection');
+    $this->continueOnExpectedWarnings('try again');
+    $this->drupalGet('update.php/selection');
     $this->assertText('No pending updates.');
   }
 
diff --git a/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php b/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
index e35d52b..9d967c8 100644
--- a/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateSchemaTest.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Url;
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Tests that update hooks are properly run.
@@ -13,6 +14,8 @@
  */
 class UpdateSchemaTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -56,6 +59,7 @@ public function testUpdateHooks() {
 
     $this->drupalLogin($this->user);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertRaw('Schema version 8001.');
     // Run the update hooks.
diff --git a/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
index da215d4..cc32694 100644
--- a/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Url;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Tests the update script access and functionality.
@@ -13,6 +14,8 @@
  */
 class UpdateScriptTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   /**
    * Modules to enable.
    *
@@ -99,6 +102,7 @@ public function testRequirements() {
     // If there are no requirements warnings or errors, we expect to be able to
     // go through the update process uninterrupted.
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertText(t('No pending updates.'), 'End of update process was reached.');
     // Confirm that all caches were cleared.
@@ -110,6 +114,7 @@ public function testRequirements() {
 
     // First, run this test with pending updates to make sure they can be run
     // successfully.
+    $this->drupalLogin($this->updateUser);
     $update_script_test_config->set('requirement_type', REQUIREMENT_WARNING)->save();
     drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
@@ -177,6 +182,7 @@ public function testNoUpdateFunctionality() {
     // Click through update.php with 'administer software updates' permission.
     $this->drupalLogin($this->updateUser);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertText(t('No pending updates.'));
     $this->assertNoLink('Administration pages');
@@ -188,6 +194,7 @@ public function testNoUpdateFunctionality() {
     $admin_user = $this->drupalCreateUser(['administer software updates', 'access administration pages']);
     $this->drupalLogin($admin_user);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertText(t('No pending updates.'));
     $this->assertLink('Administration pages');
@@ -220,6 +227,7 @@ public function testSuccessfulUpdateFunctionality() {
     $admin_user = $this->drupalCreateUser(['administer software updates', 'access administration pages', 'access site reports', 'access site in maintenance mode']);
     $this->drupalLogin($admin_user);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
     $this->checkForMetaRefresh();
@@ -287,6 +295,7 @@ public function testSuccessfulMultilingualUpdateFunctionality() {
     // Click through update.php with 'access administration pages' and
     // 'access site reports' permissions.
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
     $this->checkForMetaRefresh();
@@ -319,6 +328,7 @@ protected function runUpdates($maintenance_mode) {
       $this->assertNoText('Operating in maintenance mode.');
     }
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->clickLink(t('Apply pending updates'));
     $this->checkForMetaRefresh();
diff --git a/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php b/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
index 4f536ea..799e939 100644
--- a/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdatesWith7xTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\system\Functional\Update;
 
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 
 /**
  * Tests that the minimum schema version is correct even if only 7.x update
@@ -12,6 +13,8 @@
  */
 class UpdatesWith7xTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   /**
    * Modules to enable.
    *
@@ -48,6 +51,7 @@ public function testWith7x() {
     // Click through update.php with 'administer software updates' permission.
     $this->drupalLogin($this->updateUser);
     $this->drupalGet($this->updateUrl, ['external' => TRUE]);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
     $this->assertText(t('Some of the pending updates cannot be applied because their dependencies were not met.'));
   }
diff --git a/core/profiles/minimal/tests/src/Functional/MinimalTest.php b/core/profiles/minimal/tests/src/Functional/MinimalTest.php
index 568918a..64f4a4a 100644
--- a/core/profiles/minimal/tests/src/Functional/MinimalTest.php
+++ b/core/profiles/minimal/tests/src/Functional/MinimalTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\minimal\Functional;
 
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 use Drupal\user\UserInterface;
 
 /**
@@ -12,6 +13,8 @@
  */
 class MinimalTest extends BrowserTestBase {
 
+  use RequirementsPageTrait;
+
   protected $profile = 'minimal';
 
   /**
@@ -34,6 +37,8 @@ public function testMinimal() {
     // Ensure that there are no pending updates after installation.
     $this->drupalLogin($this->rootUser);
     $this->drupalGet('update.php/selection');
+    $this->continueOnExpectedWarnings('try again');
+    $this->drupalGet('update.php/selection');
     $this->assertText('No pending updates.');
 
     // Ensure that there are no pending entity updates after installation.
diff --git a/core/profiles/standard/tests/src/Functional/StandardTest.php b/core/profiles/standard/tests/src/Functional/StandardTest.php
index 79584b4..d6e7c7f 100644
--- a/core/profiles/standard/tests/src/Functional/StandardTest.php
+++ b/core/profiles/standard/tests/src/Functional/StandardTest.php
@@ -10,6 +10,7 @@
 use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
 use Drupal\filter\Entity\FilterFormat;
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\RequirementsPageTrait;
 use Drupal\user\Entity\Role;
 
 /**
@@ -20,6 +21,7 @@
 class StandardTest extends BrowserTestBase {
 
   use SchemaCheckTestTrait;
+  use RequirementsPageTrait;
 
   protected $profile = 'standard';
 
@@ -155,6 +157,8 @@ public function testStandard() {
     // Ensure that there are no pending updates after installation.
     $this->drupalLogin($this->rootUser);
     $this->drupalGet('update.php/selection');
+    $this->continueOnExpectedWarnings('try again');
+    $this->drupalGet('update.php/selection');
     $this->assertText('No pending updates.');
 
     // Ensure that there are no pending entity updates after installation.
diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
index 9810f34..5ea1e58 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
@@ -244,12 +244,7 @@ protected function setUpSettings() {
    * @see system_requirements()
    */
   protected function setUpRequirementsProblem() {
-    // By default, skip the "recommended PHP version" warning on older test
-    // environments. This allows the installer to be tested consistently on
-    // both recommended PHP versions and older (but still supported) versions.
-    if (version_compare(phpversion(), '7.0') < 0) {
-      $this->continueOnExpectedWarnings(['PHP']);
-    }
+    // Do nothing.
   }
 
   /**
diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index a127ab4..7b6d9d6 100644
--- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -10,6 +10,7 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Url;
+use Drupal\Tests\RequirementsPageTrait;
 use Drupal\user\Entity\User;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpFoundation\Request;
@@ -42,6 +43,7 @@
 abstract class UpdatePathTestBase extends BrowserTestBase {
 
   use SchemaCheckTestTrait;
+  use RequirementsPageTrait;
 
   /**
    * Modules to enable after the database is loaded.
@@ -295,6 +297,7 @@ protected function runUpdates() {
     ]);
 
     $this->drupalGet($this->updateUrl);
+    $this->continueOnExpectedWarnings('try again');
     $this->clickLink(t('Continue'));
 
     $this->doSelectionTest();
diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
index 9c5fd58..cba97b8 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
@@ -259,6 +259,6 @@ class TestThemeEngineExtensionList extends ThemeEngineExtensionList {
 
 }
 
-if (!defined('DRUPAL_MINIMUM_PHP')) {
-  define('DRUPAL_MINIMUM_PHP', '5.5.9');
+if (!defined('DRUPAL_MINIMUM_UPDATE_PHP')) {
+  define('DRUPAL_MINIMUM_UPDATE_PHP', '5.5.9');
 }
diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
index 97a5e93..841073b 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
@@ -146,6 +146,6 @@ protected function themeRegistryRebuild() {
 
 }
 
-if (!defined('DRUPAL_MINIMUM_PHP')) {
-  define('DRUPAL_MINIMUM_PHP', '5.5.9');
+if (!defined('DRUPAL_MINIMUM_UPDATE_PHP')) {
+  define('DRUPAL_MINIMUM_UPDATE_PHP', '5.5.9');
 }
diff --git a/core/tests/Drupal/Tests/RequirementsPageTrait.php b/core/tests/Drupal/Tests/RequirementsPageTrait.php
new file mode 100644
index 0000000..1181d0c
--- /dev/null
+++ b/core/tests/Drupal/Tests/RequirementsPageTrait.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests;
+
+/**
+ * Provides helper methods for the requirements page.
+ */
+trait RequirementsPageTrait {
+
+  /**
+   * Go to the next screen if the expected requirement warnings are found.
+   *
+   * @param string $link_label
+   *   If the expected requirement warnings are found, the test will click this
+   *   link to go to the next screen.
+   */
+  protected function continueOnExpectedWarnings($link_label) {
+    // Assert there are no errors.
+    $this->assertFalse(strpos($this->getTextContent(), 'Errors found'));
+    $this->assertRequirementWarnings();
+    $this->clickLink($link_label);
+    $this->checkForMetaRefresh();
+  }
+
+  /**
+   * Assert the expected requirement warnings are present on the page.
+   */
+  protected function assertRequirementWarnings() {
+    // Assert a warning is shown on older test environments.
+    if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
+      $this->assertWarningSummaries(['PHP']);
+    }
+  }
+
+  /**
+   * Assert the given warning summaries are present on the page.
+   *
+   * If an expected warning is not found, or if a warning not in the list is
+   * present, a fail is raised.
+   *
+   * @param string[] $warning_summaries
+   *   A list of warning summaries to expect on the requirements screen (e.g.
+   *   'PHP', 'PHP OPcode caching', etc.).
+   */
+  protected function assertWarningSummaries(array $warning_summaries) {
+    // Allow only details elements that are directly after the warning header
+    // or each other. There is no guaranteed wrapper we can rely on across
+    // distributions. When there are multiple warnings, the selectors will be:
+    // - h3#warning+details summary
+    // - h3#warning+details+details summary
+    // - etc.
+    // We add one more selector than expected warnings to confirm that there
+    // isn't any other warning before clicking the link.
+    // @todo Make this more reliable in
+    //   https://www.drupal.org/project/drupal/issues/2927345.
+    $selectors = [];
+    for ($i = 0; $i <= count($warning_summaries); $i++) {
+      $selectors[] = 'h3#warning' . implode('', array_fill(0, $i + 1, '+details')) . ' summary';
+    }
+    $warning_elements = $this->cssSelect(implode(', ', $selectors));
+
+    // Confirm that there are only the expected warnings.
+    $warnings = [];
+    foreach ($warning_elements as $warning) {
+      $warnings[] = trim($warning->getText());
+    }
+    $this->assertEquals($warning_summaries, $warnings);
+  }
+
+}
