diff --git a/core/drupalci.yml b/core/drupalci.yml
index 2085b9737b..0e2dc8735e 100644
--- a/core/drupalci.yml
+++ b/core/drupalci.yml
@@ -3,48 +3,11 @@
 # https://www.drupal.org/drupalorg/docs/drupal-ci/customizing-drupalci-testing
 build:
   assessment:
-    validate_codebase:
-      phplint:
-      csslint:
-        halt-on-fail: false
-      eslint:
-        # A test must pass eslinting standards check in order to continue processing.
-        halt-on-fail: false
-      phpcs:
-        # phpcs will use core's specified version of Coder.
-        sniff-all-files: false
-        halt-on-fail: false
     testing:
-      # 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'
-        testgroups: '--all'
-        suppress-deprecations: false
-        halt-on-fail: false
-      run_tests.kernel:
-        types: 'PHPUnit-Kernel'
-        testgroups: '--all'
-        suppress-deprecations: false
-        halt-on-fail: false
-      run_tests.simpletest:
-         types: 'Simpletest'
-         testgroups: '--all'
-         suppress-deprecations: false
-         halt-on-fail: false
-      run_tests.functional:
-        types: 'PHPUnit-Functional'
-        testgroups: '--all'
-        suppress-deprecations: false
-        halt-on-fail: false
       run_tests.javascript:
         concurrency: 15
         types: 'PHPUnit-FunctionalJavascript'
-        testgroups: '--all'
+        testgroups: '--class "Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest"'
         suppress-deprecations: false
         halt-on-fail: false
