Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / system / tests / src / Functional / Form / ElementsLabelsTest.php
1 <?php
2
3 namespace Drupal\Tests\system\Functional\Form;
4
5 use Drupal\form_test\Form\FormTestLabelForm;
6 use Drupal\Tests\BrowserTestBase;
7
8 /**
9  * Tests form element labels, required markers and associated output.
10  *
11  * @group Form
12  */
13 class ElementsLabelsTest extends BrowserTestBase {
14
15   /**
16    * Modules to enable.
17    *
18    * @var array
19    */
20   public static $modules = ['form_test'];
21
22   /**
23    * Test form elements, labels, title attributes and required marks output
24    * correctly and have the correct label option class if needed.
25    */
26   public function testFormLabels() {
27     $this->drupalGet('form_test/form-labels');
28
29     // Check that the checkbox/radio processing is not interfering with
30     // basic placement.
31     $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-third-checkbox"]/following-sibling::label[@for="edit-form-checkboxes-test-third-checkbox" and @class="option"]');
32     $this->assertTrue(isset($elements[0]), 'Label follows field and label option class correct for regular checkboxes.');
33
34     // Make sure the label is rendered for checkboxes.
35     $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-0"]/following-sibling::label[@for="edit-form-checkboxes-test-0" and @class="option"]');
36     $this->assertTrue(isset($elements[0]), 'Label 0 found checkbox.');
37
38     $elements = $this->xpath('//input[@id="edit-form-radios-test-second-radio"]/following-sibling::label[@for="edit-form-radios-test-second-radio" and @class="option"]');
39     $this->assertTrue(isset($elements[0]), 'Label follows field and label option class correct for regular radios.');
40
41     // Make sure the label is rendered for radios.
42     $elements = $this->xpath('//input[@id="edit-form-radios-test-0"]/following-sibling::label[@for="edit-form-radios-test-0" and @class="option"]');
43     $this->assertTrue(isset($elements[0]), 'Label 0 found radios.');
44
45     // Exercise various defaults for checkboxes and modifications to ensure
46     // appropriate override and correct behavior.
47     $elements = $this->xpath('//input[@id="edit-form-checkbox-test"]/following-sibling::label[@for="edit-form-checkbox-test" and @class="option"]');
48     $this->assertTrue(isset($elements[0]), 'Label follows field and label option class correct for a checkbox by default.');
49
50     // Exercise various defaults for textboxes and modifications to ensure
51     // appropriate override and correct behavior.
52     $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
53     $this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.');
54
55     $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required" and @class="js-form-required form-required"]');
56     $this->assertTrue(isset($elements[0]), 'Label tag with required marker precedes required textfield with no title.');
57
58     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]');
59     $this->assertTrue(isset($elements[0]), 'Label preceding field and label class is visually-hidden.');
60
61     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title"]/preceding-sibling::span[@class="js-form-required form-required"]');
62     $this->assertFalse(isset($elements[0]), 'No required marker on non-required field.');
63
64     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-after"]/following-sibling::label[@for="edit-form-textfield-test-title-after" and @class="option"]');
65     $this->assertTrue(isset($elements[0]), 'Label after field and label option class correct for text field.');
66
67     $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-no-show"]');
68     $this->assertFalse(isset($elements[0]), 'No label tag when title set not to display.');
69
70     $elements = $this->xpath('//div[contains(@class, "js-form-item-form-textfield-test-title-invisible") and contains(@class, "form-no-label")]');
71     $this->assertTrue(isset($elements[0]), 'Field class is form-no-label when there is no label.');
72
73     // Check #field_prefix and #field_suffix placement.
74     $elements = $this->xpath('//span[@class="field-prefix"]/following-sibling::div[@id="edit-form-radios-test"]');
75     $this->assertTrue(isset($elements[0]), 'Properly placed the #field_prefix element after the label and before the field.');
76
77     $elements = $this->xpath('//span[@class="field-suffix"]/preceding-sibling::div[@id="edit-form-radios-test"]');
78     $this->assertTrue(isset($elements[0]), 'Properly places the #field_suffix element immediately after the form field.');
79
80     // Check #prefix and #suffix placement.
81     $elements = $this->xpath('//div[@id="form-test-textfield-title-prefix"]/following-sibling::div[contains(@class, \'js-form-item-form-textfield-test-title\')]');
82     $this->assertTrue(isset($elements[0]), 'Properly places the #prefix element before the form item.');
83
84     $elements = $this->xpath('//div[@id="form-test-textfield-title-suffix"]/preceding-sibling::div[contains(@class, \'js-form-item-form-textfield-test-title\')]');
85     $this->assertTrue(isset($elements[0]), 'Properly places the #suffix element before the form item.');
86
87     // Check title attribute for radios and checkboxes.
88     $elements = $this->xpath('//div[@id="edit-form-checkboxes-title-attribute"]');
89     $this->assertEqual($elements[0]->getAttribute('title'), 'Checkboxes test' . ' (' . t('Required') . ')', 'Title attribute found.');
90     $elements = $this->xpath('//div[@id="edit-form-radios-title-attribute"]');
91     $this->assertEqual($elements[0]->getAttribute('title'), 'Radios test' . ' (' . t('Required') . ')', 'Title attribute found.');
92
93     $elements = $this->xpath('//fieldset[@id="edit-form-checkboxes-title-invisible--wrapper"]/legend/span[contains(@class, "visually-hidden")]');
94     $this->assertTrue(!empty($elements), "Title/Label not displayed when 'visually-hidden' attribute is set in checkboxes.");
95
96     $elements = $this->xpath('//fieldset[@id="edit-form-radios-title-invisible--wrapper"]/legend/span[contains(@class, "visually-hidden")]');
97     $this->assertTrue(!empty($elements), "Title/Label not displayed when 'visually-hidden' attribute is set in radios.");
98   }
99
100   /**
101    * Tests XSS-protection of element labels.
102    */
103   public function testTitleEscaping() {
104     $this->drupalGet('form_test/form-labels');
105     foreach (FormTestLabelForm::$typesWithTitle as $type) {
106       $this->assertSession()->responseContains("$type alert('XSS') is XSS filtered!");
107       $this->assertSession()->responseNotContains("$type <script>alert('XSS')</script> is XSS filtered!");
108     }
109   }
110
111   /**
112    * Tests different display options for form element descriptions.
113    */
114   public function testFormDescriptions() {
115     $this->drupalGet('form_test/form-descriptions');
116
117     // Check #description placement with #description_display='after'.
118     $field_id = 'edit-form-textfield-test-description-after';
119     $description_id = $field_id . '--description';
120     $elements = $this->xpath('//input[@id="' . $field_id . '" and @aria-describedby="' . $description_id . '"]/following-sibling::div[@id="' . $description_id . '"]');
121     $this->assertTrue(isset($elements[0]), t('Properly places the #description element after the form item.'));
122
123     // Check #description placement with #description_display='before'.
124     $field_id = 'edit-form-textfield-test-description-before';
125     $description_id = $field_id . '--description';
126     $elements = $this->xpath('//input[@id="' . $field_id . '" and @aria-describedby="' . $description_id . '"]/preceding-sibling::div[@id="' . $description_id . '"]');
127     $this->assertTrue(isset($elements[0]), t('Properly places the #description element before the form item.'));
128
129     // Check if the class is 'visually-hidden' on the form element description
130     // for the option with #description_display='invisible' and also check that
131     // the description is placed after the form element.
132     $field_id = 'edit-form-textfield-test-description-invisible';
133     $description_id = $field_id . '--description';
134     $elements = $this->xpath('//input[@id="' . $field_id . '" and @aria-describedby="' . $description_id . '"]/following-sibling::div[contains(@class, "visually-hidden")]');
135     $this->assertTrue(isset($elements[0]), t('Properly renders the #description element visually-hidden.'));
136   }
137
138   /**
139    * Test forms in theme-less environments.
140    */
141   public function testFormsInThemeLessEnvironments() {
142     $form = $this->getFormWithLimitedProperties();
143     $render_service = $this->container->get('renderer');
144     // This should not throw any notices.
145     $render_service->renderPlain($form);
146   }
147
148   /**
149    * Return a form with element with not all properties defined.
150    */
151   protected function getFormWithLimitedProperties() {
152     $form = [];
153
154     $form['fieldset'] = [
155       '#type' => 'fieldset',
156       '#title' => 'Fieldset',
157     ];
158
159     return $form;
160   }
161
162 }