Verified Commit 04fa987a authored by godotislate's avatar godotislate
Browse files

fix: #3595497 Collapsed Details Element causes JS Error for required textarea and select fields

By: alexpott
By: amitgoyal
By: godotislate
By: longwave
By: smustgrave
parent f1e54b02
Loading
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -27561,12 +27561,6 @@
	'count' => 1,
	'path' => __DIR__ . '/modules/system/tests/modules/form_test/src/Form/FormTestDescriptionForm.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\form_test\\\\Form\\\\FormTestDetailsContainsRequiredTextfieldForm\\:\\:submitForm\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/modules/system/tests/modules/form_test/src/Form/FormTestDetailsContainsRequiredTextfieldForm.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\form_test\\\\Form\\\\FormTestDetailsForm\\:\\:submitForm\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
+3 −1
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@
  window.addEventListener(
    'invalid',
    (event) => {
      if (event.target.matches('details input[required]')) {
      if (
        event.target.matches('details :is(input, textarea, select)[required]')
      ) {
        handleFragmentLinkClickOrHashChange(event, $(event.target));
      }
    },
+4 −4
Original line number Diff line number Diff line
@@ -450,11 +450,11 @@ form_test.details_form:
  requirements:
    _access: 'TRUE'

form_test.details_contains_required_textfield:
  path: '/form_test/details-contains-required-textfield/{use_ajax}'
form_test.details_contains_required_fields:
  path: '/form_test/details-contains-required-fields/{use_ajax}'
  defaults:
    _form: '\Drupal\form_test\Form\FormTestDetailsContainsRequiredTextfieldForm'
    _title: 'Form details contains required textfield test'
    _form: '\Drupal\form_test\Form\FormTestDetailsContainsRequiredFieldsForm'
    _title: 'Form details contains required fields test'
    use_ajax: FALSE
  requirements:
    _access: 'TRUE'
+24 −3
Original line number Diff line number Diff line
@@ -8,11 +8,11 @@
use Drupal\Core\Form\FormStateInterface;

/**
 * Builds a form to test a required textfield within a details element.
 * Builds a form to test required fields within details elements.
 *
 * @internal
 */
class FormTestDetailsContainsRequiredTextfieldForm extends FormBase {
class FormTestDetailsContainsRequiredFieldsForm extends FormBase {

  /**
   * {@inheritdoc}
@@ -36,6 +36,27 @@ public function buildForm(array $form, FormStateInterface $form_state, $use_ajax
      '#required' => TRUE,
      '#title' => 'Required textfield',
    ];
    $form['meta2'] = [
      '#type' => 'details',
      '#title' => 'Details element 2',
      '#open' => FALSE,
    ];
    $form['meta2']['required_textarea_in_details'] = [
      '#type' => 'textarea',
      '#required' => TRUE,
      '#title' => 'Required textarea',
    ];
    $form['meta3'] = [
      '#type' => 'details',
      '#title' => 'Details element 3',
      '#open' => FALSE,
    ];
    $form['meta3']['required_select_in_details'] = [
      '#type' => 'select',
      '#options' => ['one', 'two', 'three', 'four', 'five'],
      '#required' => TRUE,
      '#title' => 'Required select',
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => 'Submit',
@@ -57,7 +78,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $use_ajax
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
  public function submitForm(array &$form, FormStateInterface $form_state): array {
    return $form;
  }

+35 −8
Original line number Diff line number Diff line
@@ -171,49 +171,76 @@ public function testVerticalTabValidationVisibility(): void {
   * Tests form submit with a required field in closed details element.
   */
  public function testDetailsContainsRequiredTextfield(): void {
    $this->drupalGet('form_test/details-contains-required-textfield');
    $this->drupalGet('form_test/details-contains-required-fields');
    $details = $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta"]');
    $details2 = $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta2"]');
    $details3 = $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta3"]');

    // Make sure details element is not open at the beginning.
    $this->assertFalse($details->hasAttribute('open'));
    $this->assertFalse($details2->hasAttribute('open'));
    $this->assertFalse($details3->hasAttribute('open'));

    $textfield = $this->assertSession()->elementExists('css', 'input[name="required_textfield_in_details"]');
    $textarea = $this->assertSession()->elementExists('css', 'textarea[name="required_textarea_in_details"]');
    $select = $this->assertSession()->elementExists('css', 'select[name="required_select_in_details"]');

    // The text field inside the details element is not visible too.
    // The fields inside the details elements are not visible too.
    $this->assertFalse($textfield->isVisible(), 'Text field is not visible');
    $this->assertFalse($textarea->isVisible(), 'Text area field is not visible');
    $this->assertFalse($select->isVisible(), 'Select field is not visible');

    // Submit the form with invalid data in the required fields.
    $this->assertSession()
      ->elementExists('css', 'input[data-drupal-selector="edit-submit"]')
      ->click();
    // Confirm the required field is visible.
    // Confirm the required fields are visible.
    $this->assertTrue($textfield->isVisible(), 'Text field is visible');
    $this->assertTrue($textarea->isVisible(), 'Text area field is visible');
    $this->assertTrue($select->isVisible(), 'Select field is visible');
  }

  /**
   * Tests required field in closed details element with ajax form.
   */
  public function testDetailsContainsRequiredTextfieldAjaxForm(): void {
    $this->drupalGet('form_test/details-contains-required-textfield/true');
    $this->drupalGet('form_test/details-contains-required-fields/true');
    $assert_session = $this->assertSession();
    $textfield = $assert_session->elementExists('css', 'input[name="required_textfield_in_details"]');
    $textarea = $this->assertSession()->elementExists('css', 'textarea[name="required_textarea_in_details"]');
    $select = $this->assertSession()->elementExists('css', 'select[name="required_select_in_details"]');

    // Submit the ajax form to open the details element at the first time.
    $assert_session->elementExists('css', 'input[value="Submit Ajax"]')
      ->click();

    $assert_session->waitForElementVisible('css', 'input[name="required_textfield_in_details"]');
    $assert_session->waitForElementVisible('css', 'textarea[name="required_textarea_in_details"]');
    $assert_session->waitForElementVisible('css', 'select[name="required_select_in_details"]');

    // Close the details element.
    $assert_session->elementExists('css', 'form summary')
      ->click();
    // Confirm the required fields are visible.
    $this->assertTrue($textfield->isVisible(), 'Text field is visible');
    $this->assertTrue($textarea->isVisible(), 'Text area field is visible');
    $this->assertTrue($select->isVisible(), 'Select field is visible');

    // Close the details elements.
    $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta"] summary')->click();
    $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta2"] summary')->click();
    $this->assertSession()->elementExists('css', 'details[data-drupal-selector="edit-meta3"] summary')->click();

    // The fields inside the details elements are not visible too.
    $this->assertFalse($textfield->isVisible(), 'Text field is not visible');
    $this->assertFalse($textarea->isVisible(), 'Text area field is not visible');
    $this->assertFalse($select->isVisible(), 'Select field is not visible');

    // Submit the form with invalid data in the required fields without ajax.
    $assert_session->elementExists('css', 'input[data-drupal-selector="edit-submit"]')
      ->click();

    // Confirm the required field is visible.
    // Confirm the required fields are visible.
    $this->assertTrue($textfield->isVisible(), 'Text field is visible');
    $this->assertTrue($textarea->isVisible(), 'Text area field is visible');
    $this->assertTrue($select->isVisible(), 'Select field is visible');
  }

}