-      # Run nightwatch testing.
-      # @see https://www.drupal.org/project/drupal/issues/2869825
-      nightwatchjs:
+        repeat: 5
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
index 9d54f6a43a..f5b873f9ba 100644
--- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
@@ -107,26 +107,25 @@ public function testAdministrationPage() {
     // Test that users can filter by type.
     $page->selectFieldOption('Media type', 'Type One');
     $page->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForNoText('Turtle');
     $assert_session->pageTextContains('Dog');
-    $assert_session->pageTextNotContains('Turtle');
     $page->selectFieldOption('Media type', 'Type Two');
     $page->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Dog');
+    $this->waitForNoText('Dog');
     $assert_session->pageTextContains('Turtle');

     // Test that selecting elements as a part of bulk operations works.
     $page->selectFieldOption('Media type', '- Any -');
     $page->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Dog');
+
     // This tests that anchor tags clicked inside the preview are suppressed.
     $this->getSession()->executeScript('jQuery(".js-click-to-select-trigger a")[4].click()');
     $this->submitForm([], 'Apply to selected items');
+    $this->waitForNoText('Cat');
     $assert_session->pageTextContains('Dog');
-    $assert_session->pageTextNotContains('Cat');
     $this->submitForm([], 'Delete');
-    $assert_session->pageTextNotContains('Dog');
+    $this->waitForNoText('Dog');
     $assert_session->pageTextContains('Cat');

     // Test 'Select all media'.
@@ -135,7 +134,7 @@ public function testAdministrationPage() {
     $this->submitForm([], 'Apply to selected items');
     $this->getSession()->getPage()->pressButton('Delete');

-    $assert_session->pageTextNotContains('Cat');
+    $this->waitForNoText('Cat');
     $assert_session->pageTextNotContains('Turtle');
     $assert_session->pageTextNotContains('Snake');

@@ -228,8 +227,8 @@ public function testWidgetWithoutMediaTypes() {
     $field_empty_types_message = 'There are no allowed media types configured for this field. <a href="' . $field_empty_types_url->toString() . '">Edit the field settings</a> to select the allowed media types.';

     $field_null_types_url = new Url('entity.field_config.node_field_edit_form', [
-        'field_config' => 'node.basic_page.field_null_types_media',
-      ] + $route_bundle_params);
+      'field_config' => 'node.basic_page.field_null_types_media',
+    ] + $route_bundle_params);
     $field_null_types_message = 'There are no allowed media types configured for this field. <a href="' . $field_null_types_url->toString() . '">Edit the field settings</a> to select the allowed media types.';

     // Visit a node create page.
@@ -416,29 +415,27 @@ public function testWidget() {

     // Assert generic media library elements.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $this->assertFalse($assert_session->elementExists('css', '.media-library-select-all')->isVisible());
     $page->find('css', '.ui-dialog-titlebar-close')->click();

     // Assert that the media type menu is available when more than 1 type is
     // configured for the field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $menu = $assert_session->elementExists('css', '.media-library-menu');
+    $menu = $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $this->assertTrue($menu->hasLink('Type One'));
     $this->assertFalse($menu->hasLink('Type Two'));
     $this->assertTrue($menu->hasLink('Type Three'));
     $this->assertFalse($menu->hasLink('Type Four'));
     $page->find('css', '.ui-dialog-titlebar-close')->click();
-    $assert_session->assertWaitOnAjaxRequest();

     // Assert that the media type menu is available when the target_bundles
     // setting for the entity reference field is null. All types should be
     // allowed in this case.
-    $assert_session->elementExists('css', '.media-library-open-button[name^="field_null_types_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $menu = $assert_session->elementExists('css', '.media-library-menu');
+    $add_media_button = $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_null_types_media"]');
+    $this->assertNotEmpty($add_media_button);
+    $add_media_button->click();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $this->assertTrue($menu->hasLink('Type One'));
     $this->assertTrue($menu->hasLink('Type Two'));
     $this->assertTrue($menu->hasLink('Type Three'));
@@ -449,8 +446,8 @@ public function testWidget() {
     // Assert that the media type menu is not available when only 1 type is
     // configured for the field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_single_media_type"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementTextContains('css', '.media-library-selected-count', '0 of 1 item selected');
+    $this->waitForElementTextContains('.media-library-selected-count', '0 of 1 item selected');
+
     // Select a media item, assert the hidden selection field contains the ID of
     // the selected item.
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
@@ -463,69 +460,76 @@ public function testWidget() {

     // Assert the menu links can be sorted through the widget configuration.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $links = $page->findAll('css', '.media-library-menu a');
     $link_titles = [];
     foreach ($links as $link) {
       $link_titles[] = $link->getText();
     }
-    $expected_link_titles = ['Type Three (active tab)', 'Type One', 'Type Two', 'Type Four'];
+    $expected_link_titles = [
+      'Type Three (active tab)',
+      'Type One',
+      'Type Two',
+      'Type Four',
+    ];
     $this->assertSame($link_titles, $expected_link_titles);
     $this->drupalGet('admin/structure/types/manage/basic_page/form-display');
     $assert_session->buttonExists('field_twin_media_settings_edit')->press();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->buttonExists('Show row weights')->press();
+    $toggle_weight_button = $this->assertElementExistsAfterWait('css', '#field-twin-media .tabledrag-toggle-weight');
+    $toggle_weight_button->press();
     $assert_session->fieldExists('fields[field_twin_media][settings_edit_form][settings][media_types][type_one][weight]')->selectOption(0);
     $assert_session->fieldExists('fields[field_twin_media][settings_edit_form][settings][media_types][type_three][weight]')->selectOption(1);
     $assert_session->fieldExists('fields[field_twin_media][settings_edit_form][settings][media_types][type_four][weight]')->selectOption(2);
     $assert_session->fieldExists('fields[field_twin_media][settings_edit_form][settings][media_types][type_two][weight]')->selectOption(3);
     $assert_session->buttonExists('Save')->press();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->buttonExists('Hide row weights')->press();
+
     $this->drupalGet('node/add/basic_page');
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $link_titles = array_map(function ($link) {
       return $link->getText();
     }, $page->findAll('css', '.media-library-menu a'));
-    $this->assertSame($link_titles, ['Type One (active tab)', 'Type Three', 'Type Four', 'Type Two']);
+    $this->assertSame($link_titles, [
+      'Type One (active tab)',
+      'Type Three',
+      'Type Four',
+      'Type Two',
+    ]);
     $page->find('css', '.ui-dialog-titlebar-close')->click();

     // Assert media is only visible on the tab for the related media type.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Dog');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Dog');
     $assert_session->pageTextContains('Bear');
     $assert_session->pageTextNotContains('Turtle');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementExists('named', ['link', 'Type Three (active tab)']);
-    $assert_session->pageTextNotContains('Dog');
+    $this->assertElementExistsAfterWait('named', ['link', 'Type Three (active tab)']);
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForNoText('Dog');
     $assert_session->pageTextNotContains('Bear');
     $assert_session->pageTextNotContains('Turtle');
     $page->find('css', '.ui-dialog-titlebar-close')->click();

     // Assert the exposed name filter of the view.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $session = $this->getSession();
     $session->getPage()->fillField('Name', 'Dog');
     $session->getPage()->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Dog');
+    $this->waitForText('Dog');
     $assert_session->pageTextNotContains('Bear');
     $session->getPage()->fillField('Name', '');
     $session->getPage()->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Dog');
+    $this->waitForText('Dog');
     $assert_session->pageTextContains('Bear');
     $page->find('css', '.ui-dialog-titlebar-close')->click();

     // Assert the media library contains header links to switch between the grid
     // and table display.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementExists('css', '.media-library-view .media-library-item--grid');
+    $this->assertElementExistsAfterWait('css', '.media-library-view .media-library-item--grid');
     $assert_session->elementNotExists('css', '.media-library-view .media-library-item--table');
     // Assert the 'Apply filter' button is not moved to the button pane.
     $button_pane = $assert_session->elementExists('css', '.ui-dialog-buttonpane');
@@ -534,9 +538,9 @@ public function testWidget() {
     $assert_session->linkExists('Grid');
     $page->clickLink('Table');
     // Assert the display change is correctly announced for screen readers.
-    $this->assertNotEmpty($assert_session->waitForText('Loading table view.'));
-    $this->assertNotEmpty($assert_session->waitForText('Changed to table view.'));
-    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.media-library-view .media-library-item--table'));
+    $this->waitForText('Loading table view.');
+    $this->waitForText('Changed to table view.');
+    $this->assertElementExistsAfterWait('css', '.media-library-view .media-library-item--table');
     $assert_session->elementNotExists('css', '.media-library-view .media-library-item--grid');
     // Assert the 'Apply filter' button is not moved to the button pane.
     $assert_session->buttonExists('Insert selected', $button_pane);
@@ -547,17 +551,16 @@ public function testWidget() {
     // Assert the exposed filters can be applied.
     $page->fillField('Name', 'Dog');
     $page->pressButton('Apply filters');
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Dog');
+    $this->waitForText('Dog');
     $assert_session->pageTextNotContains('Bear');
     $assert_session->pageTextNotContains('Turtle');
     $page->checkField('Select Dog');
     $assert_session->linkExists('Table');
     $page->clickLink('Grid');
     // Assert the display change is correctly announced for screen readers.
-    $this->assertNotEmpty($assert_session->waitForText('Loading grid view.'));
-    $this->assertNotEmpty($assert_session->waitForText('Changed to grid view.'));
-    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.media-library-view .media-library-item--grid'));
+    $this->waitForText('Loading grid view.');
+    $this->waitForText('Changed to grid view.');
+    $this->assertElementExistsAfterWait('css', '.media-library-view .media-library-item--grid');
     $assert_session->elementNotExists('css', '.media-library-view .media-library-item--table');
     // Assert the exposed filters are persisted when changing display.
     $this->assertSame('Dog', $page->findField('Name')->getValue());
@@ -568,67 +571,62 @@ public function testWidget() {
     $assert_session->linkExists('Table');
     // Select the item.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added one media item.');
     // Ensure that the selection completed successfully.
+    $this->waitForText('Dog');
     $assert_session->pageTextNotContains('Add or select media');
-    $assert_session->pageTextContains('Dog');
     $assert_session->pageTextNotContains('Bear');
     $assert_session->pageTextNotContains('Turtle');
     // Clear the selection.
     $assert_session->elementAttributeContains('css', '.media-library-item__remove', 'aria-label', 'Remove Dog');
     $assert_session->elementExists('css', '.media-library-item__remove')->click();
-    $this->assertNotEmpty($assert_session->waitForText('Removed Dog.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Removed Dog.');

     // Assert adding a single media item and removing it.
-    $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"]')->click();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $this->assertGreaterThanOrEqual(1, count($checkboxes));
     $checkboxes[0]->click();
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added one media item.');
     // Assert the focus is set back on the open button of the media field.
     $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .js-media-library-open-button").is(":focus")');
     $assert_session->elementAttributeContains('css', '.media-library-item__remove', 'aria-label', 'Remove Dog');
     $assert_session->elementExists('css', '.media-library-item__remove')->click();
-    $this->assertNotEmpty($assert_session->waitForText('Removed Dog.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Removed Dog.');
     // Assert the focus is set back on the open button of the media field.
     $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .js-media-library-open-button").is(":focus")');

     // Assert we can select the same media item twice.
-    $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"]')->click();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $page->checkField('Select Dog');
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added one media item.');
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $page->checkField('Select Dog');
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added one media item.');
+
     // Assert the same has been added twice and remove the items again.
+    $this->assertElementExistsAfterWait('css', '[name="field_twin_media[selection][1][target_id]"]');
     $this->assertCount(2, $page->findAll('css', '.field--name-field-twin-media .media-library-item'));
     $assert_session->hiddenFieldValueEquals('field_twin_media[selection][0][target_id]', 4);
     $assert_session->hiddenFieldValueEquals('field_twin_media[selection][1][target_id]', 4);
     $assert_session->elementExists('css', '.media-library-item__remove')->click();
-    $this->assertNotEmpty($assert_session->waitForText('Removed Dog.'));
+    $this->waitForText('Removed Dog.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementExists('css', '.media-library-item__remove')->click();
-    $this->assertNotEmpty($assert_session->waitForText('Removed Dog.'));
+    $this->assertElementExistsAfterWait('css', '.media-library-item__remove')->click();
+    $this->waitForText('Removed Dog.');
     $assert_session->assertWaitOnAjaxRequest();

     // Assert the selection is persistent in the media library modal, and
     // the number of selected items is displayed correctly.
-    $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"]')->click();
     // Assert the number of selected items is displayed correctly.
-    $assert_session->elementExists('css', '.media-library-selected-count');
+    $this->assertElementExistsAfterWait('css', '.media-library-selected-count');
     $assert_session->elementTextContains('css', '.media-library-selected-count', '0 of 2 items selected');
     $assert_session->elementAttributeContains('css', '.media-library-selected-count', 'role', 'status');
     $assert_session->elementAttributeContains('css', '.media-library-selected-count', 'aria-live', 'polite');
@@ -660,8 +658,10 @@ public function testWidget() {
     // the modal.
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');
     $page->clickLink('Type One');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-two .active-tab');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $selected_checkboxes = [];
     foreach ($checkboxes as $checkbox) {
@@ -675,6 +675,7 @@ public function testWidget() {
     // Add to selection from another type.
     $page->clickLink('Type Two');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-two .active-tab');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $this->assertCount(4, $checkboxes);
     $checkboxes[0]->click();
@@ -690,22 +691,22 @@ public function testWidget() {
     // Assert the checkboxes are also disabled on other pages.
     $page->clickLink('Type One');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-one .active-tab');
     $this->assertTrue($checkboxes[0]->hasAttribute('disabled'));
     $this->assertFalse($checkboxes[1]->hasAttribute('disabled'));
     $this->assertTrue($checkboxes[2]->hasAttribute('disabled'));
     $this->assertTrue($checkboxes[3]->hasAttribute('disabled'));
     // Select the items.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added 2 media items.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added 2 media items.');
     // Assert the open button is disabled.
-    $open_button = $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]');
+    $open_button = $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"]');
     $this->assertTrue($open_button->hasAttribute('data-disabled-focus'));
     $this->assertTrue($open_button->hasAttribute('disabled'));
     $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .media-library-open-button").is(":disabled")');

     // Ensure that the selection completed successfully.
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->elementTextNotContains('css', '#field_twin_media-media-library-wrapper', 'Dog');
     $assert_session->elementTextContains('css', '#field_twin_media-media-library-wrapper', 'Cat');
     $assert_session->elementTextContains('css', '#field_twin_media-media-library-wrapper', 'Turtle');
@@ -714,12 +715,11 @@ public function testWidget() {
     // Remove "Cat" (happens to be the first remove button on the page).
     $assert_session->elementAttributeContains('css', '.media-library-item__remove', 'aria-label', 'Remove Cat');
     $assert_session->elementExists('css', '.media-library-item__remove')->click();
-    $this->assertNotEmpty($assert_session->waitForText('Removed Cat.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Removed Cat.');
     // Assert the focus is set to the wrapper of the other selected item.
     $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .media-library-item").is(":focus")');
+    $this->assertElementExistsAfterWait('css', '[aria-label="Remove Turtle"]');
     $assert_session->elementTextNotContains('css', '#field_twin_media-media-library-wrapper', 'Cat');
-    $assert_session->elementTextContains('css', '#field_twin_media-media-library-wrapper', 'Turtle');
     // Assert the open button is no longer disabled.
     $open_button = $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]');
     $this->assertFalse($open_button->hasAttribute('data-disabled-focus'));
@@ -728,14 +728,13 @@ public function testWidget() {

     // Open the media library again and select another item.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $this->assertGreaterThanOrEqual(1, count($checkboxes));
     $checkboxes[0]->click();
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementTextContains('css', '#field_twin_media-media-library-wrapper', 'Dog');
+    $this->waitForText('Added one media item.');
+    $this->assertElementExistsAfterWait('css', '[aria-label="Remove Dog"]');
     $assert_session->elementTextNotContains('css', '#field_twin_media-media-library-wrapper', 'Cat');
     $assert_session->elementTextContains('css', '#field_twin_media-media-library-wrapper', 'Turtle');
     $assert_session->elementTextNotContains('css', '#field_twin_media-media-library-wrapper', 'Snake');
@@ -746,7 +745,7 @@ public function testWidget() {

     // Assert the selection is cleared when the modal is closed.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $this->assertGreaterThanOrEqual(4, count($checkboxes));
     // Nothing is selected yet.
@@ -767,7 +766,7 @@ public function testWidget() {
     // Close the dialog, reopen it and assert not is selected again.
     $page->find('css', '.ui-dialog-titlebar-close')->click();
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input');
     $this->assertGreaterThanOrEqual(4, count($checkboxes));
     $this->assertFalse($checkboxes[0]->isChecked());
@@ -802,7 +801,7 @@ public function testWidget() {
     $assert_session->pageTextContains('Turtle');
     $assert_session->pageTextNotContains('Snake');
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $assert_session->pageTextContains('Add or select media');
     // Select all media items of type one (should also contain Dog, again).
     $checkbox_selector = '.media-library-view .js-click-to-select-checkbox input';
@@ -813,9 +812,8 @@ public function testWidget() {
     $checkboxes[2]->click();
     $checkboxes[3]->click();
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added 4 media items.'));
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Dog');
+    $this->waitForText('Added 4 media items.');
+    $this->waitForText('Dog');
     $assert_session->pageTextContains('Cat');
     $assert_session->pageTextContains('Bear');
     $assert_session->pageTextContains('Horse');
@@ -852,16 +850,15 @@ public function testWidgetAnonymous() {

     // Add to the unlimited cardinality field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');

     // Select the first media item (should be Dog).
-    $page->find('css', '.media-library-view .js-click-to-select-checkbox input')->click();
+    $this->assertElementExistsAfterWait('css', '.media-library-view .js-click-to-select-checkbox input')->click();
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Added one media item.');

     // Ensure that the selection completed successfully.
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains('Dog');

     // Save the form.
@@ -910,8 +907,8 @@ public function testWidgetUpload() {
     // Visit a node create page and open the media library.
     $this->drupalGet('node/add/basic_page');
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');

     // Assert the upload form is not visible for default tab type_three without
     // the proper permissions.
@@ -921,13 +918,14 @@ public function testWidgetUpload() {
     // type_one.
     $page->clickLink('Type One');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementNotExists('css', '.media-library-add-form');
+    $assert_session->assertNoElementAfterWait('css', '.media-library-add-form');

     // Assert the upload form is visible for type_four.
     $page->clickLink('Type Four');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-four .active-tab');
+    $this->waitForText('Maximum 2 files.');
     $assert_session->fieldExists('Add files');
-    $assert_session->pageTextContains('Maximum 2 files.');

     // Create a user that can create media for all media types.
     $user = $this->drupalCreateUser([
@@ -948,8 +946,8 @@ public function testWidgetUpload() {

     // Add to the twin media field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');

     // Assert the upload form is now visible for default tab type_three.
     $assert_session->elementExists('css', '.media-library-add-form');
@@ -961,7 +959,7 @@ public function testWidgetUpload() {
     $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri));
     $assert_session->assertWaitOnAjaxRequest();
     $this->assertJsCondition('jQuery(".media-library-add-form__added-media").is(":focus")');
-    $assert_session->pageTextContains('The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.');
+    $this->waitForText('The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.');
     $assert_session->elementAttributeContains('css', '.media-library-add-form__added-media', 'aria-label', 'Added media items');
     $assert_session->elementExists('css', '.media-library-add-form--with-input');
     $assert_session->elementNotExists('css', '.media-library-add-form--without-input');
@@ -980,10 +978,11 @@ public function testWidgetUpload() {
     $assert_session->fieldValueEquals('Name', $png_image->filename);
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Alternative text field is required');
+    $this->waitForText('Alternative text field is required');
     $page->fillField('Alternative text', $this->randomString());
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select');
     $assert_session->assertWaitOnAjaxRequest();
+
     // The file should be permanent now.
     $files = $file_storage->loadMultiple();
     $file = array_pop($files);
@@ -994,7 +993,7 @@ public function testWidgetUpload() {
     // Ensure the media item was saved to the library and automatically
     // selected. The added media items should be in the first position of the
     // add form.
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $assert_session->pageTextContains($png_image->filename);
     $assert_session->fieldValueEquals('media_library_select_form[0]', $added_media->id());
     $assert_session->checkboxChecked('media_library_select_form[0]');
@@ -1002,38 +1001,42 @@ public function testWidgetUpload() {
     $assert_session->hiddenFieldValueEquals('current_selection', $added_media->id());
     // Ensure the created item is added in the widget.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains($png_image->filename);
+    $assert_session->elementExists('css', "*:contains('$png_image->filename')");

     // Remove the item.
     $assert_session->elementExists('css', '.media-library-item__remove')->click();
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains($png_image->filename);
+    $this->waitForNoText($png_image->filename);

     // Assert we can also directly insert uploaded files in the widget.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');
     $png_uri_2 = $file_system->copy($png_image->uri, 'public://');
     $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_2));
     $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Alternative text');
     $page->fillField('Alternative text', $this->randomString());
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and insert');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
-    $assert_session->pageTextContains($file_system->basename($png_uri_2));
+    $this->waitForNoText('Add or select media');
+    $this->waitForText($file_system->basename($png_uri_2));

     // Also make sure that we can upload to the unlimited cardinality field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');

     // Select a media item to check if the selection is persisted when adding
     // new items.
@@ -1041,11 +1044,12 @@ public function testWidgetUpload() {
     $checkbox = $page->findField("Select $existing_media_name");
     $selected_item_id = $checkbox->getAttribute('value');
     $checkbox->click();
-    $assert_session->pageTextContains('1 item selected');
+    $this->waitForText('1 item selected');
     $assert_session->hiddenFieldValueEquals('current_selection', $selected_item_id);
     $png_uri_3 = $file_system->copy($png_image->uri, 'public://');
     $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_3));
     $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('The media item has been created but has not yet been saved.');
     $assert_session->checkboxChecked("Select $existing_media_name");
     $page->fillField('Name', 'Unlimited Cardinality Image');
     $page->fillField('Alternative text', $this->randomString());
@@ -1058,7 +1062,7 @@ public function testWidgetUpload() {
     // Ensure the media item was saved to the library and automatically
     // selected. The added media items should be in the first position of the
     // add form.
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $assert_session->pageTextContains('Unlimited Cardinality Image');
     $assert_session->fieldValueEquals('media_library_select_form[0]', $added_media->id());
     $assert_session->checkboxChecked('media_library_select_form[0]');
@@ -1078,26 +1082,27 @@ public function testWidgetUpload() {
     $this->assertCount(2, $selected_checkboxes);
     // Ensure the created item is added in the widget.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains('Unlimited Cardinality Image');

     // Assert we can now only upload one more media item.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Four');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-four .active-tab');
+    $this->waitForText('One file only.');
     $this->assertFalse($assert_session->fieldExists('Add file')->hasAttribute('multiple'));
-    $assert_session->pageTextContains('One file only.');

     // Assert media type four should only allow jpg files by trying a png file
     // first.
     $png_uri_4 = $file_system->copy($png_image->uri, 'public://');
     $page->attachFileToField('Add file', $file_system->realpath($png_uri_4));
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Only files with the following extensions are allowed');
+    $this->waitForText('Only files with the following extensions are allowed');
     // Assert that jpg files are accepted by type four.
     $jpg_uri_2 = $file_system->copy($jpg_image->uri, 'public://');
     $page->attachFileToField('Add file', $file_system->realpath($jpg_uri_2));
@@ -1112,26 +1117,27 @@ public function testWidgetUpload() {
     $files = $file_storage->loadMultiple();
     $file = array_pop($files);
     $this->assertSame('public://type-four-extra-dir', $file_system->dirname($file->getFileUri()));
-    $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select');
+    $this->assertElementExistsAfterWait('css', '.ui-dialog-buttonpane')->pressButton('Save and select');
     $assert_session->assertWaitOnAjaxRequest();
     // Ensure the media item was saved to the library and automatically
     // selected.
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $assert_session->pageTextContains($file_system->basename($jpg_uri_2));
     // Ensure the created item is added in the widget.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
-    $assert_session->pageTextContains($file_system->basename($jpg_uri_2));
+    $this->waitForNoText('Add or select media');
+    $this->waitForText($file_system->basename($jpg_uri_2));

     // Assert we can also remove selected items from the selection area in the
     // upload form.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');
     $checkbox = $page->findField("Select $existing_media_name");
     $selected_item_id = $checkbox->getAttribute('value');
     $checkbox->click();
@@ -1141,7 +1147,7 @@ public function testWidgetUpload() {
     $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_5));
     $assert_session->assertWaitOnAjaxRequest();
     // Assert the pre-selected items are shown.
-    $selection_area = $assert_session->elementExists('css', '.media-library-add-form__selected-media');
+    $selection_area = $this->assertElementExistsAfterWait('css', '.media-library-add-form__selected-media');
     $assert_session->elementExists('css', 'summary', $selection_area)->click();
     $assert_session->checkboxChecked("Select $existing_media_name", $selection_area);
     $page->uncheckField("Select $existing_media_name");
@@ -1156,36 +1162,37 @@ public function testWidgetUpload() {
     $media_items = Media::loadMultiple();
     $added_media = array_pop($media_items);
     $added_media_name = $added_media->label();
-    $assert_session->pageTextContains('1 item selected');
+    $this->waitForText('1 item selected');
     $assert_session->checkboxChecked("Select $added_media_name");
     $assert_session->checkboxNotChecked("Select $existing_media_name");
     $assert_session->hiddenFieldValueEquals('current_selection', $added_media->id());
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
-    $assert_session->pageTextContains($file_system->basename($png_uri_5));
+    $this->waitForNoText('Add or select media');
+    $this->waitForText($file_system->basename($png_uri_5));

     // Assert removing an uploaded media item before save works as expected.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');
     $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri));
     $assert_session->assertWaitOnAjaxRequest();
     // Assert the focus is shifted to the added media items.
     $this->assertJsCondition('jQuery(".media-library-add-form__added-media").is(":focus")');
     // Assert the media item fields are shown and the vertical tabs are no
     // longer shown.
-    $assert_session->elementExists('css', '.media-library-add-form__fields');
+    $this->assertElementExistsAfterWait('css', '.media-library-add-form__fields');
     $assert_session->elementNotExists('css', '.media-library-menu');
     // Press the 'Remove button' and assert the user is sent back to the media
     // library.
     $assert_session->elementExists('css', '.media-library-add-form__remove-button')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     // Assert the remove message is shown.
-    $assert_session->pageTextContains("The media item $png_image->filename has been removed.");
+    $this->waitForText("The media item $png_image->filename has been removed.");
     // Assert the focus is shifted to the first tabbable element of the add
     // form, which should be the source field.
     $this->assertJsCondition('jQuery("#media-library-add-form-wrapper :tabbable").is(":focus")');
@@ -1195,10 +1202,11 @@ public function testWidgetUpload() {

     // Assert uploading multiple files.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-three .active-tab');
     // Assert the existing items are remembered when adding and removing media.
     $checkbox = $page->findField("Select $existing_media_name");
     $checkbox->click();
@@ -1216,7 +1224,7 @@ public function testWidgetUpload() {
     $assert_session->assertWaitOnAjaxRequest();
     // Assert the media item fields are shown and the vertical tabs are no
     // longer shown.
-    $assert_session->elementExists('css', '.media-library-add-form__fields');
+    $this->assertElementExistsAfterWait('css', '.media-library-add-form__fields');
     $assert_session->elementNotExists('css', '.media-library-menu');
     // Assert all files have been added.
     $assert_session->fieldValueEquals('media[0][fields][name][0][value]', $filenames[0]);
@@ -1278,7 +1286,7 @@ public function testWidgetOEmbed() {

     // Add to the unlimited media field.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     $assert_session->pageTextContains('Add or select media');

     // Assert the default tab for media type one does not have an oEmbed form.
@@ -1287,16 +1295,19 @@ public function testWidgetOEmbed() {
     // Assert other media types don't have the oEmbed form fields.
     $page->clickLink('Type Three');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->waitForText('Add files');
     $assert_session->fieldNotExists('Add Type Five via URL');

     // Assert we can add an oEmbed video to media type five.
     $page->clickLink('Type Five');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-five .active-tab');
     $page->fillField('Add Type Five via URL', $youtube_url);
     $assert_session->pageTextContains('Allowed providers: YouTube, Vimeo.');
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
     // Assert the name field contains the remote video title.
+    $this->waitForText('The media item has been created but has not yet been saved.');
     $assert_session->fieldValueEquals('Name', $youtube_title);
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select');
     $assert_session->assertWaitOnAjaxRequest();
@@ -1308,41 +1319,42 @@ public function testWidgetOEmbed() {
     // Ensure the media item was saved to the library and automatically
     // selected. The added media items should be in the first position of the
     // add form.
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $assert_session->pageTextContains($youtube_title);
     $assert_session->fieldValueEquals('media_library_select_form[0]', $added_media->id());
     $assert_session->checkboxChecked('media_library_select_form[0]');

     // Assert the created oEmbed video is correctly added to the widget.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains($youtube_title);

     // Open the media library again for the unlimited field and go to the tab
     // for media type five.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Five');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-five .active-tab');

     // Assert the video is available on the tab.
-    $assert_session->pageTextContains($youtube_title);
-
+    $this->waitForText($youtube_title);
     // Assert we can only add supported URLs.
     $page->fillField('Add Type Five via URL', 'https://www.youtube.com/');
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('No matching provider found.');
+    $this->waitForText('No matching provider found.');
+
     // Assert we can not add a video ID that doesn't exist. We need to use a
     // video ID that will not be filtered by the regex, because otherwise the
     // message 'No matching provider found.' will be returned.
     $page->fillField('Add Type Five via URL', 'https://www.youtube.com/watch?v=PWjcqE3QKBg1');
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Could not retrieve the oEmbed resource.');
+    $this->waitForText('Could not retrieve the oEmbed resource.');

     // Select a media item to check if the selection is persisted when adding
     // new items.
@@ -1368,7 +1380,7 @@ public function testWidgetOEmbed() {
     // Ensure the media item was saved to the library and automatically
     // selected. The added media items should be in the first position of the
     // add form.
-    $assert_session->pageTextContains('Add or select media');
+    $this->waitForText('Add or select media');
     $assert_session->pageTextContains('Custom video title');
     $assert_session->fieldValueEquals('media_library_select_form[0]', $added_media->id());
     $assert_session->checkboxChecked('media_library_select_form[0]');
@@ -1388,33 +1400,34 @@ public function testWidgetOEmbed() {
     $this->assertCount(2, $selected_checkboxes);
     // Ensure the created item is added in the widget.
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added 2 media items.'));
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForText('Added 2 media items.');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains('Custom video title');

     // Assert we can directly insert added oEmbed media in the widget.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Five');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-five .active-tab');
     $page->fillField('Add Type Five via URL', $vimeo_url);
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and insert');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->assertElementExistsAfterWait('css', '.ui-dialog-buttonpane')->pressButton('Save and insert');
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains($vimeo_title);

     // Assert we can remove selected items from the selection area in the oEmbed
     // form.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Five');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-five .active-tab');
     $checkbox = $page->findField("Select $vimeo_title");
     $selected_item_id = $checkbox->getAttribute('value');
     $checkbox->click();
@@ -1422,8 +1435,8 @@ public function testWidgetOEmbed() {
     $page->fillField('Add Type Five via URL', $youtube_url);
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
+    $selection_area = $this->assertElementExistsAfterWait('css', '.media-library-add-form__selected-media');
     $page->fillField('Name', 'Another video');
-    $selection_area = $assert_session->elementExists('css', '.media-library-add-form__selected-media');
     $assert_session->elementExists('css', 'summary', $selection_area)->click();
     $assert_session->checkboxChecked("Select $vimeo_title", $selection_area);
     $page->uncheckField("Select $vimeo_title");
@@ -1436,22 +1449,23 @@ public function testWidgetOEmbed() {
     $assert_session->assertWaitOnAjaxRequest();
     $media_items = Media::loadMultiple();
     $added_media = array_pop($media_items);
-    $assert_session->pageTextContains('1 item selected');
+    $this->waitForText('1 item selected');
     $assert_session->checkboxChecked('Select Another video');
     $assert_session->checkboxNotChecked("Select $vimeo_title");
     $assert_session->hiddenFieldValueEquals('current_selection', $added_media->id());
     $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Insert selected');
-    $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
+    $this->waitForText('Added one media item.');
     $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextNotContains('Add or select media');
+    $this->waitForNoText('Add or select media');
     $assert_session->pageTextContains('Another video');

     // Assert removing an added oEmbed media item before save works as expected.
     $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click();
-    $assert_session->assertWaitOnAjaxRequest();
-    $assert_session->pageTextContains('Add or select media');
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
+    $this->waitForText('Add or select media');
     $page->clickLink('Type Five');
     $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu-type-five .active-tab');
     $page->fillField('Add Type Five via URL', $youtube_url);
     $page->pressButton('Add');
     $assert_session->assertWaitOnAjaxRequest();
@@ -1459,14 +1473,14 @@ public function testWidgetOEmbed() {
     $this->assertJsCondition('jQuery(".media-library-add-form__added-media").is(":focus")');
     // Assert the media item fields are shown and the vertical tabs are no
     // longer shown.
-    $assert_session->elementExists('css', '.media-library-add-form__fields');
+    $this->assertElementExistsAfterWait('css', '.media-library-add-form__fields');
     $assert_session->elementNotExists('css', '.media-library-menu');
     // Press the 'Remove button' and assert the user is sent back to the media
     // library.
     $assert_session->elementExists('css', '.media-library-add-form__remove-button')->click();
-    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertElementExistsAfterWait('css', '.media-library-menu');
     // Assert the remove message is shown.
-    $assert_session->pageTextContains("The media item $youtube_title has been removed.");
+    $this->waitForText("The media item $youtube_title has been removed.");
     // Assert the focus is shifted to the first tabbable element of the add
     // form, which should be the source field.
     $this->assertJsCondition('jQuery("#media-library-add-form-wrapper :tabbable").is(":focus")');
@@ -1474,4 +1488,50 @@ public function testWidgetOEmbed() {
     $assert_session->elementExists('css', '.media-library-menu');
   }

+  /**
+   * Asserts that text does not appear on page after a wait.
+   */
+  protected function waitForNoText($text) {
+    $assert_session = $this->assertSession();
+    $assert_session->assertNoElementAfterWait('css', "[data-off-canvas-main-canvas] :contains('$text')");
+  }
+
+  /**
+   * Asserts that text appears on page after a wait.
+   */
+  protected function waitForText($text) {
+    $assert_session = $this->assertSession();
+    $this->assertNotEmpty($assert_session->waitForText($text));
+  }
+
+  /**
+   * Asserts that text appears on page after a wait.
+   */
+  protected function waitForElementTextContains($selector, $text) {
+    $assert_session = $this->assertSession();
+    $element = $assert_session->waitForElement('css', "$selector:contains('$text')");
+    $this->assertNotEmpty($element);
+  }
+
+  /**
+   * Waits for the specified selector and returns it if not empty.
+   *
+   * @param string $selector
+   *   The selector engine name. See ElementInterface::findAll() for the
+   *   supported selectors.
+   * @param string|array $locator
+   *   The selector locator.
+   * @param int $timeout
+   *   (Optional) Timeout in milliseconds, defaults to 10000.
+   *
+   * @return \Behat\Mink\Element\NodeElement
+   *   The page element node if found. If not found, the test fails.
+   */
+  protected function assertElementExistsAfterWait($selector, $locator, $timeout = 10000) {
+    $assert_session = $this->assertSession();
+    $element = $assert_session->waitForElement($selector, $locator);
+    $this->assertNotEmpty($element);
+    return $element;
+  }
+
 }
