FormTest.php 29.4 KB
Newer Older
1 2
<?php

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 12
use Drupal\field\Entity\FieldConfig;
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 23

  /**
   * Modules to enable.
   *
24 25
   * Locale is installed so that TranslatableMarkup actually does something.
   *
26 27
   * @var array
   */
28 29 30 31 32 33 34
  protected static $modules = [
    'node',
    'field_test',
    'options',
    'entity_test',
    'locale',
  ];
35

36 37 38 39 40
  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

41 42 43 44 45
  /**
   * An array of values defining a field single.
   *
   * @var array
   */
46
  protected $fieldStorageSingle;
47 48 49 50 51 52

  /**
   * An array of values defining a field multiple.
   *
   * @var array
   */
53
  protected $fieldStorageMultiple;
54 55 56 57 58 59

  /**
   * An array of values defining a field with unlimited cardinality.
   *
   * @var array
   */
60
  protected $fieldStorageUnlimited;
61 62

  /**
63
   * An array of values defining a field.
64 65 66
   *
   * @var array
   */
67
  protected $field;
68

69
  protected function setUp(): void {
70
    parent::setUp();
71

72 73 74 75
    $web_user = $this->drupalCreateUser([
      'view test entity',
      'administer entity_test content',
    ]);
76 77
    $this->drupalLogin($web_user);

78
    $this->fieldStorageSingle = [
79
      'field_name' => 'field_single',
80 81
      'entity_type' => 'entity_test',
      'type' => 'test_field',
82 83
    ];
    $this->fieldStorageMultiple = [
84
      'field_name' => 'field_multiple',
85 86 87
      'entity_type' => 'entity_test',
      'type' => 'test_field',
      'cardinality' => 4,
88 89
    ];
    $this->fieldStorageUnlimited = [
90
      'field_name' => 'field_unlimited',
91 92
      'entity_type' => 'entity_test',
      'type' => 'test_field',
93
      'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
94
    ];
95

96
    $this->field = [
97 98
      'entity_type' => 'entity_test',
      'bundle' => 'entity_test',
99
      'label' => $this->randomMachineName() . '_label',
100
      'description' => '[site:name]_description',
101
      'weight' => mt_rand(0, 127),
102
      'settings' => [
103
        'test_field_setting' => $this->randomMachineName(),
104 105
      ],
    ];
106 107
  }

