diff --git a/core/drupalci.yml b/core/drupalci.yml
index cd92d8102d..27900ff1ec 100644
--- a/core/drupalci.yml
+++ b/core/drupalci.yml
@@ -3,49 +3,16 @@
 # https://www.drupal.org/drupalorg/docs/drupal-ci/customizing-drupalci-testing
 _phpunit_testgroups_to_execute: &testgroups
   # Default: all of Drupal core's test suite runs.
-  testgroups: '--all'
+  testgroups: '--class "\Drupal\FunctionalJavascriptTests\Ajax\ThrobberTest,\Drupal\Tests\media_library\FunctionalJavascript\WidgetViewsTest"'
   # Alternative: run only the tests for one particular module.
   # testgroups: '--module ckeditor5'
 build:
   assessment:
     testing:
-      # Run code quality checks.
-      container_command.commit-checks:
-        commands:
-          - "core/scripts/dev/commit-code-check.sh --drupalci"
-        halt-on-fail: true
-      # run_tests task is executed several times in order of performance speeds.
-      # halt-on-fail can be set on the run_tests tasks in order to fail fast.
-      # suppress-deprecations is false in order to be alerted to usages of
-      # deprecated code.
-      run_tests.phpunit:
-        types: 'PHPUnit-Unit'
-        suppress-deprecations: false
-        halt-on-fail: false
-        <<: *testgroups
-      run_tests.kernel:
-        types: 'PHPUnit-Kernel'
-        suppress-deprecations: false
-        halt-on-fail: false
-        <<: *testgroups
-      run_tests.build:
-        # Limit concurrency due to disk space concerns.
-        concurrency: 15
-        types: 'PHPUnit-Build'
-        suppress-deprecations: false
-        halt-on-fail: false
-        <<: *testgroups
-      run_tests.functional:
-        types: 'PHPUnit-Functional'
-        suppress-deprecations: false
-        halt-on-fail: false
-        <<: *testgroups
       run_tests.javascript:
         concurrency: 15
         types: 'PHPUnit-FunctionalJavascript'
         suppress-deprecations: false
         halt-on-fail: false
         <<: *testgroups
-      # Run nightwatch testing.
-      # @see https://www.drupal.org/project/drupal/issues/2869825
-      nightwatchjs: {}
+        repeat: 1000
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index 37a265f4ec..2edb060ce1 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -26,6 +26,7 @@
 use Drupal\Core\Plugin\PluginManagerPass;
 use Drupal\Core\Render\MainContent\MainContentRenderersPass;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Test\StackMiddleware\DelayResponseMiddleware;
 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -148,6 +149,11 @@ protected function registerTest(ContainerBuilder $container) {
     $container
       ->register('test.http_middleware.wait_terminate_middleware', 'Drupal\Core\Test\StackMiddleware\TestWaitTerminateMiddleware')
       ->setArguments([new Reference('state'), new Reference('lock')])
+      ->addTag('http_middleware', ['priority' => -1024])     ;
+    // Add the delay response middleware which can delay responses.
+    $container
+      ->register('test.http_middleware.delay_response_middleware', DelayResponseMiddleware::class)
+      ->setArguments([new Reference('state')])
       ->addTag('http_middleware', ['priority' => -1024]);
   }
 
