c1b135f0433948457ba1e5aeaf00bf187106d69c
[yaffs-website] / web / core / modules / field / tests / src / Functional / FormTest.php
1 <?php
2
3 namespace Drupal\Tests\field\Functional;
4
5 use Drupal\Component\Utility\Html;
6 use Drupal\Core\Entity\Entity\EntityFormDisplay;
7 use Drupal\Core\Field\FieldStorageDefinitionInterface;
8 use Drupal\Core\Form\FormState;
9 use Drupal\entity_test\Entity\EntityTest;
10 use Drupal\entity_test\Entity\EntityTestBaseFieldDisplay;
11 use Drupal\field\Entity\FieldConfig;
12 use Drupal\field\Entity\FieldStorageConfig;
13
14 /**
15  * Tests field form handling.
16  *
17  * @group field
18  */
19 class FormTest extends FieldTestBase {
20
21   /**
22    * Modules to enable.
23    *
24    * Locale is installed so that TranslatableMarkup actually does something.
25    *
26    * @var array
27    */
28   public static $modules = ['node', 'field_test', 'options', 'entity_test', 'locale'];
29
30   /**
31    * An array of values defining a field single.
32    *
33    * @var array
34    */
35   protected $fieldStorageSingle;
36
37   /**
38    * An array of values defining a field multiple.
39    *
40    * @var array
41    */
42   protected $fieldStorageMultiple;
43
44   /**
45    * An array of values defining a field with unlimited cardinality.
46    *
47    * @var array
48    */
49   protected $fieldStorageUnlimited;
50
51   /**
52    * An array of values defining a field.
53    *
54    * @var array
55    */
56   protected $field;
57
58   protected function setUp() {
59     parent::setUp();
60
61     $web_user = $this->drupalCreateUser(['view test entity', 'administer entity_test content']);
62     $this->drupalLogin($web_user);
63
64     $this->fieldStorageSingle = [
65       'field_name' => 'field_single',
66       'entity_type' => 'entity_test',
67       'type' => 'test_field',
68     ];
69     $this->fieldStorageMultiple = [
70       'field_name' => 'field_multiple',
71       'entity_type' => 'entity_test',
72       'type' => 'test_field',
73       'cardinality' => 4,
74     ];
75     $this->fieldStorageUnlimited = [
76       'field_name' => 'field_unlimited',
77       'entity_type' => 'entity_test',
78       'type' => 'test_field',
79       'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
80     ];
81
82     $this->field = [
83       'entity_type' => 'entity_test',
84       'bundle' => 'entity_test',
85       'label' => $this->randomMachineName() . '_label',
86       'description' => '[site:name]_description',
87       'weight' => mt_rand(0, 127),
88       'settings' => [
89         'test_field_setting' => $this->randomMachineName(),
90       ],
91     ];
92   }
93
94   public function testFieldFormSingle() {
95     $field_storage = $this->fieldStorageSingle;
96     $field_name = $field_storage['field_name'];
97     $this->field['field_name'] = $field_name;
98     FieldStorageConfig::create($field_storage)->save();
99     FieldConfig::create($this->field)->save();
100     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
101       ->setComponent($field_name)
102       ->save();
103
104     // Display creation form.
105     $this->drupalGet('entity_test/add');
106
107     // Create token value expected for description.
108     $token_description = Html::escape($this->config('system.site')->get('name')) . '_description';
109     $this->assertText($token_description, 'Token replacement for description is displayed');
110     $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
111     $this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
112
113     // Check that hook_field_widget_form_alter() does not believe this is the
114     // default value form.
115     $this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
116     // Check that hook_field_widget_form_alter() does not believe this is the
117     // default value form.
118     $this->assertNoText('From hook_field_widget_multivalue_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
119
120     // Submit with invalid value (field-level validation).
121     $edit = [
122       "{$field_name}[0][value]" => -1,
123     ];
124     $this->drupalPostForm(NULL, $edit, t('Save'));
125     $this->assertRaw(t('%name does not accept the value -1.', ['%name' => $this->field['label']]), 'Field validation fails with invalid input.');
126     // TODO : check that the correct field is flagged for error.
127
128     // Create an entity
129     $value = mt_rand(1, 127);
130     $edit = [
131       "{$field_name}[0][value]" => $value,
132     ];
133     $this->drupalPostForm(NULL, $edit, t('Save'));
134     preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
135     $id = $match[1];
136     $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
137     $entity = EntityTest::load($id);
138     $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
139
140     // Display edit form.
141     $this->drupalGet('entity_test/manage/' . $id . '/edit');
142     $this->assertFieldByName("{$field_name}[0][value]", $value, 'Widget is displayed with the correct default value');
143     $this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
144
145     // Update the entity.
146     $value = mt_rand(1, 127);
147     $edit = [
148       "{$field_name}[0][value]" => $value,
149     ];
150     $this->drupalPostForm(NULL, $edit, t('Save'));
151     $this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
152     $this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]);
153     $entity = EntityTest::load($id);
154     $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
155
156     // Empty the field.
157     $value = '';
158     $edit = [
159       "{$field_name}[0][value]" => $value,
160     ];
161     $this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
162     $this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
163     $this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]);
164     $entity = EntityTest::load($id);
165     $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field was emptied');
166   }
167
168   /**
169    * Tests field widget default values on entity forms.
170    */
171   public function testFieldFormDefaultValue() {
172     $field_storage = $this->fieldStorageSingle;
173     $field_name = $field_storage['field_name'];
174     $this->field['field_name'] = $field_name;
175     $default = rand(1, 127);
176     $this->field['default_value'] = [['value' => $default]];
177     FieldStorageConfig::create($field_storage)->save();
178     FieldConfig::create($this->field)->save();
179     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
180       ->setComponent($field_name)
181       ->save();
182
183     // Display creation form.
184     $this->drupalGet('entity_test/add');
185     // Test that the default value is displayed correctly.
186     $this->assertFieldByXpath("//input[@name='{$field_name}[0][value]' and @value='$default']");
187
188     // Try to submit an empty value.
189     $edit = [
190       "{$field_name}[0][value]" => '',
191     ];
192     $this->drupalPostForm(NULL, $edit, t('Save'));
193     preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
194     $id = $match[1];
195     $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created.');
196     $entity = EntityTest::load($id);
197     $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field is now empty.');
198   }
199
200   public function testFieldFormSingleRequired() {
201     $field_storage = $this->fieldStorageSingle;
202     $field_name = $field_storage['field_name'];
203     $this->field['field_name'] = $field_name;
204     $this->field['required'] = TRUE;
205     FieldStorageConfig::create($field_storage)->save();
206     FieldConfig::create($this->field)->save();
207     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
208       ->setComponent($field_name)
209       ->save();
210
211     // Submit with missing required value.
212     $edit = [];
213     $this->drupalPostForm('entity_test/add', $edit, t('Save'));
214     $this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]), 'Required field with no value fails validation');
215
216     // Create an entity
217     $value = mt_rand(1, 127);
218     $edit = [
219       "{$field_name}[0][value]" => $value,
220     ];
221     $this->drupalPostForm(NULL, $edit, t('Save'));
222     preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
223     $id = $match[1];
224     $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
225     $entity = EntityTest::load($id);
226     $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
227
228     // Edit with missing required value.
229     $value = '';
230     $edit = [
231       "{$field_name}[0][value]" => $value,
232     ];
233     $this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
234     $this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]), 'Required field with no value fails validation');
235   }
236
237   public function testFieldFormUnlimited() {
238     $field_storage = $this->fieldStorageUnlimited;
239     $field_name = $field_storage['field_name'];
240     $this->field['field_name'] = $field_name;
241     FieldStorageConfig::create($field_storage)->save();
242     FieldConfig::create($this->field)->save();
243     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
244       ->setComponent($field_name)
245       ->save();
246
247     // Display creation form -> 1 widget.
248     $this->drupalGet('entity_test/add');
249     $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
250     $this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
251
252     // Check if aria-describedby attribute is placed on multiple value widgets.
253     $elements = $this->xpath('//table[@id="field-unlimited-values" and @aria-describedby="edit-field-unlimited--description"]');
254     $this->assertTrue(isset($elements[0]), t('aria-describedby attribute is properly placed on multiple value widgets.'));
255
256     // Press 'add more' button -> 2 widgets.
257     $this->drupalPostForm(NULL, [], t('Add another item'));
258     $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
259     $this->assertFieldByName("{$field_name}[1][value]", '', 'New widget is displayed');
260     $this->assertNoField("{$field_name}[2][value]", 'No extraneous widget is displayed');
261     // TODO : check that non-field inputs are preserved ('title'), etc.
262
263     // Yet another time so that we can play with more values -> 3 widgets.
264     $this->drupalPostForm(NULL, [], t('Add another item'));
265
266     // Prepare values and weights.
267     $count = 3;
268     $delta_range = $count - 1;
269     $values = $weights = $pattern = $expected_values = [];
270     $edit = [];
271     for ($delta = 0; $delta <= $delta_range; $delta++) {
272       // Assign unique random values and weights.
273       do {
274         $value = mt_rand(1, 127);
275       } while (in_array($value, $values));
276       do {
277         $weight = mt_rand(-$delta_range, $delta_range);
278       } while (in_array($weight, $weights));
279       $edit["{$field_name}[$delta][value]"] = $value;
280       $edit["{$field_name}[$delta][_weight]"] = $weight;
281       // We'll need three slightly different formats to check the values.
282       $values[$delta] = $value;
283       $weights[$delta] = $weight;
284       $field_values[$weight]['value'] = (string) $value;
285       $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
286     }
287
288     // Press 'add more' button -> 4 widgets
289     $this->drupalPostForm(NULL, $edit, t('Add another item'));
290     for ($delta = 0; $delta <= $delta_range; $delta++) {
291       $this->assertFieldByName("{$field_name}[$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value");
292       $this->assertFieldByName("{$field_name}[$delta][_weight]", $weights[$delta], "Widget $delta has the right weight");
293     }
294     ksort($pattern);
295     $pattern = implode('.*', array_values($pattern));
296     $this->assertPattern("|$pattern|s", 'Widgets are displayed in the correct order');
297     $this->assertFieldByName("{$field_name}[$delta][value]", '', "New widget is displayed");
298     $this->assertFieldByName("{$field_name}[$delta][_weight]", $delta, "New widget has the right weight");
299     $this->assertNoField("{$field_name}[" . ($delta + 1) . '][value]', 'No extraneous widget is displayed');
300
301     // Submit the form and create the entity.
302     $this->drupalPostForm(NULL, $edit, t('Save'));
303     preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
304     $id = $match[1];
305     $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
306     $entity = EntityTest::load($id);
307     ksort($field_values);
308     $field_values = array_values($field_values);
309     $this->assertIdentical($entity->{$field_name}->getValue(), $field_values, 'Field values were saved in the correct order');
310
311     // Display edit form: check that the expected number of widgets is
312     // displayed, with correct values change values, reorder, leave an empty
313     // value in the middle.
314     // Submit: check that the entity is updated with correct values
315     // Re-submit: check that the field can be emptied.
316
317     // Test with several multiple fields in a form
318   }
319
320   /**
321    * Tests the position of the required label.
322    */
323   public function testFieldFormUnlimitedRequired() {
324     $field_name = $this->fieldStorageUnlimited['field_name'];
325     $this->field['field_name'] = $field_name;
326     $this->field['required'] = TRUE;
327     FieldStorageConfig::create($this->fieldStorageUnlimited)->save();
328     FieldConfig::create($this->field)->save();
329     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
330       ->setComponent($field_name)
331       ->save();
332
333     // Display creation form -> 1 widget.
334     $this->drupalGet('entity_test/add');
335     // Check that the Required symbol is present for the multifield label.
336     $element = $this->xpath('//h4[contains(@class, "label") and contains(@class, "js-form-required") and contains(text(), :value)]', [':value' => $this->field['label']]);
337     $this->assertTrue(isset($element[0]), 'Required symbol added field label.');
338     // Check that the label of the field input is visually hidden and contains
339     // the field title and an indication of the delta for a11y.
340     $element = $this->xpath('//label[@for=:for and contains(@class, "visually-hidden") and contains(text(), :value)]', [':for' => 'edit-field-unlimited-0-value', ':value' => $this->field['label'] . ' (value 1)']);
341     $this->assertTrue(isset($element[0]), 'Required symbol not added for field input.');
342   }
343
344   /**
345    * Tests widget handling of multiple required radios.
346    */
347   public function testFieldFormMultivalueWithRequiredRadio() {
348     // Create a multivalue test field.
349     $field_storage = $this->fieldStorageUnlimited;
350     $field_name = $field_storage['field_name'];
351     $this->field['field_name'] = $field_name;
352     FieldStorageConfig::create($field_storage)->save();
353     FieldConfig::create($this->field)->save();
354     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
355       ->setComponent($field_name)
356       ->save();
357
358     // Add a required radio field.
359     FieldStorageConfig::create([
360       'field_name' => 'required_radio_test',
361       'entity_type' => 'entity_test',
362       'type' => 'list_string',
363       'settings' => [
364         'allowed_values' => ['yes' => 'yes', 'no' => 'no'],
365       ],
366     ])->save();
367     $field = [
368       'field_name' => 'required_radio_test',
369       'entity_type' => 'entity_test',
370       'bundle' => 'entity_test',
371       'required' => TRUE,
372     ];
373     FieldConfig::create($field)->save();
374     entity_get_form_display($field['entity_type'], $field['bundle'], 'default')
375       ->setComponent($field['field_name'], [
376         'type' => 'options_buttons',
377       ])
378       ->save();
379
380     // Display creation form.
381     $this->drupalGet('entity_test/add');
382
383     // Press the 'Add more' button.
384     $this->drupalPostForm(NULL, [], t('Add another item'));
385
386     // Verify that no error is thrown by the radio element.
387     $this->assertNoFieldByXpath('//div[contains(@class, "error")]', FALSE, 'No error message is displayed.');
388
389     // Verify that the widget is added.
390     $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
391     $this->assertFieldByName("{$field_name}[1][value]", '', 'New widget is displayed');
392     $this->assertNoField("{$field_name}[2][value]", 'No extraneous widget is displayed');
393   }
394
395   /**
396    * Tests widgets handling multiple values.
397    */
398   public function testFieldFormMultipleWidget() {
399     // Create a field with fixed cardinality, configure the form to use a
400     // "multiple" widget.
401     $field_storage = $this->fieldStorageMultiple;
402     $field_name = $field_storage['field_name'];
403     $this->field['field_name'] = $field_name;
404     FieldStorageConfig::create($field_storage)->save();
405     FieldConfig::create($this->field)->save();
406     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
407       ->setComponent($field_name, [
408         'type' => 'test_field_widget_multiple',
409       ])
410       ->save();
411
412     // Display creation form.
413     $this->drupalGet('entity_test/add');
414     $this->assertFieldByName($field_name, '', 'Widget is displayed.');
415
416     // Create entity with three values.
417     $edit = [
418       $field_name => '1, 2, 3',
419     ];
420     $this->drupalPostForm(NULL, $edit, t('Save'));
421     preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
422     $id = $match[1];
423
424     // Check that the values were saved.
425     $entity_init = EntityTest::load($id);
426     $this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
427
428     // Display the form, check that the values are correctly filled in.
429     $this->drupalGet('entity_test/manage/' . $id . '/edit');
430     $this->assertFieldByName($field_name, '1, 2, 3', 'Widget is displayed.');
431
432     // Submit the form with more values than the field accepts.
433     $edit = [$field_name => '1, 2, 3, 4, 5'];
434     $this->drupalPostForm(NULL, $edit, t('Save'));
435     $this->assertRaw('this field cannot hold more than 4 values', 'Form validation failed.');
436     // Check that the field values were not submitted.
437     $this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
438   }
439
440   /**
441    * Tests fields with no 'edit' access.
442    */
443   public function testFieldFormAccess() {
444     $entity_type = 'entity_test_rev';
445     // Create a "regular" field.
446     $field_storage = $this->fieldStorageSingle;
447     $field_storage['entity_type'] = $entity_type;
448     $field_name = $field_storage['field_name'];
449     $field = $this->field;
450     $field['field_name'] = $field_name;
451     $field['entity_type'] = $entity_type;
452     $field['bundle'] = $entity_type;
453     FieldStorageConfig::create($field_storage)->save();
454     FieldConfig::create($field)->save();
455     entity_get_form_display($entity_type, $entity_type, 'default')
456       ->setComponent($field_name)
457       ->save();
458
459     // Create a field with no edit access. See
460     // field_test_entity_field_access().
461     $field_storage_no_access = [
462       'field_name' => 'field_no_edit_access',
463       'entity_type' => $entity_type,
464       'type' => 'test_field',
465     ];
466     $field_name_no_access = $field_storage_no_access['field_name'];
467     $field_no_access = [
468       'field_name' => $field_name_no_access,
469       'entity_type' => $entity_type,
470       'bundle' => $entity_type,
471       'default_value' => [0 => ['value' => 99]],
472     ];
473     FieldStorageConfig::create($field_storage_no_access)->save();
474     FieldConfig::create($field_no_access)->save();
475     entity_get_form_display($field_no_access['entity_type'], $field_no_access['bundle'], 'default')
476       ->setComponent($field_name_no_access)
477       ->save();
478
479     // Test that the form structure includes full information for each delta
480     // apart from #access.
481     $entity = $this->container->get('entity_type.manager')
482       ->getStorage($entity_type)
483       ->create(['id' => 0, 'revision_id' => 0]);
484
485     $display = entity_get_form_display($entity_type, $entity_type, 'default');
486     $form = [];
487     $form_state = new FormState();
488     $display->buildForm($entity, $form, $form_state);
489
490     $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');
491
492     // Display creation form.
493     $this->drupalGet($entity_type . '/add');
494     $this->assertNoFieldByName("{$field_name_no_access}[0][value]", '', 'Widget is not displayed if field access is denied.');
495
496     // Create entity.
497     $edit = [
498       "{$field_name}[0][value]" => 1,
499     ];
500     $this->drupalPostForm(NULL, $edit, t('Save'));
501     preg_match("|$entity_type/manage/(\d+)|", $this->getUrl(), $match);
502     $id = $match[1];
503
504     // Check that the default value was saved.
505     $storage = $this->container->get('entity_type.manager')
506       ->getStorage($entity_type);
507     $entity = $storage->load($id);
508     $this->assertEqual($entity->$field_name_no_access->value, 99, 'Default value was saved for the field with no edit access.');
509     $this->assertEqual($entity->$field_name->value, 1, 'Entered value vas saved for the field with edit access.');
510
511     // Create a new revision.
512     $edit = [
513       "{$field_name}[0][value]" => 2,
514       'revision' => TRUE,
515     ];
516     $this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
517
518     // Check that the new revision has the expected values.
519     $storage->resetCache([$id]);
520     $entity = $storage->load($id);
521     $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
522     $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
523
524     // Check that the revision is also saved in the revisions table.
525     $entity = $this->container->get('entity_type.manager')
526       ->getStorage($entity_type)
527       ->loadRevision($entity->getRevisionId());
528     $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
529     $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
530   }
531
532   /**
533    * Tests hiding a field in a form.
534    */
535   public function testHiddenField() {
536     $entity_type = 'entity_test_rev';
537     $field_storage = $this->fieldStorageSingle;
538     $field_storage['entity_type'] = $entity_type;
539     $field_name = $field_storage['field_name'];
540     $this->field['field_name'] = $field_name;
541     $this->field['default_value'] = [0 => ['value' => 99]];
542     $this->field['entity_type'] = $entity_type;
543     $this->field['bundle'] = $entity_type;
544     FieldStorageConfig::create($field_storage)->save();
545     $this->field = FieldConfig::create($this->field);
546     $this->field->save();
547     // We explicitly do not assign a widget in a form display, so the field
548     // stays hidden in forms.
549
550     // Display the entity creation form.
551     $this->drupalGet($entity_type . '/add');
552
553     // Create an entity and test that the default value is assigned correctly to
554     // the field that uses the hidden widget.
555     $this->assertNoField("{$field_name}[0][value]", 'The field does not appear in the form');
556     $this->drupalPostForm(NULL, [], t('Save'));
557     preg_match('|' . $entity_type . '/manage/(\d+)|', $this->getUrl(), $match);
558     $id = $match[1];
559     $this->assertText(t('entity_test_rev @id has been created.', ['@id' => $id]), 'Entity was created');
560     $storage = $this->container->get('entity_type.manager')
561       ->getStorage($entity_type);
562
563     $entity = $storage->load($id);
564     $this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
565
566     // Update the field to remove the default value, and switch to the default
567     // widget.
568     $this->field->setDefaultValue([]);
569     $this->field->save();
570     entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
571       ->setComponent($this->field->getName(), [
572         'type' => 'test_field_widget',
573       ])
574       ->save();
575
576     // Display edit form.
577     $this->drupalGet($entity_type . '/manage/' . $id . '/edit');
578     $this->assertFieldByName("{$field_name}[0][value]", 99, 'Widget is displayed with the correct default value');
579
580     // Update the entity.
581     $value = mt_rand(1, 127);
582     $edit = ["{$field_name}[0][value]" => $value];
583     $this->drupalPostForm(NULL, $edit, t('Save'));
584     $this->assertText(t('entity_test_rev @id has been updated.', ['@id' => $id]), 'Entity was updated');
585     $storage->resetCache([$id]);
586     $entity = $storage->load($id);
587     $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
588
589     // Set the field back to hidden.
590     entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
591       ->removeComponent($this->field->getName())
592       ->save();
593
594     // Create a new revision.
595     $edit = ['revision' => TRUE];
596     $this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
597
598     // Check that the expected value has been carried over to the new revision.
599     $storage->resetCache([$id]);
600     $entity = $storage->load($id);
601     $this->assertEqual($entity->{$field_name}->value, $value, 'New revision has the expected value for the field with the Hidden widget');
602   }
603
604   /**
605    * Tests the form display of the label for multi-value fields.
606    */
607   public function testLabelOnMultiValueFields() {
608     $user = $this->drupalCreateUser(['administer entity_test content']);
609     $this->drupalLogin($user);
610
611     FieldStorageConfig::create([
612       'entity_type' => 'entity_test_base_field_display',
613       'field_name' => 'foo',
614       'type' => 'text',
615       'cardinality' => FieldStorageConfig::CARDINALITY_UNLIMITED,
616     ])->save();
617     FieldConfig::create([
618       'entity_type' => 'entity_test_base_field_display',
619       'bundle' => 'bar',
620       'field_name' => 'foo',
621       // Set a dangerous label to test XSS filtering.
622       'label' => "<script>alert('a configurable field');</script>",
623     ])->save();
624     EntityFormDisplay::create([
625       'targetEntityType' => 'entity_test_base_field_display',
626       'bundle' => 'bar',
627       'mode' => 'default',
628     ])->setComponent('foo', ['type' => 'text_textfield'])->enable()->save();
629
630     $entity = EntityTestBaseFieldDisplay::create(['type' => 'bar']);
631     $entity->save();
632
633     $this->drupalGet('entity_test_base_field_display/manage/' . $entity->id());
634     $this->assertResponse(200);
635     $this->assertText('A field with multiple values');
636     // Test if labels were XSS filtered.
637     $this->assertEscaped("<script>alert('a configurable field');</script>");
638   }
639
640   /**
641    * Tests hook_field_widget_multivalue_form_alter().
642    */
643   public function testFieldFormMultipleWidgetAlter() {
644     $this->widgetAlterTest('hook_field_widget_multivalue_form_alter', 'test_field_widget_multiple');
645   }
646
647   /**
648    * Tests hook_field_widget_multivalue_form_alter() with single value elements.
649    */
650   public function testFieldFormMultipleWidgetAlterSingleValues() {
651     $this->widgetAlterTest('hook_field_widget_multivalue_form_alter', 'test_field_widget_multiple_single_value');
652   }
653
654   /**
655    * Tests hook_field_widget_multivalue_WIDGET_TYPE_form_alter().
656    */
657   public function testFieldFormMultipleWidgetTypeAlter() {
658     $this->widgetAlterTest('hook_field_widget_multivalue_WIDGET_TYPE_form_alter', 'test_field_widget_multiple');
659   }
660
661   /**
662    * Tests hook_field_widget_multivalue_WIDGET_TYPE_form_alter() with single value elements.
663    */
664   public function testFieldFormMultipleWidgetTypeAlterSingleValues() {
665     $this->widgetAlterTest('hook_field_widget_multivalue_WIDGET_TYPE_form_alter', 'test_field_widget_multiple_single_value');
666   }
667
668   /**
669    * Tests widget alter hooks for a given hook name.
670    */
671   protected function widgetAlterTest($hook, $widget) {
672     // Create a field with fixed cardinality, configure the form to use a
673     // "multiple" widget.
674     $field_storage = $this->fieldStorageMultiple;
675     $field_name = $field_storage['field_name'];
676     $this->field['field_name'] = $field_name;
677     FieldStorageConfig::create($field_storage)->save();
678     FieldConfig::create($this->field)->save();
679
680     // Set a flag in state so that the hook implementations will run.
681     \Drupal::state()->set("field_test.widget_alter_test", [
682       'hook' => $hook,
683       'field_name' => $field_name,
684       'widget' => $widget,
685     ]);
686     entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
687       ->setComponent($field_name, [
688         'type' => $widget,
689       ])
690       ->save();
691
692     $this->drupalGet('entity_test/add');
693     $this->assertUniqueText("From $hook(): prefix on $field_name parent element.");
694     if ($widget === 'test_field_widget_multiple_single_value') {
695       $suffix_text = "From $hook(): suffix on $field_name child element.";
696       $this->assertEqual($field_storage['cardinality'], substr_count($this->getTextContent(), $suffix_text), "'$suffix_text' was found {$field_storage['cardinality']} times  using widget $widget");
697     }
698   }
699
700 }