108
  public function testFieldFormSingle() {
109
    $field_storage = $this->fieldStorageSingle;
110
    $field_name = $field_storage['field_name'];
111
    $this->field['field_name'] = $field_name;
112
    FieldStorageConfig::create($field_storage)->save();
113
    FieldConfig::create($this->field)->save();
114 115
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
116
      ->setComponent($field_name)
117
      ->save();
118 119

    // Display creation form.
120
    $this->drupalGet('entity_test/add');
121 122

    // Create token value expected for description.
123
    $token_description = Html::escape($this->config('system.site')->get('name')) . '_description';
124
    $this->assertText($token_description, 'Token replacement for description is displayed');
125
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", '');
126
    // Verify that no extraneous widget is displayed.
127
    $this->assertSession()->fieldNotExists("{$field_name}[1][value]");
128

129 130
    // Check that hook_field_widget_form_alter() does not believe this is the
    // default value form.
131
    $this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
132 133 134
    // Check that hook_field_widget_form_alter() does not believe this is the
    // default value form.
    $this->assertNoText('From hook_field_widget_multivalue_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
135

136
    // Submit with invalid value (field-level validation).
137
    $edit = [
138
      "{$field_name}[0][value]" => -1,
139
    ];
140
    $this->drupalPostForm(NULL, $edit, t('Save'));
141
    $this->assertRaw(t('%name does not accept the value -1.', ['%name' => $this->field['label']]));
142 143 144 145
    // TODO : check that the correct field is flagged for error.

    // Create an entity
    $value = mt_rand(1, 127);
146
    $edit = [
147
      "{$field_name}[0][value]" => $value,
148
    ];
149
    $this->drupalPostForm(NULL, $edit, t('Save'));
150
    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
151
    $id = $match[1];
152
    $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
153
    $entity = EntityTest::load($id);
154
    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
155 156

    // Display edit form.
157
    $this->drupalGet('entity_test/manage/' . $id . '/edit');
158 159
    // Check that the widget is displayed with the correct default value.
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", $value);
160
    // Verify that no extraneous widget is displayed.
161
    $this->assertSession()->fieldNotExists("{$field_name}[1][value]");
162 163 164

    // Update the entity.
    $value = mt_rand(1, 127);
165
    $edit = [
166
      "{$field_name}[0][value]" => $value,
167
    ];
168
    $this->drupalPostForm(NULL, $edit, t('Save'));
169
    $this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
170
    $this->container->get('entity_type.manager')->getStorage('entity_test')->resetCache([$id]);
171
    $entity = EntityTest::load($id);
172
    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
173 174 175

    // Empty the field.
    $value = '';
176
    $edit = [
177
      "{$field_name}[0][value]" => $value,
178
    ];
179
    $this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
180
    $this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
181
    $this->container->get('entity_type.manager')->getStorage('entity_test')->resetCache([$id]);
182
    $entity = EntityTest::load($id);
183
    $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field was emptied');
184
  }
185

186 187 188
  /**
   * Tests field widget default values on entity forms.
   */
189
  public function testFieldFormDefaultValue() {
190
    $field_storage = $this->fieldStorageSingle;
191
    $field_name = $field_storage['field_name'];
192
    $this->field['field_name'] = $field_name;
193
    $default = rand(1, 127);
194
    $this->field['default_value'] = [['value' => $default]];
195
    FieldStorageConfig::create($field_storage)->save();
196
    FieldConfig::create($this->field)->save();
197 198
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
199
      ->setComponent($field_name)
200
      ->save();
201 202

    // Display creation form.
203
    $this->drupalGet('entity_test/add');
204
    // Test that the default value is displayed correctly.
205
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", $default);
206 207

    // Try to submit an empty value.
208
    $edit = [
209
      "{$field_name}[0][value]" => '',
210
    ];
211
    $this->drupalPostForm(NULL, $edit, t('Save'));
212
    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
213
    $id = $match[1];
214
    $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created.');
215
    $entity = EntityTest::load($id);
216
    $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field is now empty.');
217 218
  }

219
  public function testFieldFormSingleRequired() {
220
    $field_storage = $this->fieldStorageSingle;
221
    $field_name = $field_storage['field_name'];
222 223
    $this->field['field_name'] = $field_name;
    $this->field['required'] = TRUE;
224
    FieldStorageConfig::create($field_storage)->save();
225
    FieldConfig::create($this->field)->save();
226 227
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
228
      ->setComponent($field_name)
229
      ->save();
230 231

    // Submit with missing required value.
232
    $edit = [];
233
    $this->drupalPostForm('entity_test/add', $edit, t('Save'));
234
    $this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]));
235 236 237

    // Create an entity
    $value = mt_rand(1, 127);
238
    $edit = [
239
      "{$field_name}[0][value]" => $value,
240
    ];
241
    $this->drupalPostForm(NULL, $edit, t('Save'));
242
    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
243
    $id = $match[1];
244
    $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
245
    $entity = EntityTest::load($id);
246
    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
247 248 249

    // Edit with missing required value.
    $value = '';
250
    $edit = [
251
      "{$field_name}[0][value]" => $value,
252
    ];
253
    $this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
254
    $this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]));
255 256
  }

