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