Loading core/lib/Drupal/Core/Form/FormHelper.php +3 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,9 @@ protected static function processStatesArray(array &$conditions, $search, $repla * * @param array $elements * A render array element having a #states property as described above. * * @see \Drupal\form_test\Form\JavascriptStatesForm * @see \Drupal\FunctionalJavascriptTests\Core\Form\JavascriptStatesTest */ public static function processStates(array &$elements) { $elements['#attached']['library'][] = 'core/drupal.states'; Loading core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php +296 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,302 @@ public function getFormId() { * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form['checkbox_trigger'] = [ '#type' => 'checkbox', '#title' => 'Checkbox trigger', ]; $form['textfield_trigger'] = [ '#type' => 'textfield', '#title' => 'Textfield trigger', ]; $form['radios_trigger'] = [ '#type' => 'radios', '#title' => 'Radios trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], ]; $form['checkboxes_trigger'] = [ '#type' => 'checkboxes', '#title' => 'Checkboxes trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], ]; $form['select_trigger'] = [ '#type' => 'select', '#title' => 'Select trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], '#empty_value' => '_none', '#empty_option' => '- None -', ]; // Tested fields. // Checkbox trigger. $form['textfield_invisible_when_checkbox_trigger_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield invisible when checkbox trigger checked', '#states' => [ 'invisible' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['textfield_required_when_checkbox_trigger_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield required when checkbox trigger checked', '#states' => [ 'required' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['details_expanded_when_checkbox_trigger_checked'] = [ '#type' => 'details', '#title' => 'Details expanded when checkbox trigger checked', '#states' => [ 'expanded' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['details_expanded_when_checkbox_trigger_checked']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; $form['checkbox_checked_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when checkbox trigger checked', '#states' => [ 'checked' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['checkbox_unchecked_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when checkbox trigger checked', '#states' => [ 'unchecked' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['checkbox_visible_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox visible when checkbox trigger checked', '#states' => [ 'visible' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; // Checkboxes trigger. $form['textfield_visible_when_checkboxes_trigger_value2_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when checkboxes trigger value2 checked', '#states' => [ 'visible' => [ ':input[name="checkboxes_trigger[value2]"]' => ['checked' => TRUE], ], ], ]; $form['textfield_visible_when_checkboxes_trigger_value3_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when checkboxes trigger value3 checked', '#states' => [ 'visible' => [ ':input[name="checkboxes_trigger[value3]"]' => ['checked' => TRUE], ], ], ]; // Radios trigger. $form['fieldset_visible_when_radios_trigger_has_value2'] = [ '#type' => 'fieldset', '#title' => 'Fieldset visible when radio trigger has value2', '#states' => [ 'visible' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['fieldset_visible_when_radios_trigger_has_value2']['textfield_in_fieldset'] = [ '#type' => 'textfield', '#title' => 'Textfield in fieldset', ]; $form['textfield_invisible_when_radios_trigger_has_value2'] = [ '#type' => 'textfield', '#title' => 'Textfield invisible when radio trigger has value2', '#states' => [ 'invisible' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['select_required_when_radios_trigger_has_value2'] = [ '#type' => 'select', '#title' => 'Select required when radio trigger has value2', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], '#states' => [ 'required' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['checkbox_checked_when_radios_trigger_has_value3'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when radios trigger has value3', '#states' => [ 'checked' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['checkbox_unchecked_when_radios_trigger_has_value3'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when radios trigger has value3', '#states' => [ 'unchecked' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['details_expanded_when_radios_trigger_has_value3'] = [ '#type' => 'details', '#title' => 'Details expanded when radio trigger has value3', '#states' => [ 'expanded' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['details_expanded_when_radios_trigger_has_value3']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; // Select trigger $form['item_visible_when_select_trigger_has_value2'] = [ '#type' => 'item', '#title' => 'Item visible when select trigger has value2', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value2'], ], ], ]; $form['textfield_visible_when_select_trigger_has_value3'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when select trigger has value3', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value3'], ], ], ]; $form['textfield_visible_when_select_trigger_has_value2_or_value3'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when select trigger has value2 or value3', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => [ ['value' => 'value2'], ['value' => 'value3'], ], ], ], ]; // Textfield trigger. $form['checkbox_checked_when_textfield_trigger_filled'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when textfield trigger filled', '#default_value' => '0', '#states' => [ 'checked' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['checkbox_unchecked_when_textfield_trigger_filled'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when textfield trigger filled', '#default_value' => '1', '#states' => [ 'unchecked' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select_invisible_when_textfield_trigger_filled'] = [ '#type' => 'select', '#title' => 'Select invisible when textfield trigger filled', '#options' => [0 => 0, 1 => 1, 2 => 2], '#states' => [ 'invisible' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select_visible_when_textfield_trigger_filled'] = [ '#type' => 'select', '#title' => 'Select visible when textfield trigger filled', '#options' => [0 => 0, 1 => 1, 2 => 2], '#states' => [ 'visible' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['textfield_required_when_textfield_trigger_filled'] = [ '#type' => 'textfield', '#title' => 'Textfield required when textfield trigger filled', '#states' => [ 'required' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['details_expanded_when_textfield_trigger_filled'] = [ '#type' => 'details', '#title' => 'Details expanded when textfield trigger filled', '#states' => [ 'expanded' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['details_expanded_when_textfield_trigger_filled']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; // Multiple triggers. $form['item_visible_when_select_trigger_has_value2_and_textfield_trigger_filled'] = [ '#type' => 'item', '#title' => 'Item visible when select trigger has value2 and textfield trigger filled', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value2'], ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select'] = [ '#type' => 'select', '#title' => 'select 1', Loading core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php 0 → 100644 +289 −0 Original line number Diff line number Diff line <?php namespace Drupal\FunctionalJavascriptTests\Core\Form; use Drupal\FunctionalJavascriptTests\WebDriverTestBase; /** * Tests the state of elements based on another elements. * * @group javascript */ class JavascriptStatesTest extends WebDriverTestBase { /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ protected static $modules = ['form_test']; /** * Tests the JavaScript #states functionality of form elements. * * To avoid the large cost of a dataProvider in FunctionalJavascript tests, * this is a single public test method that invokes a series of protected * methods to do assertions on specific kinds of triggering elements. */ public function testJavascriptStates() { $this->doCheckboxTriggerTests(); $this->doCheckboxesTriggerTests(); $this->doTextfieldTriggerTests(); $this->doRadiosTriggerTests(); $this->doSelectTriggerTests(); $this->doMultipleTriggerTests(); } /** * Tests states of elements triggered by a checkbox element. */ protected function doCheckboxTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('checkbox_trigger'); $this->assertNotEmpty($trigger); $textfield_invisible_element = $page->findField('textfield_invisible_when_checkbox_trigger_checked'); $this->assertNotEmpty($textfield_invisible_element); $textfield_required_element = $page->findField('textfield_required_when_checkbox_trigger_checked'); $this->assertNotEmpty($textfield_required_element); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-checkbox-trigger-checked'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); $checkbox_checked_element = $page->findField('checkbox_checked_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_checked_element); $checkbox_unchecked_element = $page->findField('checkbox_unchecked_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_unchecked_element); $checkbox_visible_element = $page->findField('checkbox_visible_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_visible_element); // Verify initial state. $this->assertTrue($textfield_invisible_element->isVisible()); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); $this->assertFalse($textfield_required_element->hasAttribute('required')); $this->assertFalse($checkbox_checked_element->isChecked()); $this->assertTrue($checkbox_unchecked_element->isChecked()); $this->assertFalse($checkbox_visible_element->isVisible()); // Change state: check the checkbox. $trigger->check(); // Verify triggered state. $this->assertFalse($textfield_invisible_element->isVisible()); $this->assertEquals('required', $textfield_required_element->getAttribute('required')); $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); $this->assertTrue($checkbox_checked_element->isChecked()); $this->assertFalse($checkbox_unchecked_element->isChecked()); $this->assertTrue($checkbox_visible_element->isVisible()); } /** * Tests states of elements triggered by a checkboxes element. */ protected function doCheckboxesTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger_value1 = $page->findField('checkboxes_trigger[value1]'); $this->assertNotEmpty($trigger_value1); $trigger_value2 = $page->findField('checkboxes_trigger[value2]'); $this->assertNotEmpty($trigger_value2); $trigger_value3 = $page->findField('checkboxes_trigger[value3]'); $this->assertNotEmpty($trigger_value3); $textfield_visible_value2 = $page->findField('textfield_visible_when_checkboxes_trigger_value2_checked'); $this->assertNotEmpty($textfield_visible_value2); $textfield_visible_value3 = $page->findField('textfield_visible_when_checkboxes_trigger_value3_checked'); $this->assertNotEmpty($textfield_visible_value3); // Verify initial state. $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 1' checkbox. $trigger_value1->check(); $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 2' checkbox. $trigger_value2->check(); $this->assertTrue($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 3' checkbox. $trigger_value3->check(); $this->assertTrue($textfield_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); // Change state: uncheck the 'Value 2' checkbox. $trigger_value2->uncheck(); $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); } /** * Tests states of elements triggered by a textfield element. */ protected function doTextfieldTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('textfield_trigger'); $this->assertNotEmpty($trigger); $checkbox_checked_target = $page->findField('checkbox_checked_when_textfield_trigger_filled'); $this->assertNotEmpty($checkbox_checked_target); $checkbox_unchecked_target = $page->findField('checkbox_unchecked_when_textfield_trigger_filled'); $this->assertNotEmpty($checkbox_unchecked_target); $select_invisible_target = $page->findField('select_invisible_when_textfield_trigger_filled'); $this->assertNotEmpty($select_invisible_target); $select_visible_target = $page->findField('select_visible_when_textfield_trigger_filled'); $this->assertNotEmpty($select_visible_target); $textfield_required_target = $page->findField('textfield_required_when_textfield_trigger_filled'); $this->assertNotEmpty($textfield_required_target); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-textfield-trigger-filled'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); // Verify initial state. $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertTrue($select_invisible_target->isVisible()); $this->assertFalse($select_visible_target->isVisible()); $this->assertFalse($textfield_required_target->hasAttribute('required')); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: fill the textfield. $trigger->setValue('filled'); // Verify triggered state. $this->assertTrue($checkbox_checked_target->isChecked()); $this->assertFalse($checkbox_unchecked_target->isChecked()); $this->assertFalse($select_invisible_target->isVisible()); $this->assertTrue($select_visible_target->isVisible()); $this->assertEquals('required', $textfield_required_target->getAttribute('required')); $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); } /** * Tests states of elements triggered by a radios element. */ protected function doRadiosTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('radios_trigger'); $this->assertNotEmpty($trigger); $fieldset_visible_when_value2 = $this->assertSession()->elementExists('css', '#edit-fieldset-visible-when-radios-trigger-has-value2'); $textfield_in_fieldset = $fieldset_visible_when_value2->findField('textfield_in_fieldset'); $this->assertNotEmpty($textfield_in_fieldset); $checkbox_checked_target = $page->findField('checkbox_checked_when_radios_trigger_has_value3'); $this->assertNotEmpty($checkbox_checked_target); $checkbox_unchecked_target = $page->findField('checkbox_unchecked_when_radios_trigger_has_value3'); $this->assertNotEmpty($checkbox_unchecked_target); $textfield_invisible_target = $page->findField('textfield_invisible_when_radios_trigger_has_value2'); $this->assertNotEmpty($textfield_invisible_target); $select_required_target = $page->findField('select_required_when_radios_trigger_has_value2'); $this->assertNotEmpty($select_required_target); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-radios-trigger-has-value3'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); // Verify initial state, both the fieldset and something inside it. $this->assertFalse($fieldset_visible_when_value2->isVisible()); $this->assertFalse($textfield_in_fieldset->isVisible()); $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertTrue($textfield_invisible_target->isVisible()); $this->assertFalse($select_required_target->hasAttribute('required')); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: select the value2 radios option. $trigger->selectOption('value2'); // Verify triggered state. $this->assertTrue($fieldset_visible_when_value2->isVisible()); $this->assertTrue($textfield_in_fieldset->isVisible()); $this->assertFalse($textfield_invisible_target->isVisible()); $this->assertTrue($select_required_target->hasAttribute('required')); // Checkboxes and details should not have changed state, yet. $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: select the value3 radios option. $trigger->selectOption('value3'); // Fieldset and contents should re-disappear. $this->assertFalse($fieldset_visible_when_value2->isVisible()); $this->assertFalse($textfield_in_fieldset->isVisible()); // Textfield and select should revert to initial state. $this->assertTrue($textfield_invisible_target->isVisible()); $this->assertFalse($select_required_target->hasAttribute('required')); // Checkbox states should now change. $this->assertTrue($checkbox_checked_target->isChecked()); $this->assertFalse($checkbox_unchecked_target->isChecked()); // Details should now be expanded. $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); } /** * Tests states of elements triggered by a select element. */ protected function doSelectTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('select_trigger'); $this->assertNotEmpty($trigger); $item_visible_value2 = $this->assertSession()->elementExists('css', '#edit-item-visible-when-select-trigger-has-value2'); $textfield_visible_value3 = $page->findField('textfield_visible_when_select_trigger_has_value3'); $this->assertNotEmpty($textfield_visible_value3); $textfield_visible_value2_or_value3 = $page->findField('textfield_visible_when_select_trigger_has_value2_or_value3'); $this->assertNotEmpty($textfield_visible_value2_or_value3); // Verify initial state. $this->assertFalse($item_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); $this->assertFalse($textfield_visible_value2_or_value3->isVisible()); // Change state: select the 'Value 2' option. $trigger->setValue('value2'); $this->assertTrue($item_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); $this->assertTrue($textfield_visible_value2_or_value3->isVisible()); // Change state: select the 'Value 3' option. $trigger->setValue('value3'); $this->assertFalse($item_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); $this->assertTrue($textfield_visible_value2_or_value3->isVisible()); } /** * Tests states of elements triggered by multiple elements. */ protected function doMultipleTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $select_trigger = $page->findField('select_trigger'); $this->assertNotEmpty($select_trigger); $textfield_trigger = $page->findField('textfield_trigger'); $this->assertNotEmpty($textfield_trigger); $item_visible_value2_and_textfield = $this->assertSession()->elementExists('css', '#edit-item-visible-when-select-trigger-has-value2-and-textfield-trigger-filled'); // Verify initial state. $this->assertFalse($item_visible_value2_and_textfield->isVisible()); // Change state: select the 'Value 2' option. $select_trigger->setValue('value2'); $this->assertFalse($item_visible_value2_and_textfield->isVisible()); // Change state: fill the textfield. $textfield_trigger->setValue('filled'); $this->assertTrue($item_visible_value2_and_textfield->isVisible()); } } Loading
core/lib/Drupal/Core/Form/FormHelper.php +3 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,9 @@ protected static function processStatesArray(array &$conditions, $search, $repla * * @param array $elements * A render array element having a #states property as described above. * * @see \Drupal\form_test\Form\JavascriptStatesForm * @see \Drupal\FunctionalJavascriptTests\Core\Form\JavascriptStatesTest */ public static function processStates(array &$elements) { $elements['#attached']['library'][] = 'core/drupal.states'; Loading
core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php +296 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,302 @@ public function getFormId() { * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form['checkbox_trigger'] = [ '#type' => 'checkbox', '#title' => 'Checkbox trigger', ]; $form['textfield_trigger'] = [ '#type' => 'textfield', '#title' => 'Textfield trigger', ]; $form['radios_trigger'] = [ '#type' => 'radios', '#title' => 'Radios trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], ]; $form['checkboxes_trigger'] = [ '#type' => 'checkboxes', '#title' => 'Checkboxes trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], ]; $form['select_trigger'] = [ '#type' => 'select', '#title' => 'Select trigger', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], '#empty_value' => '_none', '#empty_option' => '- None -', ]; // Tested fields. // Checkbox trigger. $form['textfield_invisible_when_checkbox_trigger_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield invisible when checkbox trigger checked', '#states' => [ 'invisible' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['textfield_required_when_checkbox_trigger_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield required when checkbox trigger checked', '#states' => [ 'required' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['details_expanded_when_checkbox_trigger_checked'] = [ '#type' => 'details', '#title' => 'Details expanded when checkbox trigger checked', '#states' => [ 'expanded' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['details_expanded_when_checkbox_trigger_checked']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; $form['checkbox_checked_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when checkbox trigger checked', '#states' => [ 'checked' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['checkbox_unchecked_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when checkbox trigger checked', '#states' => [ 'unchecked' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; $form['checkbox_visible_when_checkbox_trigger_checked'] = [ '#type' => 'checkbox', '#title' => 'Checkbox visible when checkbox trigger checked', '#states' => [ 'visible' => [ ':input[name="checkbox_trigger"]' => ['checked' => TRUE], ], ], ]; // Checkboxes trigger. $form['textfield_visible_when_checkboxes_trigger_value2_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when checkboxes trigger value2 checked', '#states' => [ 'visible' => [ ':input[name="checkboxes_trigger[value2]"]' => ['checked' => TRUE], ], ], ]; $form['textfield_visible_when_checkboxes_trigger_value3_checked'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when checkboxes trigger value3 checked', '#states' => [ 'visible' => [ ':input[name="checkboxes_trigger[value3]"]' => ['checked' => TRUE], ], ], ]; // Radios trigger. $form['fieldset_visible_when_radios_trigger_has_value2'] = [ '#type' => 'fieldset', '#title' => 'Fieldset visible when radio trigger has value2', '#states' => [ 'visible' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['fieldset_visible_when_radios_trigger_has_value2']['textfield_in_fieldset'] = [ '#type' => 'textfield', '#title' => 'Textfield in fieldset', ]; $form['textfield_invisible_when_radios_trigger_has_value2'] = [ '#type' => 'textfield', '#title' => 'Textfield invisible when radio trigger has value2', '#states' => [ 'invisible' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['select_required_when_radios_trigger_has_value2'] = [ '#type' => 'select', '#title' => 'Select required when radio trigger has value2', '#options' => [ 'value1' => 'Value 1', 'value2' => 'Value 2', 'value3' => 'Value 3', ], '#states' => [ 'required' => [ ':input[name="radios_trigger"]' => ['value' => 'value2'], ], ], ]; $form['checkbox_checked_when_radios_trigger_has_value3'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when radios trigger has value3', '#states' => [ 'checked' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['checkbox_unchecked_when_radios_trigger_has_value3'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when radios trigger has value3', '#states' => [ 'unchecked' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['details_expanded_when_radios_trigger_has_value3'] = [ '#type' => 'details', '#title' => 'Details expanded when radio trigger has value3', '#states' => [ 'expanded' => [ ':input[name="radios_trigger"]' => ['value' => 'value3'], ], ], ]; $form['details_expanded_when_radios_trigger_has_value3']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; // Select trigger $form['item_visible_when_select_trigger_has_value2'] = [ '#type' => 'item', '#title' => 'Item visible when select trigger has value2', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value2'], ], ], ]; $form['textfield_visible_when_select_trigger_has_value3'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when select trigger has value3', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value3'], ], ], ]; $form['textfield_visible_when_select_trigger_has_value2_or_value3'] = [ '#type' => 'textfield', '#title' => 'Textfield visible when select trigger has value2 or value3', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => [ ['value' => 'value2'], ['value' => 'value3'], ], ], ], ]; // Textfield trigger. $form['checkbox_checked_when_textfield_trigger_filled'] = [ '#type' => 'checkbox', '#title' => 'Checkbox checked when textfield trigger filled', '#default_value' => '0', '#states' => [ 'checked' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['checkbox_unchecked_when_textfield_trigger_filled'] = [ '#type' => 'checkbox', '#title' => 'Checkbox unchecked when textfield trigger filled', '#default_value' => '1', '#states' => [ 'unchecked' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select_invisible_when_textfield_trigger_filled'] = [ '#type' => 'select', '#title' => 'Select invisible when textfield trigger filled', '#options' => [0 => 0, 1 => 1, 2 => 2], '#states' => [ 'invisible' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select_visible_when_textfield_trigger_filled'] = [ '#type' => 'select', '#title' => 'Select visible when textfield trigger filled', '#options' => [0 => 0, 1 => 1, 2 => 2], '#states' => [ 'visible' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['textfield_required_when_textfield_trigger_filled'] = [ '#type' => 'textfield', '#title' => 'Textfield required when textfield trigger filled', '#states' => [ 'required' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['details_expanded_when_textfield_trigger_filled'] = [ '#type' => 'details', '#title' => 'Details expanded when textfield trigger filled', '#states' => [ 'expanded' => [ ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['details_expanded_when_textfield_trigger_filled']['textfield_in_details'] = [ '#type' => 'textfield', '#title' => 'Textfield in details', ]; // Multiple triggers. $form['item_visible_when_select_trigger_has_value2_and_textfield_trigger_filled'] = [ '#type' => 'item', '#title' => 'Item visible when select trigger has value2 and textfield trigger filled', '#states' => [ 'visible' => [ ':input[name="select_trigger"]' => ['value' => 'value2'], ':input[name="textfield_trigger"]' => ['filled' => TRUE], ], ], ]; $form['select'] = [ '#type' => 'select', '#title' => 'select 1', Loading
core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php 0 → 100644 +289 −0 Original line number Diff line number Diff line <?php namespace Drupal\FunctionalJavascriptTests\Core\Form; use Drupal\FunctionalJavascriptTests\WebDriverTestBase; /** * Tests the state of elements based on another elements. * * @group javascript */ class JavascriptStatesTest extends WebDriverTestBase { /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ protected static $modules = ['form_test']; /** * Tests the JavaScript #states functionality of form elements. * * To avoid the large cost of a dataProvider in FunctionalJavascript tests, * this is a single public test method that invokes a series of protected * methods to do assertions on specific kinds of triggering elements. */ public function testJavascriptStates() { $this->doCheckboxTriggerTests(); $this->doCheckboxesTriggerTests(); $this->doTextfieldTriggerTests(); $this->doRadiosTriggerTests(); $this->doSelectTriggerTests(); $this->doMultipleTriggerTests(); } /** * Tests states of elements triggered by a checkbox element. */ protected function doCheckboxTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('checkbox_trigger'); $this->assertNotEmpty($trigger); $textfield_invisible_element = $page->findField('textfield_invisible_when_checkbox_trigger_checked'); $this->assertNotEmpty($textfield_invisible_element); $textfield_required_element = $page->findField('textfield_required_when_checkbox_trigger_checked'); $this->assertNotEmpty($textfield_required_element); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-checkbox-trigger-checked'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); $checkbox_checked_element = $page->findField('checkbox_checked_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_checked_element); $checkbox_unchecked_element = $page->findField('checkbox_unchecked_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_unchecked_element); $checkbox_visible_element = $page->findField('checkbox_visible_when_checkbox_trigger_checked'); $this->assertNotEmpty($checkbox_visible_element); // Verify initial state. $this->assertTrue($textfield_invisible_element->isVisible()); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); $this->assertFalse($textfield_required_element->hasAttribute('required')); $this->assertFalse($checkbox_checked_element->isChecked()); $this->assertTrue($checkbox_unchecked_element->isChecked()); $this->assertFalse($checkbox_visible_element->isVisible()); // Change state: check the checkbox. $trigger->check(); // Verify triggered state. $this->assertFalse($textfield_invisible_element->isVisible()); $this->assertEquals('required', $textfield_required_element->getAttribute('required')); $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); $this->assertTrue($checkbox_checked_element->isChecked()); $this->assertFalse($checkbox_unchecked_element->isChecked()); $this->assertTrue($checkbox_visible_element->isVisible()); } /** * Tests states of elements triggered by a checkboxes element. */ protected function doCheckboxesTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger_value1 = $page->findField('checkboxes_trigger[value1]'); $this->assertNotEmpty($trigger_value1); $trigger_value2 = $page->findField('checkboxes_trigger[value2]'); $this->assertNotEmpty($trigger_value2); $trigger_value3 = $page->findField('checkboxes_trigger[value3]'); $this->assertNotEmpty($trigger_value3); $textfield_visible_value2 = $page->findField('textfield_visible_when_checkboxes_trigger_value2_checked'); $this->assertNotEmpty($textfield_visible_value2); $textfield_visible_value3 = $page->findField('textfield_visible_when_checkboxes_trigger_value3_checked'); $this->assertNotEmpty($textfield_visible_value3); // Verify initial state. $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 1' checkbox. $trigger_value1->check(); $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 2' checkbox. $trigger_value2->check(); $this->assertTrue($textfield_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); // Change state: check the 'Value 3' checkbox. $trigger_value3->check(); $this->assertTrue($textfield_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); // Change state: uncheck the 'Value 2' checkbox. $trigger_value2->uncheck(); $this->assertFalse($textfield_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); } /** * Tests states of elements triggered by a textfield element. */ protected function doTextfieldTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('textfield_trigger'); $this->assertNotEmpty($trigger); $checkbox_checked_target = $page->findField('checkbox_checked_when_textfield_trigger_filled'); $this->assertNotEmpty($checkbox_checked_target); $checkbox_unchecked_target = $page->findField('checkbox_unchecked_when_textfield_trigger_filled'); $this->assertNotEmpty($checkbox_unchecked_target); $select_invisible_target = $page->findField('select_invisible_when_textfield_trigger_filled'); $this->assertNotEmpty($select_invisible_target); $select_visible_target = $page->findField('select_visible_when_textfield_trigger_filled'); $this->assertNotEmpty($select_visible_target); $textfield_required_target = $page->findField('textfield_required_when_textfield_trigger_filled'); $this->assertNotEmpty($textfield_required_target); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-textfield-trigger-filled'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); // Verify initial state. $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertTrue($select_invisible_target->isVisible()); $this->assertFalse($select_visible_target->isVisible()); $this->assertFalse($textfield_required_target->hasAttribute('required')); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: fill the textfield. $trigger->setValue('filled'); // Verify triggered state. $this->assertTrue($checkbox_checked_target->isChecked()); $this->assertFalse($checkbox_unchecked_target->isChecked()); $this->assertFalse($select_invisible_target->isVisible()); $this->assertTrue($select_visible_target->isVisible()); $this->assertEquals('required', $textfield_required_target->getAttribute('required')); $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); } /** * Tests states of elements triggered by a radios element. */ protected function doRadiosTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('radios_trigger'); $this->assertNotEmpty($trigger); $fieldset_visible_when_value2 = $this->assertSession()->elementExists('css', '#edit-fieldset-visible-when-radios-trigger-has-value2'); $textfield_in_fieldset = $fieldset_visible_when_value2->findField('textfield_in_fieldset'); $this->assertNotEmpty($textfield_in_fieldset); $checkbox_checked_target = $page->findField('checkbox_checked_when_radios_trigger_has_value3'); $this->assertNotEmpty($checkbox_checked_target); $checkbox_unchecked_target = $page->findField('checkbox_unchecked_when_radios_trigger_has_value3'); $this->assertNotEmpty($checkbox_unchecked_target); $textfield_invisible_target = $page->findField('textfield_invisible_when_radios_trigger_has_value2'); $this->assertNotEmpty($textfield_invisible_target); $select_required_target = $page->findField('select_required_when_radios_trigger_has_value2'); $this->assertNotEmpty($select_required_target); $details = $this->assertSession()->elementExists('css', '#edit-details-expanded-when-radios-trigger-has-value3'); $textfield_in_details = $details->findField('textfield_in_details'); $this->assertNotEmpty($textfield_in_details); // Verify initial state, both the fieldset and something inside it. $this->assertFalse($fieldset_visible_when_value2->isVisible()); $this->assertFalse($textfield_in_fieldset->isVisible()); $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertTrue($textfield_invisible_target->isVisible()); $this->assertFalse($select_required_target->hasAttribute('required')); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: select the value2 radios option. $trigger->selectOption('value2'); // Verify triggered state. $this->assertTrue($fieldset_visible_when_value2->isVisible()); $this->assertTrue($textfield_in_fieldset->isVisible()); $this->assertFalse($textfield_invisible_target->isVisible()); $this->assertTrue($select_required_target->hasAttribute('required')); // Checkboxes and details should not have changed state, yet. $this->assertFalse($checkbox_checked_target->isChecked()); $this->assertTrue($checkbox_unchecked_target->isChecked()); $this->assertFalse($details->hasAttribute('open')); $this->assertFalse($textfield_in_details->isVisible()); // Change state: select the value3 radios option. $trigger->selectOption('value3'); // Fieldset and contents should re-disappear. $this->assertFalse($fieldset_visible_when_value2->isVisible()); $this->assertFalse($textfield_in_fieldset->isVisible()); // Textfield and select should revert to initial state. $this->assertTrue($textfield_invisible_target->isVisible()); $this->assertFalse($select_required_target->hasAttribute('required')); // Checkbox states should now change. $this->assertTrue($checkbox_checked_target->isChecked()); $this->assertFalse($checkbox_unchecked_target->isChecked()); // Details should now be expanded. $this->assertTrue($details->hasAttribute('open')); $this->assertTrue($textfield_in_details->isVisible()); } /** * Tests states of elements triggered by a select element. */ protected function doSelectTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $trigger = $page->findField('select_trigger'); $this->assertNotEmpty($trigger); $item_visible_value2 = $this->assertSession()->elementExists('css', '#edit-item-visible-when-select-trigger-has-value2'); $textfield_visible_value3 = $page->findField('textfield_visible_when_select_trigger_has_value3'); $this->assertNotEmpty($textfield_visible_value3); $textfield_visible_value2_or_value3 = $page->findField('textfield_visible_when_select_trigger_has_value2_or_value3'); $this->assertNotEmpty($textfield_visible_value2_or_value3); // Verify initial state. $this->assertFalse($item_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); $this->assertFalse($textfield_visible_value2_or_value3->isVisible()); // Change state: select the 'Value 2' option. $trigger->setValue('value2'); $this->assertTrue($item_visible_value2->isVisible()); $this->assertFalse($textfield_visible_value3->isVisible()); $this->assertTrue($textfield_visible_value2_or_value3->isVisible()); // Change state: select the 'Value 3' option. $trigger->setValue('value3'); $this->assertFalse($item_visible_value2->isVisible()); $this->assertTrue($textfield_visible_value3->isVisible()); $this->assertTrue($textfield_visible_value2_or_value3->isVisible()); } /** * Tests states of elements triggered by multiple elements. */ protected function doMultipleTriggerTests() { $this->drupalGet('form-test/javascript-states-form'); $page = $this->getSession()->getPage(); // Find trigger and target elements. $select_trigger = $page->findField('select_trigger'); $this->assertNotEmpty($select_trigger); $textfield_trigger = $page->findField('textfield_trigger'); $this->assertNotEmpty($textfield_trigger); $item_visible_value2_and_textfield = $this->assertSession()->elementExists('css', '#edit-item-visible-when-select-trigger-has-value2-and-textfield-trigger-filled'); // Verify initial state. $this->assertFalse($item_visible_value2_and_textfield->isVisible()); // Change state: select the 'Value 2' option. $select_trigger->setValue('value2'); $this->assertFalse($item_visible_value2_and_textfield->isVisible()); // Change state: fill the textfield. $textfield_trigger->setValue('filled'); $this->assertTrue($item_visible_value2_and_textfield->isVisible()); } }