257
  public function testFieldFormUnlimited() {
258
    $field_storage = $this->fieldStorageUnlimited;
259
    $field_name = $field_storage['field_name'];
260
    $this->field['field_name'] = $field_name;
261
    FieldStorageConfig::create($field_storage)->save();
262
    FieldConfig::create($this->field)->save();
263 264
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
265
      ->setComponent($field_name)
266
      ->save();
267 268

    // Display creation form -> 1 widget.
269
    $this->drupalGet('entity_test/add');
270
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", '');
271
    // Verify that no extraneous widget is displayed.
272
    $this->assertSession()->fieldNotExists("{$field_name}[1][value]");
273

274 275
    // Check if aria-describedby attribute is placed on multiple value widgets.
    $elements = $this->xpath('//table[@id="field-unlimited-values" and @aria-describedby="edit-field-unlimited--description"]');
276
    $this->assertTrue(isset($elements[0]), 'aria-describedby attribute is properly placed on multiple value widgets.');
277

278
    // Press 'add more' button -> 2 widgets.
279
    $this->drupalPostForm(NULL, [], t('Add another item'));
280 281
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", '');
    $this->assertSession()->fieldValueEquals("{$field_name}[1][value]", '');
282
    // Verify that no extraneous widget is displayed.
283
    $this->assertSession()->fieldNotExists("{$field_name}[2][value]");
284
    // TODO : check that non-field inputs are preserved ('title'), etc.
285 286

    // Yet another time so that we can play with more values -> 3 widgets.
287
    $this->drupalPostForm(NULL, [], t('Add another item'));
288 289 290 291

    // Prepare values and weights.
    $count = 3;
    $delta_range = $count - 1;
292 293
    $values = $weights = $pattern = $expected_values = [];
    $edit = [];
294 295 296 297 298 299 300 301
    for ($delta = 0; $delta <= $delta_range; $delta++) {
      // Assign unique random values and weights.
      do {
        $value = mt_rand(1, 127);
      } while (in_array($value, $values));
      do {
        $weight = mt_rand(-$delta_range, $delta_range);
      } while (in_array($weight, $weights));
302 303
      $edit["{$field_name}[$delta][value]"] = $value;
      $edit["{$field_name}[$delta][_weight]"] = $weight;
304 305 306 307 308 309 310 311
      // We'll need three slightly different formats to check the values.
      $values[$delta] = $value;
      $weights[$delta] = $weight;
      $field_values[$weight]['value'] = (string) $value;
      $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
    }

    // Press 'add more' button -> 4 widgets
312
    $this->drupalPostForm(NULL, $edit, t('Add another item'));
313
    for ($delta = 0; $delta <= $delta_range; $delta++) {
314 315
      $this->assertSession()->fieldValueEquals("{$field_name}[$delta][value]", $values[$delta]);
      $this->assertSession()->fieldValueEquals("{$field_name}[$delta][_weight]", $weights[$delta]);
316 317 318
    }
    ksort($pattern);
    $pattern = implode('.*', array_values($pattern));
319
    // Verify that the widgets are displayed in the correct order.
320
    $this->assertSession()->responseMatches("|$pattern|s");
321 322
    $this->assertSession()->fieldValueEquals("{$field_name}[$delta][value]", '');
    $this->assertSession()->fieldValueEquals("{$field_name}[$delta][_weight]", $delta);
323
    // Verify that no extraneous widget is displayed.
324
    $this->assertSession()->fieldNotExists("{$field_name}[" . ($delta + 1) . '][value]');
325 326

    // Submit the form and create the entity.
327
    $this->drupalPostForm(NULL, $edit, t('Save'));
328
    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
329
    $id = $match[1];
330
    $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
331
    $entity = EntityTest::load($id);
332 333
    ksort($field_values);
    $field_values = array_values($field_values);
334
    $this->assertIdentical($entity->{$field_name}->getValue(), $field_values, 'Field values were saved in the correct order');
335 336 337 338 339 340 341 342 343 344

    // Display edit form: check that the expected number of widgets is
    // displayed, with correct values change values, reorder, leave an empty
    // value in the middle.
    // Submit: check that the entity is updated with correct values
    // Re-submit: check that the field can be emptied.

    // Test with several multiple fields in a form
  }

345 346 347 348 349 350 351 352 353
  /**
   * Tests the position of the required label.
   */
  public function testFieldFormUnlimitedRequired() {
    $field_name = $this->fieldStorageUnlimited['field_name'];
    $this->field['field_name'] = $field_name;
    $this->field['required'] = TRUE;
    FieldStorageConfig::create($this->fieldStorageUnlimited)->save();
    FieldConfig::create($this->field)->save();
354 355
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
356 357 358 359 360 361
      ->setComponent($field_name)
      ->save();

    // Display creation form -> 1 widget.
    $this->drupalGet('entity_test/add');
    // Check that the Required symbol is present for the multifield label.
362
    $element = $this->xpath('//h4[contains(@class, "label") and contains(@class, "js-form-required") and contains(text(), :value)]', [':value' => $this->field['label']]);
363
    $this->assertTrue(isset($element[0]), 'Required symbol added field label.');
364 365
    // Check that the label of the field input is visually hidden and contains
    // the field title and an indication of the delta for a11y.
366
    $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)']);
367
    $this->assertTrue(isset($element[0]), 'Required symbol not added for field input.');
