diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml index d8c5833..22b1221 100644 --- a/core/modules/system/tests/modules/form_test/form_test.routing.yml +++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml @@ -480,3 +480,10 @@ form_test.get_form: _form: '\Drupal\form_test\Form\FormTestGetForm' requirements: _access: 'TRUE' + +form_test.javascript_states_form: + path: '/form-test/javascript-states-form' + defaults: + _form: '\Drupal\form_test\Form\JavascriptStatesForm' + requirements: + _access: 'TRUE' diff --git a/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php new file mode 100644 index 0000000..8b94871 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php @@ -0,0 +1,278 @@ + 'textfield', + '#title' => $this->t('Name'), + '#states' => array( + 'invisible' => array( + ':input[name="anonymous"]' => array('checked' => TRUE), + ), + ), + ); + + // Uncheck anonymous field when the name field is filled. + $form['anonymous'] = array( + '#type' => 'checkbox', + '#title' => $this->t('I prefer to remain anonymous'), + '#default_value' => '1', + '#states' => array( + 'unchecked' => array( + ':input[name="name"]' => array('filled' => TRUE), + ), + ), + ); + + $form['student_type'] = array( + '#type' => 'radios', + '#options' => array( + 'high_school' => $this->t('High School'), + 'undergraduate' => $this->t('Undergraduate'), + 'graduate' => $this->t('Graduate'), + ), + '#title' => $this->t('What type of student are you?'), + ); + $form['high_school'] = array( + '#type' => 'fieldset', + '#title' => $this->t('High School Information'), + // This #states rule says that the "high school" fieldset should only + // be shown if the "student_type" form element is set to "High School". + '#states' => array( + 'visible' => array( + ':input[name="student_type"]' => array('value' => 'high_school'), + ), + ), + ); + + // High school information. + $form['high_school']['tests_taken'] = array( + '#type' => 'checkboxes', + '#options' => array_combine(array('SAT', 'ACT'), array(t('SAT'), t('ACT'))), + '#title' => $this->t('What standardized tests did you take?'), + // This #states rule says that this checkboxes array will be visible only + // when $form['student_type'] is set to t('High School'). + // It uses the jQuery selector :input[name=student_type] to choose the + // element which triggers the behavior, and then defines the "High School" + // value as the one that triggers visibility. + '#states' => array( + // Action to take. + 'visible' => array( + ':input[name="student_type"]' => array('value' => 'high_school'), + ), + ), + ); + + $form['high_school']['sat_score'] = array( + '#type' => 'textfield', + '#title' => $this->t('Your SAT score:'), + '#size' => 4, + + // This #states rule limits visibility to when the $form['tests_taken'] + // 'SAT' checkbox is checked." + '#states' => array( + // Action to take. + 'visible' => array( + ':input[name="tests_taken[SAT]"]' => array('checked' => TRUE), + ), + ), + ); + $form['high_school']['act_score'] = array( + '#type' => 'textfield', + '#title' => $this->t('Your ACT score:'), + '#size' => 4, + + // Set this element visible if the ACT checkbox above is checked. + '#states' => array( + // Action to take. + 'visible' => array( + ':input[name="tests_taken[ACT]"]' => array('checked' => TRUE), + ), + ), + ); + + // Undergrad information. + $form['undergraduate'] = array( + '#type' => 'fieldset', + '#title' => $this->t('Undergraduate Information'), + // This #states rule says that the "undergraduate" fieldset should only + // be shown if the "student_type" form element is set to "Undergraduate". + '#states' => array( + 'visible' => array( + ':input[name="student_type"]' => array('value' => 'undergraduate'), + ), + ), + ); + + $form['undergraduate']['how_many_years'] = array( + '#type' => 'select', + '#title' => $this->t('How many years have you completed?'), + // The options here are integers, but since all the action here happens + // using the DOM on the client, we will have to use strings to work with + // them. + '#options' => array( + 1 => $this->t('One'), + 2 => $this->t('Two'), + 3 => $this->t('Three'), + 4 => $this->t('Four'), + 5 => $this->t('Lots'), + ), + ); + + $form['undergraduate']['comment'] = array( + '#type' => 'item', + '#description' => $this->t("Wow, that's a long time."), + '#states' => array( + 'visible' => array( + // Note that '5' must be used here instead of the integer 5. + // The information is coming from the DOM as a string. + ':input[name="how_many_years"]' => array('value' => '5'), + ), + ), + ); + $form['undergraduate']['school_name'] = array( + '#type' => 'textfield', + '#title' => $this->t('Your college or university:'), + ); + $form['undergraduate']['school_country'] = array( + '#type' => 'select', + '#options' => array_combine(array('UK', 'Other'), array(t('UK'), t('Other'))), + '#title' => $this->t('In what country is your college or university located?'), + ); + $form['undergraduate']['country_writein'] = array( + '#type' => 'textfield', + '#size' => 20, + '#title' => $this->t('Please enter the name of the country where your college or university is located.'), + + // Only show this field if school_country is set to 'Other'. + '#states' => array( + // Action to take: Make visible. + 'visible' => array( + ':input[name="school_country"]' => array('value' => $this->t('Other')), + ), + ), + ); + + $form['undergraduate']['thanks'] = array( + '#type' => 'item', + '#description' => $this->t('Thanks for providing both your school and your country.'), + '#states' => array( + // Here visibility requires that two separate conditions be true. + 'visible' => array( + ':input[name="school_country"]' => array('value' => $this->t('Other')), + ':input[name="country_writein"]' => array('filled' => TRUE), + ), + ), + ); + $form['undergraduate']['go_away'] = array( + '#type' => 'submit', + '#value' => $this->t('Done with form'), + '#states' => array( + // Here visibility requires that two separate conditions be true. + 'visible' => array( + ':input[name="school_country"]' => array('value' => $this->t('Other')), + ':input[name="country_writein"]' => array('filled' => TRUE), + ), + ), + ); + + // Graduate student information. + $form['graduate'] = array( + '#type' => 'fieldset', + '#title' => $this->t('Graduate School Information'), + // This #states rule says that the "graduate" fieldset should only + // be shown if the "student_type" form element is set to "Graduate". + '#states' => array( + 'visible' => array( + ':input[name="student_type"]' => array('value' => 'graduate'), + ), + ), + ); + $form['graduate']['more_info'] = array( + '#type' => 'textarea', + '#title' => $this->t('Please describe your graduate studies'), + ); + + $form['graduate']['info_provide'] = array( + '#type' => 'checkbox', + '#title' => $this->t('Check here if you have provided information above'), + '#disabled' => TRUE, + '#states' => array( + // Mark this checkbox checked if the "more_info" textarea has something + // in it, if it's 'filled'. + 'checked' => array( + ':input[name="more_info"]' => array('filled' => TRUE), + ), + ), + ); + + $form['average'] = array( + '#type' => 'textfield', + '#title' => $this->t('Enter your average'), + // To trigger a state when the same controlling element can have more than + // one possible value, put all values in a higher-level array. + '#states' => array( + 'visible' => array( + ':input[name="student_type"]' => array( + array('value' => 'high_school'), + array('value' => 'undergraduate'), + ), + ), + ), + ); + + $form['expand_more_info'] = array( + '#type' => 'checkbox', + '#title' => $this->t('Check here if you want to add more information.'), + ); + $form['more_info'] = array( + '#type' => 'details', + '#title' => $this->t('Additional Information'), + // Expand the expand_more_info fieldset if the box is checked. + '#states' => array( + 'expanded' => array( + ':input[name="expand_more_info"]' => array('checked' => TRUE), + ), + ), + ); + $form['more_info']['feedback'] = array( + '#type' => 'textarea', + '#title' => $this->t('What do you have to say?'), + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + } + +} diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php new file mode 100644 index 0000000..e1f0f31 --- /dev/null +++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php @@ -0,0 +1,110 @@ +drupalGet('form-test/javascript-states-form'); + $driver = $this->getSession()->getDriver(); + + $this->assertElementNotVisible('#edit-name', 'Name field is not visible.'); + + // This should make the name element visible. + $this->click('#edit-anonymous'); + $this->assertElementVisible('#edit-name', 'Name field is not visible.'); + + // This should make the name element invisible. + $this->click('#edit-anonymous'); + $this->assertElementNotVisible('#edit-name', 'Name field is not visible.'); + + // This should make the name element visible. + $this->click('#edit-anonymous'); + $this->assertElementVisible('#edit-name', 'Name field is visible.'); + + // Ensure all the details elements are invisible. + $this->assertElementNotVisible('#edit-high-school'); + $this->assertElementNotVisible('#edit-undergraduate'); + $this->assertElementNotVisible('#edit-graduate'); + $this->assertElementNotVisible('#edit-average'); + + // High school form testing. + $this->click('#edit-student-type-high-school'); + $this->assertElementVisible('#edit-high-school'); + $this->assertElementNotVisible('#edit-undergraduate'); + $this->assertElementNotVisible('#edit-graduate'); + $this->assertElementVisible('#edit-average'); + + $this->assertElementNotVisible('#edit-sat-score'); + $this->assertElementNotVisible('#edit-act-score'); + $this->click('#edit-tests-taken-sat'); + $this->assertElementVisible('#edit-sat-score'); + $this->assertElementNotVisible('#edit-act-score'); + $this->click('#edit-tests-taken-act'); + $this->assertElementVisible('#edit-act-score'); + $this->assertElementVisible('#edit-sat-score'); + $this->click('#edit-tests-taken-sat'); + $this->click('#edit-tests-taken-act'); + $this->assertElementNotVisible('#edit-sat-score'); + $this->assertElementNotVisible('#edit-act-score'); + + // Undergraduate form testing. + $this->click('#edit-student-type-undergraduate'); + $this->assertElementNotVisible('#edit-high-school'); + $this->assertElementVisible('#edit-undergraduate'); + $this->assertElementNotVisible('#edit-graduate'); + $this->assertElementVisible('#edit-average'); + + $this->assertElementNotVisible('#edit-comment--description'); + $driver->selectOption(CssSelector::toXPath('#edit-how-many-years'), '5'); + $this->assertElementVisible('#edit-comment--description'); + $this->assertElementNotVisible('#edit-country-writein'); + $driver->selectOption(CssSelector::toXPath('#edit-school-country'), 'Other'); + $this->assertElementVisible('#edit-country-writein'); + $driver->selectOption(CssSelector::toXPath('#edit-school-country'), 'UK'); + $this->assertElementNotVisible('#edit-country-writein'); + + // Graduate form testing. + $this->click('#edit-student-type-graduate'); + $this->assertElementNotVisible('#edit-high-school'); + $this->assertElementNotVisible('#edit-undergraduate'); + $this->assertElementVisible('#edit-graduate'); + $this->assertElementNotVisible('#edit-average'); + + $this->assertFalse($driver->isChecked(CssSelector::toXPath('#edit-info-provide')), '#edit-info-provide is not checked'); + $driver->setValue(CssSelector::toXPath('#edit-more-info'), 'Some text'); + $this->assertTrue($driver->isChecked(CssSelector::toXPath('#edit-info-provide')), '#edit-info-provide is checked'); + // This is not working for some reason. +// $driver->setValue(CssSelector::toXPath('#edit-more-info'), ''); +// $this->assertFalse($driver->isChecked(CssSelector::toXPath('#edit-info-provide')), '#edit-info-provide is not checked'); + + // Feedback testing. + $this->assertElementNotVisible('#edit-feedback'); + $this->click('#edit-expand-more-info'); + $this->assertElementVisible('#edit-feedback'); + $this->click('#edit-expand-more-info'); + $this->assertElementNotVisible('#edit-feedback'); + } + +}