Version 1
[yaffs-website] / web / core / modules / system / src / Tests / Form / ValidationTest.php
1 <?php
2
3 namespace Drupal\system\Tests\Form;
4
5 use Drupal\Core\Render\Element;
6 use Drupal\simpletest\WebTestBase;
7
8 /**
9  * Tests form processing and alteration via form validation handlers.
10  *
11  * @group Form
12  */
13 class ValidationTest extends WebTestBase {
14
15   /**
16    * Modules to enable.
17    *
18    * @var array
19    */
20   public static $modules = ['form_test'];
21
22   /**
23    * Tests #element_validate and #validate.
24    */
25   public function testValidate() {
26     $this->drupalGet('form-test/validate');
27     // Verify that #element_validate handlers can alter the form and submitted
28     // form values.
29     $edit = [
30       'name' => 'element_validate',
31     ];
32     $this->drupalPostForm(NULL, $edit, 'Save');
33     $this->assertFieldByName('name', '#value changed by #element_validate', 'Form element #value was altered.');
34     $this->assertText('Name value: value changed by setValueForElement() in #element_validate', 'Form element value in $form_state was altered.');
35
36     // Verify that #validate handlers can alter the form and submitted
37     // form values.
38     $edit = [
39       'name' => 'validate',
40     ];
41     $this->drupalPostForm(NULL, $edit, 'Save');
42     $this->assertFieldByName('name', '#value changed by #validate', 'Form element #value was altered.');
43     $this->assertText('Name value: value changed by setValueForElement() in #validate', 'Form element value in $form_state was altered.');
44
45     // Verify that #element_validate handlers can make form elements
46     // inaccessible, but values persist.
47     $edit = [
48       'name' => 'element_validate_access',
49     ];
50     $this->drupalPostForm(NULL, $edit, 'Save');
51     $this->assertNoFieldByName('name', 'Form element was hidden.');
52     $this->assertText('Name value: element_validate_access', 'Value for inaccessible form element exists.');
53
54     // Verify that value for inaccessible form element persists.
55     $this->drupalPostForm(NULL, [], 'Save');
56     $this->assertNoFieldByName('name', 'Form element was hidden.');
57     $this->assertText('Name value: element_validate_access', 'Value for inaccessible form element exists.');
58
59     // Verify that #validate handlers don't run if the CSRF token is invalid.
60     $this->drupalLogin($this->drupalCreateUser());
61     $this->drupalGet('form-test/validate');
62     $edit = [
63       'name' => 'validate',
64       'form_token' => 'invalid token'
65     ];
66     $this->drupalPostForm(NULL, $edit, 'Save');
67     $this->assertNoFieldByName('name', '#value changed by #validate', 'Form element #value was not altered.');
68     $this->assertNoText('Name value: value changed by setValueForElement() in #validate', 'Form element value in $form_state was not altered.');
69     $this->assertText('The form has become outdated. Copy any unsaved work in the form below');
70   }
71
72   /**
73    * Tests that a form with a disabled CSRF token can be validated.
74    */
75   public function testDisabledToken() {
76     $this->drupalPostForm('form-test/validate-no-token', [], 'Save');
77     $this->assertText('The form_test_validate_no_token form has been submitted successfully.');
78   }
79
80   /**
81    * Tests partial form validation through #limit_validation_errors.
82    */
83   public function testValidateLimitErrors() {
84     $edit = [
85       'test' => 'invalid',
86       'test_numeric_index[0]' => 'invalid',
87       'test_substring[foo]' => 'invalid',
88     ];
89     $path = 'form-test/limit-validation-errors';
90
91     // Render the form, and verify that the buttons with limited server-side
92     // validation have the proper 'formnovalidate' attribute (to prevent
93     // client-side validation by the browser).
94     $this->drupalGet($path);
95     $expected = 'formnovalidate';
96     foreach (['partial', 'partial-numeric-index', 'substring'] as $type) {
97       $element = $this->xpath('//input[@id=:id and @formnovalidate=:expected]', [
98         ':id' => 'edit-' . $type,
99         ':expected' => $expected,
100       ]);
101       $this->assertTrue(!empty($element), format_string('The @type button has the proper formnovalidate attribute.', ['@type' => $type]));
102     }
103     // The button with full server-side validation should not have the
104     // 'formnovalidate' attribute.
105     $element = $this->xpath('//input[@id=:id and not(@formnovalidate)]', [
106       ':id' => 'edit-full',
107     ]);
108     $this->assertTrue(!empty($element), 'The button with full server-side validation does not have the formnovalidate attribute.');
109
110     // Submit the form by pressing the 'Partial validate' button (uses
111     // #limit_validation_errors) and ensure that the title field is not
112     // validated, but the #element_validate handler for the 'test' field
113     // is triggered.
114     $this->drupalPostForm($path, $edit, t('Partial validate'));
115     $this->assertNoText(t('@name field is required.', ['@name' => 'Title']));
116     $this->assertText('Test element is invalid');
117
118     // Edge case of #limit_validation_errors containing numeric indexes: same
119     // thing with the 'Partial validate (numeric index)' button and the
120     // 'test_numeric_index' field.
121     $this->drupalPostForm($path, $edit, t('Partial validate (numeric index)'));
122     $this->assertNoText(t('@name field is required.', ['@name' => 'Title']));
123     $this->assertText('Test (numeric index) element is invalid');
124
125     // Ensure something like 'foobar' isn't considered "inside" 'foo'.
126     $this->drupalPostForm($path, $edit, t('Partial validate (substring)'));
127     $this->assertNoText(t('@name field is required.', ['@name' => 'Title']));
128     $this->assertText('Test (substring) foo element is invalid');
129
130     // Ensure not validated values are not available to submit handlers.
131     $this->drupalPostForm($path, ['title' => '', 'test' => 'valid'], t('Partial validate'));
132     $this->assertText('Only validated values appear in the form values.');
133
134     // Now test full form validation and ensure that the #element_validate
135     // handler is still triggered.
136     $this->drupalPostForm($path, $edit, t('Full validate'));
137     $this->assertText(t('@name field is required.', ['@name' => 'Title']));
138     $this->assertText('Test element is invalid');
139   }
140
141   /**
142    * Tests #pattern validation.
143    */
144   public function testPatternValidation() {
145     $textfield_error = t('%name field is not in the right format.', ['%name' => 'One digit followed by lowercase letters']);
146     $tel_error = t('%name field is not in the right format.', ['%name' => 'Everything except numbers']);
147     $password_error = t('%name field is not in the right format.', ['%name' => 'Password']);
148
149     // Invalid textfield, valid tel.
150     $edit = [
151       'textfield' => 'invalid',
152       'tel' => 'valid',
153     ];
154     $this->drupalPostForm('form-test/pattern', $edit, 'Submit');
155     $this->assertRaw($textfield_error);
156     $this->assertNoRaw($tel_error);
157     $this->assertNoRaw($password_error);
158
159     // Valid textfield, invalid tel, valid password.
160     $edit = [
161       'textfield' => '7seven',
162       'tel' => '818937',
163       'password' => '0100110',
164     ];
165     $this->drupalPostForm('form-test/pattern', $edit, 'Submit');
166     $this->assertNoRaw($textfield_error);
167     $this->assertRaw($tel_error);
168     $this->assertNoRaw($password_error);
169
170     // Non required fields are not validated if empty.
171     $edit = [
172       'textfield' => '',
173       'tel' => '',
174     ];
175     $this->drupalPostForm('form-test/pattern', $edit, 'Submit');
176     $this->assertNoRaw($textfield_error);
177     $this->assertNoRaw($tel_error);
178     $this->assertNoRaw($password_error);
179
180     // Invalid password.
181     $edit = [
182       'password' => $this->randomMachineName(),
183     ];
184     $this->drupalPostForm('form-test/pattern', $edit, 'Submit');
185     $this->assertNoRaw($textfield_error);
186     $this->assertNoRaw($tel_error);
187     $this->assertRaw($password_error);
188
189     // The pattern attribute overrides #pattern and is not validated on the
190     // server side.
191     $edit = [
192       'textfield' => '',
193       'tel' => '',
194       'url' => 'http://www.example.com/',
195     ];
196     $this->drupalPostForm('form-test/pattern', $edit, 'Submit');
197     $this->assertNoRaw(t('%name field is not in the right format.', ['%name' => 'Client side validation']));
198   }
199
200   /**
201    * Tests #required with custom validation errors.
202    *
203    * @see \Drupal\form_test\Form\FormTestValidateRequiredForm
204    */
205   public function testCustomRequiredError() {
206     $form = \Drupal::formBuilder()->getForm('\Drupal\form_test\Form\FormTestValidateRequiredForm');
207
208     // Verify that a custom #required error can be set.
209     $edit = [];
210     $this->drupalPostForm('form-test/validate-required', $edit, 'Submit');
211
212     foreach (Element::children($form) as $key) {
213       if (isset($form[$key]['#required_error'])) {
214         $this->assertNoText(t('@name field is required.', ['@name' => $form[$key]['#title']]));
215         $this->assertText($form[$key]['#required_error']);
216       }
217       elseif (isset($form[$key]['#form_test_required_error'])) {
218         $this->assertNoText(t('@name field is required.', ['@name' => $form[$key]['#title']]));
219         $this->assertText($form[$key]['#form_test_required_error']);
220       }
221     }
222     $this->assertNoText(t('An illegal choice has been detected. Please contact the site administrator.'));
223
224     // Verify that no custom validation error appears with valid values.
225     $edit = [
226       'textfield' => $this->randomString(),
227       'checkboxes[foo]' => TRUE,
228       'select' => 'foo',
229     ];
230     $this->drupalPostForm('form-test/validate-required', $edit, 'Submit');
231
232     foreach (Element::children($form) as $key) {
233       if (isset($form[$key]['#required_error'])) {
234         $this->assertNoText(t('@name field is required.', ['@name' => $form[$key]['#title']]));
235         $this->assertNoText($form[$key]['#required_error']);
236       }
237       elseif (isset($form[$key]['#form_test_required_error'])) {
238         $this->assertNoText(t('@name field is required.', ['@name' => $form[$key]['#title']]));
239         $this->assertNoText($form[$key]['#form_test_required_error']);
240       }
241     }
242     $this->assertNoText(t('An illegal choice has been detected. Please contact the site administrator.'));
243   }
244
245 }