368 369
  }

370 371 372
  /**
   * Tests widget handling of multiple required radios.
   */
373
  public function testFieldFormMultivalueWithRequiredRadio() {
374 375 376
    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
    $display_repository = \Drupal::service('entity_display.repository');

377
    // Create a multivalue test field.
378
    $field_storage = $this->fieldStorageUnlimited;
379
    $field_name = $field_storage['field_name'];
380
    $this->field['field_name'] = $field_name;
381
    FieldStorageConfig::create($field_storage)->save();
382
    FieldConfig::create($this->field)->save();
383
    $display_repository->getFormDisplay($this->field['entity_type'], $this->field['bundle'])
384
      ->setComponent($field_name)
385
      ->save();
386 387

    // Add a required radio field.
388
    FieldStorageConfig::create([
389
      'field_name' => 'required_radio_test',
390
      'entity_type' => 'entity_test',
391
      'type' => 'list_string',
392 393 394 395 396
      'settings' => [
        'allowed_values' => ['yes' => 'yes', 'no' => 'no'],
      ],
    ])->save();
    $field = [
397
      'field_name' => 'required_radio_test',
398 399
      'entity_type' => 'entity_test',
      'bundle' => 'entity_test',
400
      'required' => TRUE,
401
    ];
402
    FieldConfig::create($field)->save();
403
    $display_repository->getFormDisplay($field['entity_type'], $field['bundle'])
404
      ->setComponent($field['field_name'], [
405
        'type' => 'options_buttons',
406
      ])
407
      ->save();
408 409

    // Display creation form.
410
    $this->drupalGet('entity_test/add');
411 412

    // Press the 'Add more' button.
413
    $this->drupalPostForm(NULL, [], t('Add another item'));
414 415

    // Verify that no error is thrown by the radio element.
416
    $this->assertSession()->elementNotExists('xpath', '//div[contains(@class, "error")]');
417 418

    // Verify that the widget is added.
419 420
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", '');
    $this->assertSession()->fieldValueEquals("{$field_name}[1][value]", '');
421
    // Verify that no extraneous widget is displayed.
422
    $this->assertSession()->fieldNotExists("{$field_name}[2][value]");
423 424 425 426 427
  }

  /**
   * Tests widgets handling multiple values.
   */
428
  public function testFieldFormMultipleWidget() {
429 430
    // Create a field with fixed cardinality, configure the form to use a
    // "multiple" widget.
431
    $field_storage = $this->fieldStorageMultiple;
432
    $field_name = $field_storage['field_name'];
433
    $this->field['field_name'] = $field_name;
434
    FieldStorageConfig::create($field_storage)->save();
435
    FieldConfig::create($this->field)->save();
436
    $form = \Drupal::service('entity_display.repository')->getFormDisplay($this->field['entity_type'], $this->field['bundle'], 'default')
437
      ->setComponent($field_name, [
438
        'type' => 'test_field_widget_multiple',
439 440 441
      ]);
    $form->save();
    $session = $this->assertSession();
442 443

    // Display creation form.
444
    $this->drupalGet('entity_test/add');
445
    $this->assertSession()->fieldValueEquals($field_name, '');
446 447

    // Create entity with three values.
448
    $edit = [
449
      $field_name => '1, 2, 3',
450
    ];
451
    $this->drupalPostForm(NULL, $edit, t('Save'));
452
    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
453 454 455
    $id = $match[1];

    // Check that the values were saved.
456
    $entity_init = EntityTest::load($id);
457
    $this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
458 459

    // Display the form, check that the values are correctly filled in.
460
    $this->drupalGet('entity_test/manage/' . $id . '/edit');
461
    $this->assertSession()->fieldValueEquals($field_name, '1, 2, 3');
462 463

    // Submit the form with more values than the field accepts.
464
    $edit = [$field_name => '1, 2, 3, 4, 5'];
465
    $this->drupalPostForm(NULL, $edit, t('Save'));
466
    $this->assertRaw('this field cannot hold more than 4 values');
467
    // Check that the field values were not submitted.
468
    $this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
469 470 471 472 473 474 475 476 477 478

    // Check that Attributes are rendered on the multivalue container if it is
    // a multiple widget form.
    $form->setComponent($field_name, [
      'type' => 'entity_reference_autocomplete',
    ])
      ->save();
    $this->drupalGet('entity_test/manage/' . $id . '/edit');
    $name = str_replace('_', '-', $field_name);
    $session->responseContains('data-drupal-selector="edit-' . $name . '"');
479 480 481 482 483
  }

  /**
   * Tests fields with no 'edit' access.
   */
