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