From 9faff8cae868ffadeac8d0d2aca3e5a349993bab Mon Sep 17 00:00:00 2001
From: xjm <xjm@65776.no-reply.drupal.org>
Date: Mon, 16 Jan 2023 16:01:11 -0600
Subject: [PATCH] Issue #3307509 by J-Lee, smustgrave, Abhijith S, alexpott,
 xjm: No empty option for views bulk form

---
 .../FunctionalJavascript/MediaOverviewTest.php   |  4 ++++
 .../tests/src/Functional/Views/BulkFormTest.php  |  2 +-
 .../views/src/Plugin/views/field/BulkForm.php    | 16 ++++++++++++++++
 .../views/tests/src/Functional/BulkFormTest.php  | 12 +++++++++++-
 .../src/Functional/Plugin/ViewsBulkTest.php      |  8 ++++++++
 5 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaOverviewTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaOverviewTest.php
index 88e6cecb18c5..c7bdb44d3a4d 100644
--- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaOverviewTest.php
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaOverviewTest.php
@@ -108,6 +108,10 @@ public function testAdministrationPage() {
     $assert_session->elementExists('css', '#views-exposed-form-media-library-page')->submit();
     $this->waitForText('Dog');
 
+    // Select the "Delete media" action.
+    $page->selectFieldOption('Action', 'Delete media');
+    $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');
diff --git a/core/modules/node/tests/src/Functional/Views/BulkFormTest.php b/core/modules/node/tests/src/Functional/Views/BulkFormTest.php
index c4eada729ac7..bcd15ccc3739 100644
--- a/core/modules/node/tests/src/Functional/Views/BulkFormTest.php
+++ b/core/modules/node/tests/src/Functional/Views/BulkFormTest.php
@@ -94,7 +94,7 @@ protected function setUp($import_test_views = TRUE, $modules = ['node_test_views
     ]));
     $this->drupalGet('test-node-bulk-form');
     $elements = $this->assertSession()->selectExists('edit-action')->findAll('css', 'option');
-    $this->assertCount(8, $elements, 'All node operations are found.');
+    $this->assertCount(9, $elements, 'All node operations are found.');
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/field/BulkForm.php b/core/modules/views/src/Plugin/views/field/BulkForm.php
index 5340aac5e455..2edd80159846 100644
--- a/core/modules/views/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/views/src/Plugin/views/field/BulkForm.php
@@ -319,6 +319,7 @@ public function viewsForm(&$form, FormStateInterface $form_state) {
         '#type' => 'select',
         '#title' => $this->options['action_title'],
         '#options' => $this->getBulkOptions(),
+        '#empty_option' => $this->t('- Select -'),
       ];
 
       // Duplicate the form actions into the action container in the header.
@@ -441,6 +442,16 @@ protected function emptySelectedMessage() {
     return $this->t('No items selected.');
   }
 
+  /**
+   * Returns the message that is displayed when no action is selected.
+   *
+   * @return string
+   *   Message displayed when no action is selected.
+   */
+  protected function emptyActionMessage() {
+    return $this->t('No %title option selected.', ['%title' => $this->options['action_title']]);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -449,6 +460,11 @@ public function viewsFormValidate(&$form, FormStateInterface $form_state) {
     if (empty($ids) || empty(array_filter($ids))) {
       $form_state->setErrorByName('', $this->emptySelectedMessage());
     }
+
+    $action = $form_state->getValue('action');
+    if (empty($action)) {
+      $form_state->setErrorByName('', $this->emptyActionMessage());
+    }
   }
 
   /**
diff --git a/core/modules/views/tests/src/Functional/BulkFormTest.php b/core/modules/views/tests/src/Functional/BulkFormTest.php
index 4e515c6aa602..0f4c53d7bee4 100644
--- a/core/modules/views/tests/src/Functional/BulkFormTest.php
+++ b/core/modules/views/tests/src/Functional/BulkFormTest.php
@@ -116,7 +116,7 @@ public function testBulkForm() {
 
     $this->drupalGet('test_bulk_form');
     $options = $this->assertSession()->selectExists('edit-action')->findAll('css', 'option');
-    $this->assertCount(2, $options);
+    $this->assertCount(3, $options);
     $this->assertSession()->optionExists('edit-action', 'node_make_sticky_action');
     $this->assertSession()->optionExists('edit-action', 'node_make_unsticky_action');
 
@@ -134,6 +134,11 @@ public function testBulkForm() {
     $this->drupalGet('test_bulk_form');
     $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-action"]', 'Action');
 
+    // There should be an error message if no action is selected.
+    $edit = ['node_bulk_form[0]' => TRUE, 'action' => ''];
+    $this->submitForm($edit, 'Apply to selected items');
+    $this->assertSession()->pageTextContains('No Action option selected.');
+
     // Setup up a different bulk form title.
     $view = Views::getView('test_bulk_form');
     $display = &$view->storage->getDisplay('default');
@@ -143,6 +148,11 @@ public function testBulkForm() {
     $this->drupalGet('test_bulk_form');
     $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-action"]', 'Test title');
 
+    // The error message when no action is selected should reflect the new form
+    // title.
+    $this->submitForm($edit, 'Apply to selected items');
+    $this->assertSession()->pageTextContains('No Test title option selected.');
+
     $this->drupalGet('test_bulk_form');
     // Call the node delete action.
     $edit = [];
diff --git a/core/modules/views/tests/src/Functional/Plugin/ViewsBulkTest.php b/core/modules/views/tests/src/Functional/Plugin/ViewsBulkTest.php
index c0be12e33dbe..c37b5f409099 100644
--- a/core/modules/views/tests/src/Functional/Plugin/ViewsBulkTest.php
+++ b/core/modules/views/tests/src/Functional/Plugin/ViewsBulkTest.php
@@ -64,6 +64,11 @@ public function testBulkSelection() {
       'changed' => \Drupal::time()->getRequestTime() - 120,
     ]);
 
+    // Select the node deletion action.
+    $action_select = $this->getSession()->getPage()->findField('edit-action');
+    $action_select_name = $action_select->getAttribute('name');
+    $this->getSession()->getPage()->selectFieldOption($action_select_name, 'node_delete_action');
+
     // Now click 'Apply to selected items' and assert the first node is selected
     // on the confirm form.
     $this->submitForm(['node_bulk_form[0]' => TRUE], 'Apply to selected items');
@@ -82,6 +87,9 @@ public function testBulkSelection() {
       'title' => 'The third node',
     ]);
 
+    // Select the node deletion action.
+    $this->getSession()->getPage()->selectFieldOption($action_select_name, 'node_delete_action');
+
     // Now click 'Apply to selected items' and assert the second node is
     // selected on the confirm form.
     $this->submitForm(['node_bulk_form[1]' => TRUE], 'Apply to selected items');
-- 
GitLab