484
  public function testFieldFormAccess() {
485 486 487
    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
    $display_repository = \Drupal::service('entity_display.repository');

488
    $entity_type = 'entity_test_rev';
489
    // Create a "regular" field.
490 491
    $field_storage = $this->fieldStorageSingle;
    $field_storage['entity_type'] = $entity_type;
492
    $field_name = $field_storage['field_name'];
493 494 495 496
    $field = $this->field;
    $field['field_name'] = $field_name;
    $field['entity_type'] = $entity_type;
    $field['bundle'] = $entity_type;
497
    FieldStorageConfig::create($field_storage)->save();
498
    FieldConfig::create($field)->save();
499
    $display_repository->getFormDisplay($entity_type, $entity_type)
500 501
      ->setComponent($field_name)
      ->save();
502

503 504
    // Create a field with no edit access. See
    // field_test_entity_field_access().
505
    $field_storage_no_access = [
506
      'field_name' => 'field_no_edit_access',
507
      'entity_type' => $entity_type,
508
      'type' => 'test_field',
509
    ];
510
    $field_name_no_access = $field_storage_no_access['field_name'];
511
    $field_no_access = [
512
      'field_name' => $field_name_no_access,
513 514
      'entity_type' => $entity_type,
      'bundle' => $entity_type,
515 516
      'default_value' => [0 => ['value' => 99]],
    ];
517
    FieldStorageConfig::create($field_storage_no_access)->save();
518
    FieldConfig::create($field_no_access)->save();
519
    $display_repository->getFormDisplay($field_no_access['entity_type'], $field_no_access['bundle'])
520 521
      ->setComponent($field_name_no_access)
      ->save();
522 523 524

    // Test that the form structure includes full information for each delta
    // apart from #access.
525 526
    $entity = $this->container->get('entity_type.manager')
      ->getStorage($entity_type)
527
      ->create(['id' => 0, 'revision_id' => 0]);
528

529
    $display = $display_repository->getFormDisplay($entity_type, $entity_type);
530
    $form = [];
531
    $form_state = new FormState();
532
    $display->buildForm($entity, $form, $form_state);
533 534 535 536

    $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');

    // Display creation form.
537
    $this->drupalGet($entity_type . '/add');
538 539
    // Check that the widget is not displayed if field access is denied.
    $this->assertSession()->fieldNotExists("{$field_name_no_access}[0][value]");
540 541

    // Create entity.
542
    $edit = [
543
      "{$field_name}[0][value]" => 1,
544
    ];
545
    $this->drupalPostForm(NULL, $edit, t('Save'));
546
    preg_match("|$entity_type/manage/(\d+)|", $this->getUrl(), $match);
547 548 549
    $id = $match[1];

    // Check that the default value was saved.
550 551 552
    $storage = $this->container->get('entity_type.manager')
      ->getStorage($entity_type);
    $entity = $storage->load($id);
553 554
    $this->assertEqual($entity->$field_name_no_access->value, 99, 'Default value was saved for the field with no edit access.');
    $this->assertEqual($entity->$field_name->value, 1, 'Entered value vas saved for the field with edit access.');
555 556

    // Create a new revision.
557
    $edit = [
558
      "{$field_name}[0][value]" => 2,
559
      'revision' => TRUE,
560
    ];
561
    $this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
562 563

    // Check that the new revision has the expected values.
564 565
    $storage->resetCache([$id]);
    $entity = $storage->load($id);
566 567
    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
568 569

    // Check that the revision is also saved in the revisions table.
570 571 572
    $entity = $this->container->get('entity_type.manager')
      ->getStorage($entity_type)
      ->loadRevision($entity->getRevisionId());
573 574
    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
575 576
  }

577
  /**
578
   * Tests hiding a field in a form.
579
   */