diff --git a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php
index 8298223a37..4f4b0e0b88 100644
--- a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php
+++ b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php
@@ -51,7 +51,7 @@ public function parse($filename) {
         throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename);
       }
       if (!isset($parsed_info['core_version_requirement'])) {
-        if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . '/core/')) {
+        if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . DIRECTORY_SEPARATOR . 'core/')) {
           // Core extensions do not need to specify core compatibility: they are
           // by definition compatible so a sensible default is used. Core
           // modules are allowed to provide these for testing purposes.
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTestBase.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTestBase.php
index d1968f948f..0f4f919f23 100644
--- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTestBase.php
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTestBase.php
@@ -4,16 +4,19 @@
 
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\media\Entity\Media;
+use Drupal\Tests\DelayResponseTrait;
 
 /**
  * Base class for functional tests of Media Library functionality.
  */
 abstract class MediaLibraryTestBase extends WebDriverTestBase {
 
+  use DelayResponseTrait;
+
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['media_library_test', 'hold_test'];
+  protected static $modules = ['media_library_test'];
 
   /**
    * {@inheritdoc}
@@ -431,11 +434,13 @@ protected function switchToMediaLibraryGrid() {
    * Switches to the table display of the widget view.
    */
   protected function switchToMediaLibraryTable() {
-    hold_test_response(TRUE);
+    // Delay the response, so we have time to check the announce before it's
+    // removed when the AJAX-response arrives.
+    $this->setDelayResponse();
     $this->getSession()->getPage()->clickLink('Table');
     // Assert the display change is correctly announced for screen readers.
     $this->assertAnnounceContains('Loading table view.');
-    hold_test_response(FALSE);
+    $this->unsetDelayResponse();
     $this->assertAnnounceContains('Changed to table view.');
     $this->assertMediaLibraryTable();
   }
diff --git a/core/modules/system/tests/modules/hold_test/hold_test.info.yml b/core/modules/system/tests/modules/hold_test/hold_test.info.yml
deleted file mode 100644
index 9600d70831..0000000000
--- a/core/modules/system/tests/modules/hold_test/hold_test.info.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-name: Hold test
-type: module
-description: 'Support testing with request/response hold.'
-package: Testing
-version: VERSION
diff --git a/core/modules/system/tests/modules/hold_test/hold_test.install b/core/modules/system/tests/modules/hold_test/hold_test.install
deleted file mode 100644
index 183463deb3..0000000000
--- a/core/modules/system/tests/modules/hold_test/hold_test.install
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-/**
- * @file
- * Install, update and uninstall functions for the hold_test module.
- */
-
-/**
- * Implements hook_install().
- */
-function hold_test_install() {
-  hold_test_request(FALSE);
-  hold_test_response(FALSE);
-}
diff --git a/core/modules/system/tests/modules/hold_test/hold_test.module b/core/modules/system/tests/modules/hold_test/hold_test.module
deleted file mode 100644
index 4444f96dcc..0000000000
--- a/core/modules/system/tests/modules/hold_test/hold_test.module
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains functions for testing hold request/response.
- */
-
-use Drupal\hold_test\EventSubscriber\HoldTestSubscriber;
-
-/**
- * Request hold.
- *
- * @param bool $status
- *   TRUE - enable hold, FALSE - disable hold.
- */
-function hold_test_request($status) {
-  $site_path = \Drupal::getContainer()->getParameter('site.path');
-  file_put_contents($site_path . '/hold_test_request.txt', $status);
-  // If we're releasing the hold wait for a bit to allow the subscriber to read
-  // the file.
-  if (!$status) {
-    usleep(HoldTestSubscriber::WAIT * 2);
-  }
-}
-
-/**
- * Response hold.
- *
- * @param bool $status
- *   TRUE - enable hold, FALSE - disable hold.
- */
-function hold_test_response($status) {
-  $site_path = \Drupal::getContainer()->getParameter('site.path');
-  file_put_contents($site_path . '/hold_test_response.txt', $status);
-  // If we're releasing the hold wait for a bit to allow the subscriber to read
-  // the file.
-  if (!$status) {
-    usleep(HoldTestSubscriber::WAIT * 2);
-  }
-}
diff --git a/core/modules/system/tests/modules/hold_test/hold_test.services.yml b/core/modules/system/tests/modules/hold_test/hold_test.services.yml
deleted file mode 100644
index 309f219291..0000000000
--- a/core/modules/system/tests/modules/hold_test/hold_test.services.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-services:
-  hold_test.response:
-    class: Drupal\hold_test\EventSubscriber\HoldTestSubscriber
-    arguments: ['%site.path%']
-    tags:
-      - { name: event_subscriber }
diff --git a/core/modules/system/tests/modules/hold_test/src/EventSubscriber/HoldTestSubscriber.php b/core/modules/system/tests/modules/hold_test/src/EventSubscriber/HoldTestSubscriber.php
deleted file mode 100644
index 5ccb0ecb64..0000000000
--- a/core/modules/system/tests/modules/hold_test/src/EventSubscriber/HoldTestSubscriber.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-namespace Drupal\hold_test\EventSubscriber;
-
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Response subscriber to test hold.
- */
-class HoldTestSubscriber implements EventSubscriberInterface {
-
-  const HOLD_REQUEST = 'request';
-  const HOLD_RESPONSE = 'response';
-
-  /**
-   * Time in microseconds to wait for before checking if the file is updated.
-   *
-   * @var int
-   */
-  const WAIT = 100000;
-
-  /**
-   * The site path.
-   *
-   * @var string
-   */
-  protected $sitePath;
-
-  /**
-   * HoldTestSubscriber constructor.
-   *
-   * @param string $site_path
-   *   The site path.
-   */
-  public function __construct(string $site_path) {
-    $this->sitePath = $site_path;
-  }
-
-  /**
-   * Request hold.
-   */
-  public function onRequest() {
-    $this->hold(static::HOLD_REQUEST);
-  }
-
-  /**
-   * Response hold.
-   */
-  public function onRespond() {
-    $this->hold(static::HOLD_RESPONSE);
-  }
-
-  /**
-   * Hold process by type.
-   *
-   * @param string $type
-   *   Type of hold.
-   */
-  protected function hold($type) {
-    $path = "{$this->sitePath}/hold_test_$type.txt";
-    while ((bool) file_get_contents($path)) {
-      usleep(static::WAIT);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents(): array {
-    $events[KernelEvents::REQUEST][] = ['onRequest'];
-    $events[KernelEvents::RESPONSE][] = ['onRespond'];
-    return $events;
-  }
-
-}
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
index eb66398b57..35f7ac97aa 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\FunctionalJavascriptTests\Ajax;
 
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\Tests\DelayResponseTrait;
 
 /**
  * Tests the throbber.
@@ -11,6 +12,8 @@
  */
 class ThrobberTest extends WebDriverTestBase {
 
+  use DelayResponseTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -19,7 +22,6 @@ class ThrobberTest extends WebDriverTestBase {
     'views',
     'views_ui',
     'views_ui_test_field',
-    'hold_test',
     'block',
   ];
 
@@ -28,18 +30,6 @@ class ThrobberTest extends WebDriverTestBase {
    */
   protected $defaultTheme = 'stark';
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp(): void {
-    parent::setUp();
-
-    $admin_user = $this->drupalCreateUser([
-      'administer views',
-    ]);
-    $this->drupalLogin($admin_user);
-  }
-
   /**
    * Tests theming throbber element.
    */
@@ -47,6 +37,11 @@ public function testThemingThrobberElement() {
     $session = $this->getSession();
     $web_assert = $this->assertSession();
     $page = $session->getPage();
+    $admin_user = $this->drupalCreateUser([
+      'administer views',
+      'administer blocks',
+    ]);
+    $this->drupalLogin($admin_user);
 
     $custom_ajax_progress_indicator_fullscreen = <<<JS
       Drupal.theme.ajaxProgressIndicatorFullscreen = function () {
@@ -69,46 +64,45 @@ public function testThemingThrobberElement() {
 
     // Test theming fullscreen throbber.
     $session->executeScript($custom_ajax_progress_indicator_fullscreen);
-    hold_test_response(TRUE);
+    // Delay the response, so we have time to check the throbber before it's
+    // removed when the AJAX-response arrives.
+    $this->setDelayResponse();
     $page->clickLink('Content: Published (grouped)');
     $this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-fullscreen'), 'Custom ajaxProgressIndicatorFullscreen.');
-    hold_test_response(FALSE);
-    $web_assert->assertNoElementAfterWait('css', '.custom-ajax-progress-fullscreen');
+    // Note we set the timeout period to the amount we delayed the response by.
+    // This is done, so we're sure the response arrived and the throbber had a
+    // chance to be removed.
+    $web_assert->assertNoElementAfterWait('css', '.custom-ajax-progress-fullscreen', 100000);
+    $this->unsetDelayResponse();
 
     // Test theming throbber message.
     $web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-add-group"]');
     $session->executeScript($custom_ajax_progress_message);
-    hold_test_response(TRUE);
+    $this->setDelayResponse();
     $page->pressButton('Add another item');
     $this->assertNotNull($web_assert->waitForElement('css', '.ajax-progress-throbber .custom-ajax-progress-message'), 'Custom ajaxProgressMessage.');
-    hold_test_response(FALSE);
-    $web_assert->assertNoElementAfterWait('css', '.ajax-progress-throbber');
+    $web_assert->assertNoElementAfterWait('css', '.ajax-progress-throbber', 100000);
+    $this->unsetDelayResponse();
 
     // Test theming throbber.
     $web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-group-items-3-title"]');
     $session->executeScript($custom_ajax_progress_throbber);
-    hold_test_response(TRUE);
+    $this->setDelayResponse();
     $page->pressButton('Add another item');
     $this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-throbber'), 'Custom ajaxProgressThrobber.');
-    hold_test_response(FALSE);
-    $web_assert->assertNoElementAfterWait('css', '.custom-ajax-progress-throbber');
-  }
-
-  /**
-   * Tests progress throbber element position.
-   */
-  public function testProgressThrobberPosition() {
-    $this->drupalLogin($this->rootUser);
+    $web_assert->assertNoElementAfterWait('css', '.custom-ajax-progress-throbber', 100000);
+    $this->unsetDelayResponse();
 
+    //Test progress throbber position on a dropbutton in a table display.
     $this->drupalGet('/admin/structure/block');
     $this->clickLink('Place block');
-    hold_test_response(FALSE);
-    $this->assertSession()->waitForText('Place Block');
+    $web_assert->assertWaitOnAjaxRequest();
+    $this->assertNotEmpty($web_assert->waitForElementVisible('css', '#drupal-modal'));
+    $this->setDelayResponse();
     $this->clickLink('Place block');
-    hold_test_response(TRUE);
-    $this->assertSession()->elementExists('xpath', '//div[contains(@class, "dropbutton-wrapper")]/following-sibling::div[contains(@class, "ajax-progress-throbber")]');
-    hold_test_response(FALSE);
-    $this->assertSession()->assertNoElementAfterWait('css', '.ajax-progress-throbber');
+    $this->assertNotNull($web_assert->waitForElement('xpath', '//div[contains(@class, "dropbutton-wrapper")]/following-sibling::div[contains(@class, "ajax-progress-throbber")]'));
+    $web_assert->assertNoElementAfterWait('css', '.ajax-progress-throbber', 100000);
+    $this->unsetDelayResponse();
   }
 
 }
