diff --git a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php index 810aff4799df81ffa89ee493313b3d02247d8175..232732a38a4beef6c61b706b9721513c19d4663c 100644 --- a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php +++ b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php @@ -51,6 +51,11 @@ public function viewsForm(array &$form, FormStateInterface $form_state) { 'class' => ['media-library-views-form', 'js-media-library-views-form'], ]; + // Add an attribute that identifies the media type displayed in the form. + if (isset($this->view->args[0])) { + $form['#attributes']['data-drupal-media-type'] = $this->view->args[0]; + } + // Render checkboxes for all rows. $form[$this->options['id']]['#tree'] = TRUE; foreach ($this->view->result as $row_index => $row) { diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php index efc9cffb32fca1c24c4cce67854adcb23000086d..5da6ddc42ce47d44a7b3083ab431dff74cb7215c 100644 --- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php @@ -128,19 +128,18 @@ public function testAdministrationPage() { // Test that users can filter by type. $page->selectFieldOption('Media type', 'Type One'); $page->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextContains('Dog'); - $assert_session->pageTextNotContains('Turtle'); + $this->waitForText('Dog'); + $this->waitForNoText('Turtle'); $page->selectFieldOption('Media type', 'Type Two'); $page->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Dog'); - $assert_session->pageTextContains('Turtle'); + $this->waitForNoText('Dog'); + $this->waitForText('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'); @@ -304,30 +303,25 @@ public function testWidgetWithoutMediaTypes() { * Tests that the integration with Views works correctly. */ public function testViewsAdmin() { - $assert_session = $this->assertSession(); $page = $this->getSession()->getPage(); // Assert that the widget can be seen and that there are 8 items. $this->drupalGet('/admin/structure/views/view/media_library/edit/widget'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementsCount('css', '.media-library-item', 8); + $this->waitForElementsCount('css', '.media-library-item', 8); // Assert that filtering works in live preview. $page->find('css', '.media-library-view .view-filters')->fillField('name', 'snake'); $page->find('css', '.media-library-view .view-filters')->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementsCount('css', '.media-library-item', 1); + $this->waitForElementsCount('css', '.media-library-item', 1); // Test the same routine but in the view for the table wiget. $this->drupalGet('/admin/structure/views/view/media_library/edit/widget_table'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementsCount('css', '.media-library-item', 8); + $this->waitForElementsCount('css', '.media-library-item', 8); // Assert that filtering works in live preview. $page->find('css', '.media-library-view .view-filters')->fillField('name', 'snake'); $page->find('css', '.media-library-view .view-filters')->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementsCount('css', '.media-library-item', 1); + $this->waitForElementsCount('css', '.media-library-item', 1); // We cannot test clicking the 'Insert selected' button in either view // because we expect an AJAX error, which would always throw an exception @@ -444,23 +438,19 @@ public function testWidget() { $assert_session->pageTextContains('Empty types media'); // 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->openMediaLibraryForField('field_unlimited_media'); + $this->waitForText('Add or select media'); $this->assertFalse($assert_session->elementExists('css', '.media-library-select-all')->isVisible()); $assert_session->elementExists('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->openMediaLibraryForField('field_unlimited_media'); $this->assertTrue($menu->hasLink('Show Type One media (selected)')); $this->assertFalse($menu->hasLink('Type Two')); $this->assertTrue($menu->hasLink('Type Three')); $this->assertFalse($menu->hasLink('Type Four')); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); // Assert the active tab is set correctly. $this->assertFalse($menu->hasLink('Show Type One media (selected)')); $this->assertTrue($menu->hasLink('Show Type Three media (selected)')); @@ -468,23 +458,18 @@ public function testWidget() { // is clicked. $this->assertJsCondition('jQuery("#media-library-content :tabbable:first").is(":focus")'); $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); - $assert_session->assertWaitOnAjaxRequest(); // Assert that there are no links in the media library view. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->elementNotExists('css', '.media-library-item__name a'); $assert_session->elementNotExists('css', '.media-library-view .media-library-item__edit'); $assert_session->elementNotExists('css', '.media-library-view .media-library-item__remove'); $assert_session->elementExists('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'); + $menu = $this->openMediaLibraryForField('field_null_types_media'); $this->assertTrue($menu->hasLink('Type One')); $this->assertTrue($menu->hasLink('Type Two')); $this->assertTrue($menu->hasLink('Type Three')); @@ -494,9 +479,9 @@ 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->openMediaLibraryForField('field_single_media_type', '.media-library-wrapper'); + $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'); @@ -508,8 +493,7 @@ public function testWidget() { $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); // 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->openMediaLibraryForField('field_twin_media'); $links = $page->findAll('css', '.media-library-menu a'); $link_titles = []; foreach ($links as $link) { @@ -519,18 +503,15 @@ public function testWidget() { $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(); + $this->assertElementExistsAfterWait('css', '#field-twin-media .tabledrag-toggle-weight')->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->openMediaLibraryForField('field_twin_media'); $link_titles = array_map(function ($link) { return $link->getText(); }, $page->findAll('css', '.media-library-menu a')); @@ -538,28 +519,22 @@ public function testWidget() { $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); // Assert the announcements for media type navigation in the media library. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); + $this->switchToMediaType('Three'); $this->assertNotEmpty($assert_session->waitForText('Showing Type Three media.')); - $page->clickLink('Type One'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('One'); $this->assertNotEmpty($assert_session->waitForText('Showing Type One media.')); // Assert the links can be triggered by via the spacebar. $assert_session->elementExists('named', ['link', 'Type Three'])->keyPress(32); - $assert_session->assertWaitOnAjaxRequest(); - $this->assertNotEmpty($assert_session->waitForText('Showing Type Three media.')); + $this->waitForText('Showing Type Three media.'); $assert_session->elementExists('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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Dog'); $assert_session->pageTextContains('Bear'); $assert_session->pageTextNotContains('Turtle'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); $this->assertNotEmpty($assert_session->waitForText('Showing Type Three media.')); $assert_session->elementExists('named', ['link', 'Show Type Three media (selected)']); $assert_session->pageTextNotContains('Dog'); @@ -568,30 +543,25 @@ public function testWidget() { $assert_session->elementExists('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->openMediaLibraryForField('field_unlimited_media'); $session = $this->getSession(); $session->getPage()->fillField('Name', 'Dog'); $session->getPage()->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextContains('Dog'); - $assert_session->pageTextNotContains('Bear'); + $this->waitForText('Dog'); + $this->waitForNoText('Bear'); $session->getPage()->fillField('Name', ''); $session->getPage()->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextContains('Dog'); - $assert_session->pageTextContains('Bear'); + $this->waitForText('Dog'); + $this->waitForText('Bear'); $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); // 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->openMediaLibraryForField('field_twin_media'); $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 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 the weight field can be focused via a mouse click. @@ -602,38 +572,32 @@ public function testWidget() { $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(); // 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->openMediaLibraryForField('field_twin_media'); $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(); - $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_twin_media'); $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->assertCount(2, $page->findAll('css', '.field--name-field-twin-media .media-library-item')); + $this->waitForElementsCount('css', '.field--name-field-twin-media .media-library-item', 2); $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.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementExists('css', '.media-library-item__remove')->click(); + $this->assertElementExistsAfterWait('css', '.media-library-item__remove')->click(); $this->assertNotEmpty($assert_session->waitForText('Removed Dog.')); - $assert_session->assertWaitOnAjaxRequest(); + $assert_session->assertNoElementAfterWait('css', '.media-library-item__remove'); // 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->openMediaLibraryForField('field_twin_media'); // Assert the number of selected items is displayed correctly. $assert_session->elementExists('css', '.media-library-selected-count'); $assert_session->elementTextContains('css', '.media-library-selected-count', '0 of 2 items selected'); @@ -665,10 +629,8 @@ public function testWidget() { $this->assertFalse($checkboxes[3]->hasAttribute('disabled')); // The selection should be persisted when navigating to other media types in // the modal. - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); - $page->clickLink('Type One'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); + $this->switchToMediaType('One'); $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input'); $selected_checkboxes = []; foreach ($checkboxes as $checkbox) { @@ -680,8 +642,7 @@ public function testWidget() { $assert_session->hiddenFieldValueEquals('media-library-modal-selection', implode(',', $selected_checkboxes)); $assert_session->elementTextContains('css', '.media-library-selected-count', '1 of 2 items selected'); // Add to selection from another type. - $page->clickLink('Type Two'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Two'); $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input'); $this->assertCount(4, $checkboxes); $checkboxes[0]->click(); @@ -695,8 +656,7 @@ public function testWidget() { $this->assertTrue($checkboxes[2]->hasAttribute('disabled')); $this->assertTrue($checkboxes[3]->hasAttribute('disabled')); // Assert the checkboxes are also disabled on other pages. - $page->clickLink('Type One'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('One'); $this->assertTrue($checkboxes[0]->hasAttribute('disabled')); $this->assertFalse($checkboxes[1]->hasAttribute('disabled')); $this->assertTrue($checkboxes[2]->hasAttribute('disabled')); @@ -704,9 +664,8 @@ public function testWidget() { // 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(); // 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")'); @@ -722,7 +681,6 @@ public function testWidget() { $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(); // 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")'); $assert_session->elementTextNotContains('css', '#field_twin_media-media-library-wrapper', 'Cat'); @@ -734,15 +692,13 @@ public function testWidget() { $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .media-library-open-button").is(":not(:disabled)")'); // 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->openMediaLibraryForField('field_twin_media'); $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->waitForElementTextContains('#field_twin_media-media-library-wrapper', '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'); @@ -752,8 +708,7 @@ public function testWidget() { $this->assertJsCondition('jQuery("#field_twin_media-media-library-wrapper .media-library-open-button").is(":disabled")'); // 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->openMediaLibraryForField('field_unlimited_media'); $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input'); $this->assertGreaterThanOrEqual(4, count($checkboxes)); // Nothing is selected yet. @@ -773,8 +728,7 @@ public function testWidget() { $this->assertFalse($checkboxes[3]->isChecked()); // Close the dialog, reopen it and assert not is selected again. $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); $checkboxes = $page->findAll('css', '.media-library-view .js-click-to-select-checkbox input'); $this->assertGreaterThanOrEqual(4, count($checkboxes)); $this->assertFalse($checkboxes[0]->isChecked()); @@ -808,8 +762,7 @@ public function testWidget() { $assert_session->pageTextNotContains('Horse'); $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->openMediaLibraryForField('field_unlimited_media'); $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'; @@ -820,9 +773,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'); @@ -882,8 +834,7 @@ public function testWidgetViews() { // 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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->elementExists('css', '.media-library-view .media-library-item--grid'); $assert_session->elementNotExists('css', '.media-library-view .media-library-item--table'); $assert_session->linkExists('Grid'); @@ -898,12 +849,10 @@ public function testWidgetViews() { $assert_session->elementTextContains('css', '.media-library-view .pager__item.is-active', 'Page 1'); $assert_session->elementsCount('css', '.media-library-view .js-click-to-select-checkbox input', 24); $page->clickLink('Next page'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementTextContains('css', '.media-library-view .pager__item.is-active', 'Page 2'); + $this->waitForElementTextContains('.media-library-view .pager__item.is-active', 'Page 2'); $assert_session->elementsCount('css', '.media-library-view .js-click-to-select-checkbox input', 1); $page->clickLink('Previous page'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->elementTextContains('css', '.media-library-view .pager__item.is-active', 'Page 1'); + $this->waitForElementTextContains('.media-library-view .pager__item.is-active', 'Page 1'); $assert_session->elementsCount('css', '.media-library-view .js-click-to-select-checkbox input', 24); // Assert the display change is correctly announced for screen readers. @@ -923,9 +872,8 @@ public function testWidgetViews() { // Assert the exposed filters can be applied. $page->fillField('Name', 'Dog'); $page->pressButton('Apply filters'); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextContains('Dog'); - $assert_session->pageTextNotContains('Bear'); + $this->waitForText('Dog'); + $this->waitForNoText('Bear'); $assert_session->pageTextNotContains('Turtle'); $page->checkField('Select Dog'); $assert_session->linkExists('Table'); @@ -948,9 +896,8 @@ public function testWidgetViews() { // 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(); // Ensure that the selection completed successfully. - $assert_session->pageTextNotContains('Add or select media'); + $this->waitForNoText('Add or select media'); $assert_session->pageTextContains('Dog'); $assert_session->pageTextNotContains('Bear'); $assert_session->pageTextNotContains('Turtle'); @@ -977,18 +924,16 @@ public function testWidgetAnonymous() { $this->drupalGet('node/add/basic_page'); // Add to the unlimited cardinality field. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); // Select the first media item (should be Dog). $page->find('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(); // Ensure that the selection completed successfully. - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains('Dog'); + $this->waitForNoText('Add or select media'); + $this->waitForText('Dog'); // Save the form. $assert_session->elementExists('css', '.js-media-library-widget-toggle-weight')->click(); @@ -1002,6 +947,9 @@ public function testWidgetAnonymous() { /** * Tests that uploads in the Media library's widget works as expected. + * + * Note that this test will occasionally fail with SQLite until + * https://www.drupal.org/node/3066447 is addressed. */ public function testWidgetUpload() { $assert_session = $this->assertSession(); @@ -1035,8 +983,7 @@ 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(); + $this->openMediaLibraryForField('field_twin_media'); $assert_session->pageTextContains('Add or select media'); // Assert the upload form is not visible for default tab type_three without @@ -1045,13 +992,11 @@ public function testWidgetUpload() { // Assert the upload form is not visible for the non-file based media type // type_one. - $page->clickLink('Type One'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('One'); $assert_session->elementNotExists('css', '.media-library-add-form'); // Assert the upload form is visible for type_four. - $page->clickLink('Type Four'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Four'); $assert_session->fieldExists('Add files'); $assert_session->pageTextContains('Maximum 2 files.'); @@ -1073,8 +1018,7 @@ public function testWidgetUpload() { $file_system = $this->container->get('file_system'); // Add to the twin media field. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_twin_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_twin_media'); $assert_session->pageTextContains('Add or select media'); // Assert the upload form is now visible for default tab type_three. @@ -1084,8 +1028,7 @@ public function testWidgetUpload() { // Assert we can upload a file to the default tab type_three. $assert_session->elementExists('css', '.media-library-add-form--without-input'); $assert_session->elementNotExists('css', '.media-library-add-form--with-input'); - $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); - $assert_session->assertWaitOnAjaxRequest(); + $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); $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.'); $assert_session->elementAttributeContains('css', '.media-library-add-form__added-media', 'aria-label', 'Added media items'); @@ -1104,12 +1047,10 @@ public function testWidgetUpload() { $assert_session->fieldNotExists('Revision log message', $upload_form); // Assert the name field contains the filename and the alt text is required. $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->saveAnd('select'); + $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(); + $this->saveAnd('select'); $this->assertJsCondition('jQuery("input[name=\'media_library_select_form[0]\']").is(":focus")'); // The file should be permanent now. $files = $file_storage->loadMultiple(); @@ -1130,37 +1071,29 @@ public function testWidgetUpload() { // 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.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains($png_image->filename); + $this->waitForNoText('Add or select media'); + $this->waitForText($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(); + $this->openMediaLibraryForField('field_twin_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); $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(); - $page->fillField('Alternative text', $this->randomString()); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and insert'); + $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_2)); + $this->waitForFieldExists('Alternative text')->setValue($this->randomString()); + $this->saveAnd('insert'); $this->assertNotEmpty($assert_session->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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); // Select a media item to check if the selection is persisted when adding // new items. @@ -1171,13 +1104,13 @@ public function testWidgetUpload() { $assert_session->pageTextContains('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->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_3)); + $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()); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select'); - $assert_session->assertWaitOnAjaxRequest(); + $this->saveAnd('select'); + $this->waitForNoText('Save and select'); // Load the created media item. $media_items = Media::loadMultiple(); $added_media = array_pop($media_items); @@ -1205,81 +1138,74 @@ 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 2 media items.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains('Unlimited Cardinality Image'); + $this->waitForText('Added 2 media items.'); + $this->waitForNoText('Add or select media'); + $this->waitForText('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(); + $this->openMediaLibraryForField('field_twin_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Four'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Four'); $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->addMediaFileToField('Add file', $file_system->realpath($png_uri_4), FALSE); + $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)); - $assert_session->assertWaitOnAjaxRequest(); - $page->fillField('Alternative text', $this->randomString()); + $this->addMediaFileToField('Add file', $file_system->realpath($jpg_uri_2)); + $this->waitForFieldExists('Alternative text')->setValue($this->randomString()); // The type_four media type has another optional image field. $assert_session->pageTextContains('Extra Image'); $jpg_uri_3 = $file_system->copy($jpg_image->uri, 'public://'); - $page->attachFileToField('Extra Image', $this->container->get('file_system')->realpath($jpg_uri_3)); - $assert_session->assertWaitOnAjaxRequest(); + $this->addMediaFileToField('Extra Image', $this->container->get('file_system')->realpath($jpg_uri_3)); + $this->waitForText($file_system->basename($jpg_uri_3)); // Ensure that the extra image was uploaded to the correct directory. $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'); - $assert_session->assertWaitOnAjaxRequest(); + $this->saveAnd('select'); // Ensure the media item was saved to the library and automatically // selected. - $assert_session->pageTextContains('Add or select media'); - $assert_session->pageTextContains($file_system->basename($jpg_uri_2)); + $this->waitForText('Add or select media'); + $this->waitForText($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.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); + $this->waitForNoText('Add or select media'); $assert_session->pageTextContains($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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); $checkbox = $page->findField("Select $existing_media_name"); $selected_item_id = $checkbox->getAttribute('value'); $checkbox->click(); $assert_session->hiddenFieldValueEquals('current_selection', $selected_item_id); $this->assertTrue($assert_session->fieldExists('Add files')->hasAttribute('multiple')); $png_uri_5 = $file_system->copy($png_image->uri, 'public://'); - $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_5)); + $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_5)); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $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"); + $selection_area->uncheckField("Select $existing_media_name"); $page->fillField('Alternative text', $this->randomString()); $assert_session->hiddenFieldValueEquals('current_selection', ''); // Close the details element so that clicking the Save and select works. // @todo Fix dialog or test so this is not necessary to prevent random // fails. https://www.drupal.org/project/drupal/issues/3055648 $this->click('details.media-library-add-form__selected-media summary'); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select'); - $assert_session->assertWaitOnAjaxRequest(); + $this->saveAnd('select'); + $this->waitForText("Select $existing_media_name"); $media_items = Media::loadMultiple(); $added_media = array_pop($media_items); $added_media_name = $added_media->label(); @@ -1289,18 +1215,14 @@ public function testWidgetUpload() { $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.')); - $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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); - $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); + $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); // 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 @@ -1310,9 +1232,8 @@ public function testWidgetUpload() { // 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(); // 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")'); @@ -1321,11 +1242,9 @@ public function testWidgetUpload() { $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); // Assert uploading multiple files. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); // Assert the existing items are remembered when adding and removing media. $checkbox = $page->findField("Select $existing_media_name"); $checkbox->click(); @@ -1340,10 +1259,9 @@ public function testWidgetUpload() { $remote_paths[] = $driver->uploadFileAndGetRemoteFilePath($file_system->realpath($path)); } $page->findField('Add files')->setValue(implode("\n", $remote_paths)); - $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]); @@ -1438,30 +1356,29 @@ public function testWidgetOEmbed() { $this->drupalGet('node/add/basic_page'); // Add to the unlimited media field. - $assert_session->elementExists('css', '.media-library-open-button[name^="field_unlimited_media"]')->click(); - $assert_session->assertWaitOnAjaxRequest(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); // Assert the default tab for media type one does not have an oEmbed form. $assert_session->fieldNotExists('Add Type Five via URL'); // Assert other media types don't have the oEmbed form fields. - $page->clickLink('Type Three'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Three'); $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->switchToMediaType('Five'); $page->fillField('Add Type Five via URL', $youtube_url); $assert_session->pageTextContains('Allowed providers: YouTube, Vimeo.'); $page->pressButton('Add'); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $assert_session->assertWaitOnAjaxRequest(); + $this->waitForText('The media item has been created but has not yet been saved.'); // Assert the name field contains the remote video title. $assert_session->fieldValueEquals('Name', $youtube_title); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select'); - $assert_session->assertWaitOnAjaxRequest(); - + $this->saveAnd('select'); + $this->waitForText('Add Type Five via URL'); // Load the created media item. $media_items = Media::loadMultiple(); $added_media = array_pop($media_items); @@ -1477,33 +1394,33 @@ public function testWidgetOEmbed() { // 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.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains($youtube_title); + $this->waitForNoText('Add or select media'); + $this->waitForText($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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Five'); - $assert_session->assertWaitOnAjaxRequest(); - + $this->switchToMediaType('Five'); // Assert the video is available on the tab. $assert_session->pageTextContains($youtube_title); // Assert we can only add supported URLs. $page->fillField('Add Type Five via URL', 'https://www.youtube.com/'); $page->pressButton('Add'); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $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'); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $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. @@ -1516,12 +1433,15 @@ public function testWidgetOEmbed() { // Assert we can add a oEmbed video with a custom name. $page->fillField('Add Type Five via URL', $youtube_url); $page->pressButton('Add'); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $assert_session->assertWaitOnAjaxRequest(); + $this->waitForText('The media item has been created but has not yet been saved.'); $page->fillField('Name', 'Custom video title'); $selection_area = $assert_session->elementExists('css', '.media-library-add-form__selected-media'); $assert_session->checkboxChecked("Select $youtube_title", $selection_area); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select'); - $assert_session->assertWaitOnAjaxRequest(); + $this->saveAnd('select'); + $this->waitForNoText('Save and select'); // Load the created media item. $media_items = Media::loadMultiple(); @@ -1549,42 +1469,39 @@ 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'); - $assert_session->pageTextContains('Custom video title'); + $this->waitForText('Added 2 media items.'); + $this->waitForNoText('Add or select media'); + $this->waitForText('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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Five'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Five'); $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->waitForText('The media item has been created but has not yet been saved.'); + $this->saveAnd('insert'); $this->assertNotEmpty($assert_session->waitForText('Added one media item.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains($vimeo_title); + $this->waitForNoText('Add or select media'); + $this->waitForText($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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Five'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Five'); $checkbox = $page->findField("Select $vimeo_title"); $selected_item_id = $checkbox->getAttribute('value'); $checkbox->click(); $assert_session->hiddenFieldValueEquals('current_selection', $selected_item_id); $page->fillField('Add Type Five via URL', $youtube_url); $page->pressButton('Add'); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. $assert_session->assertWaitOnAjaxRequest(); + $this->waitForText('The media item has been created but has not yet been saved'); $page->fillField('Name', 'Another video'); - $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 $vimeo_title", $selection_area); $page->uncheckField("Select $vimeo_title"); @@ -1593,29 +1510,24 @@ public function testWidgetOEmbed() { // @todo Fix dialog or test so this is not necessary to prevent random // fails. https://www.drupal.org/project/drupal/issues/3055648 $this->click('details.media-library-add-form__selected-media summary'); - $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save and select'); - $assert_session->assertWaitOnAjaxRequest(); + $this->saveAnd('select'); $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.')); - $assert_session->assertWaitOnAjaxRequest(); - $assert_session->pageTextNotContains('Add or select media'); - $assert_session->pageTextContains('Another video'); + $this->waitForNoText('Add or select media'); + $this->waitForText('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(); + $this->openMediaLibraryForField('field_unlimited_media'); $assert_session->pageTextContains('Add or select media'); - $page->clickLink('Type Five'); - $assert_session->assertWaitOnAjaxRequest(); + $this->switchToMediaType('Five'); $page->fillField('Add Type Five via URL', $youtube_url); $page->pressButton('Add'); - $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 @@ -1625,9 +1537,8 @@ public function testWidgetOEmbed() { // 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(); // 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")'); @@ -1658,13 +1569,201 @@ public function testFieldUiIntegration() { $page->pressButton('Save field settings'); $assert_session->pageTextNotContains('Undefined index: target_bundles'); $page->checkField('settings[handler_settings][target_bundles][type_one]'); - $assert_session->assertWaitOnAjaxRequest(); + $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_one]"][checked="checked"]'); $page->checkField('settings[handler_settings][target_bundles][type_two]'); - $assert_session->assertWaitOnAjaxRequest(); + $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_two]"][checked="checked"]'); $page->checkField('settings[handler_settings][target_bundles][type_three]'); - $assert_session->assertWaitOnAjaxRequest(); + $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_three]"][checked="checked"]'); $page->pressButton('Save settings'); $assert_session->pageTextContains('Saved Shatner configuration.'); } + /** + * Asserts that text does not appear on page after a wait. + * + * @param string $text + * The text that should not be on the page. + * @param int $timeout + * Timeout in milliseconds, defaults to 10000. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function waitForNoText($text, $timeout = 10000) { + $page = $this->getSession()->getPage(); + $result = $page->waitFor($timeout / 1000, function ($page) use ($text) { + $actual = preg_replace('/\s+/u', ' ', $page->getText()); + $regex = '/' . preg_quote($text, '/') . '/ui'; + return (bool) !preg_match($regex, $actual); + }); + $this->assertNotEmpty($result, "\"$text\" was found but shouldn't be there."); + } + + /** + * Asserts that text appears on page after a wait. + * + * @param string $text + * The text that should appear on the page. + * @param int $timeout + * Timeout in milliseconds, defaults to 10000. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function waitForText($text, $timeout = 10000) { + $result = $this->assertSession()->waitForText($text, $timeout); + $this->assertNotEmpty($result, "\"$text\" not found"); + } + + /** + * Asserts that text appears in an element after a wait. + * + * @param string $selector + * The CSS selector of the element to check. + * @param string $text + * The text that should appear in the element. + * @param int $timeout + * Timeout in milliseconds, defaults to 10000. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function waitForElementTextContains($selector, $text, $timeout = 10000) { + $element = $this->assertSession()->waitForElement('css', "$selector:contains('$text')", $timeout); + $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 + * Timeout in milliseconds, defaults to 10000. + * + * @return \Behat\Mink\Element\NodeElement + * The page element node if found. If not found, the test fails. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function assertElementExistsAfterWait($selector, $locator, $timeout = 10000) { + $element = $this->assertSession()->waitForElement($selector, $locator, $timeout); + $this->assertNotEmpty($element); + return $element; + } + + /** + * Clicks a media type tab and waits for it to appear. + */ + protected function switchToMediaType($type) { + $page = $this->getSession()->getPage(); + $lowercase_type = strtolower($type); + + if (!is_null($page->find('css', ".media-library-menu-type-$lowercase_type .active-tab"))) { + // There is nothing to do as the type is already active. + return; + } + + $page->clickLink($type); + $this->assertElementExistsAfterWait('css', ".media-library-menu-type-$lowercase_type .active-tab"); + $this->assertElementExistsAfterWait('css', "[data-drupal-media-type='type_$lowercase_type']"); + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. + $this->assertSession()->assertWaitOnAjaxRequest(); + } + + /** + * Checks for a specified number of specific elements on page after wait. + * + * @param string $selector_type + * Element selector type (css, xpath) + * @param string|array $selector + * Element selector. + * @param int $count + * Expected count. + * @param int $timeout + * Timeout in milliseconds, defaults to 10000. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function waitForElementsCount($selector_type, $selector, $count, $timeout = 10000) { + $page = $this->getSession()->getPage(); + + $start = microtime(TRUE); + $end = $start + ($timeout / 1000); + do { + $nodes = $page->findAll($selector_type, $selector); + if (count($nodes) === $count) { + return; + } + usleep(100000); + } while (microtime(TRUE) < $end); + + $this->assertSession()->elementsCount($selector_type, $selector, $count); + } + + /** + * Checks for the existence of a field on page after wait. + * + * @param string $field + * The field to find. + * @param int $timeout + * Timeout in milliseconds, defaults to 10000. + * + * @return \Behat\Mink\Element\NodeElement|null + * The element if found, otherwise null. + * + * @todo replace with whatever gets added in + * https://www.drupal.org/node/3061852 + */ + protected function waitForFieldExists($field, $timeout = 10000) { + $assert_session = $this->assertSession(); + $assert_session->waitForField($field, $timeout); + return $assert_session->fieldExists($field); + } + + /** + * Waits for a file field to exist before uploading. + */ + public function addMediaFileToField($locator, $path) { + $page = $this->getSession()->getPage(); + $this->waitForFieldExists($locator); + $page->attachFileToField($locator, $path); + } + + /** + * Clicks "Save and select||insert" button and waits for AJAX completion. + * + * @param string $operation + * The final word of the button to be clicked. + */ + protected function saveAnd($operation) { + $this->assertElementExistsAfterWait('css', '.ui-dialog-buttonpane')->pressButton("Save and $operation"); + + // assertWaitOnAjaxRequest() required for input "id" attributes to + // consistently match their label's "for" attribute. + $this->assertSession()->assertWaitOnAjaxRequest(); + } + + /** + * Clicks a button that opens a media widget and confirms it is open. + * + * @param string $button_name + * The beginning of the name attribute of the button. + * @param string $after_open_selector + * The selector to look for after the button is clicked. + * + * @return \Behat\Mink\Element\NodeElement + * The NodeElement found via $after_open_selector. + */ + protected function openMediaLibraryForField($button_name, $after_open_selector = '.media-library-menu') { + $this->assertElementExistsAfterWait('css', ".media-library-open-button[name^=\"$button_name\"]")->click(); + return $this->assertElementExistsAfterWait('css', $after_open_selector); + } + }