580
  public function testHiddenField() {
581
    $entity_type = 'entity_test_rev';
582 583
    $field_storage = $this->fieldStorageSingle;
    $field_storage['entity_type'] = $entity_type;
584
    $field_name = $field_storage['field_name'];
585
    $this->field['field_name'] = $field_name;
586
    $this->field['default_value'] = [0 => ['value' => 99]];
587 588
    $this->field['entity_type'] = $entity_type;
    $this->field['bundle'] = $entity_type;
589
    FieldStorageConfig::create($field_storage)->save();
590
    $this->field = FieldConfig::create($this->field);
591
    $this->field->save();
592 593
    // We explicitly do not assign a widget in a form display, so the field
    // stays hidden in forms.
594 595

    // Display the entity creation form.
596
    $this->drupalGet($entity_type . '/add');
597 598 599

    // Create an entity and test that the default value is assigned correctly to
    // the field that uses the hidden widget.
600
    $this->assertSession()->fieldNotExists("{$field_name}[0][value]");
601
    $this->drupalPostForm(NULL, [], t('Save'));
602
    preg_match('|' . $entity_type . '/manage/(\d+)|', $this->getUrl(), $match);
603
    $id = $match[1];
604
    $this->assertText(t('entity_test_rev @id has been created.', ['@id' => $id]), 'Entity was created');
605 606 607 608
    $storage = $this->container->get('entity_type.manager')
      ->getStorage($entity_type);

    $entity = $storage->load($id);
609
    $this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
610

611 612
    // Update the field to remove the default value, and switch to the default
    // widget.
613
    $this->field->setDefaultValue([]);
614
    $this->field->save();
615 616
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($entity_type, $this->field->getTargetBundle())
617
      ->setComponent($this->field->getName(), [
618
        'type' => 'test_field_widget',
619
      ])
620
      ->save();
621 622

    // Display edit form.
623
    $this->drupalGet($entity_type . '/manage/' . $id . '/edit');
624
    $this->assertSession()->fieldValueEquals("{$field_name}[0][value]", 99);
625 626 627

    // Update the entity.
    $value = mt_rand(1, 127);
628
    $edit = ["{$field_name}[0][value]" => $value];
629
    $this->drupalPostForm(NULL, $edit, t('Save'));
630
    $this->assertText(t('entity_test_rev @id has been updated.', ['@id' => $id]), 'Entity was updated');
631 632
    $storage->resetCache([$id]);
    $entity = $storage->load($id);
633
    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
634

635
    // Set the field back to hidden.
636 637
    \Drupal::service('entity_display.repository')
      ->getFormDisplay($entity_type, $this->field->getTargetBundle())
638
      ->removeComponent($this->field->getName())
639
      ->save();
640 641

    // Create a new revision.
642
    $edit = ['revision' => TRUE];
643
    $this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
644 645

    // Check that the expected value has been carried over to the new revision.
646
    $storage->resetCache([$id]);
647
    $entity = $storage->load($id);
648
    $this->assertEqual($entity->{$field_name}->value, $value, 'New revision has the expected value for the field with the Hidden widget');
649
  }
650

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
  /**
   * Tests the form display of the label for multi-value fields.
   */
  public function testLabelOnMultiValueFields() {
    $user = $this->drupalCreateUser(['administer entity_test content']);
    $this->drupalLogin($user);

    FieldStorageConfig::create([
      'entity_type' => 'entity_test_base_field_display',
      'field_name' => 'foo',
      'type' => 'text',
      'cardinality' => FieldStorageConfig::CARDINALITY_UNLIMITED,
    ])->save();
    FieldConfig::create([
      'entity_type' => 'entity_test_base_field_display',
      'bundle' => 'bar',
      'field_name' => 'foo',
      // Set a dangerous label to test XSS filtering.
      'label' => "<script>alert('a configurable field');</script>",
    ])->save();
    EntityFormDisplay::create([
      'targetEntityType' => 'entity_test_base_field_display',
      'bundle' => 'bar',
      'mode' => 'default',
    ])->setComponent('foo', ['type' => 'text_textfield'])->enable()->save();

    $entity = EntityTestBaseFieldDisplay::create(['type' => 'bar']);
    $entity->save();

    $this->drupalGet('entity_test_base_field_display/manage/' . $entity->id());
681
    $this->assertSession()->statusCodeEquals(200);
682 683
    $this->assertText('A field with multiple values');
    // Test if labels were XSS filtered.
684
    $this->assertSession()->assertEscaped("<script>alert('a configurable field');</script>");
685 686
  }

catch's avatar