OptionsWidgetsTest.php 21.7 KB
Newer Older
1 2
<?php

3
namespace Drupal\Tests\options\Functional;
4

5
use Drupal\entity_test\Entity\EntityTest;
6
use Drupal\field\Entity\FieldConfig;
7
use Drupal\field\Entity\FieldStorageConfig;
8
use Drupal\Tests\field\Functional\FieldTestBase;
9 10

/**
11 12 13
 * Tests the Options widgets.
 *
 * @group options
14 15
 */
class OptionsWidgetsTest extends FieldTestBase {
16 17 18 19 20 21

  /**
   * Modules to enable.
   *
   * @var array
   */
22 23 24 25 26 27 28 29
  protected static $modules = [
    'node',
    'options',
    'entity_test',
    'options_test',
    'taxonomy',
    'field_ui',
  ];
30

31 32 33 34 35
  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

36
  /**
37
   * A field storage with cardinality 1 to use in this test class.
38
   *
39
   * @var \Drupal\field\Entity\FieldStorageConfig
40
   */
41
  protected $card1;
42 43

  /**
44
   * A field storage with cardinality 2 to use in this test class.
45
   *
46
   * @var \Drupal\field\Entity\FieldStorageConfig
47
   */
48
  protected $card2;
49

50 51 52 53 54 55 56
  /**
   * A field storage with float values to use in this test class.
   *
   * @var \Drupal\field\Entity\FieldStorageConfig
   */
  protected $float;

57
  protected function setUp(): void {
58
    parent::setUp();
59

60
    // Field storage with cardinality 1.
61
    $this->card1 = FieldStorageConfig::create([
62
      'field_name' => 'card_1',
63
      'entity_type' => 'entity_test',
64
      'type' => 'list_integer',
65
      'cardinality' => 1,
66 67
      'settings' => [
        'allowed_values' => [
68 69 70 71 72 73 74
          // Make sure that 0 works as an option.
          0 => 'Zero',
          1 => 'One',
          // Make sure that option text is properly sanitized.
          2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
          // Make sure that HTML entities in option text are not double-encoded.
          3 => 'Some HTML encoded markup with &lt; &amp; &gt;',
75 76 77 78
        ],
      ],
    ]);
    $this->card1->save();
79

80
    // Field storage with cardinality 2.
81
    $this->card2 = FieldStorageConfig::create([
82
      'field_name' => 'card_2',
83
      'entity_type' => 'entity_test',
84
      'type' => 'list_integer',
85
      'cardinality' => 2,
86 87
      'settings' => [
        'allowed_values' => [
88 89 90 91 92
          // Make sure that 0 works as an option.
          0 => 'Zero',
          1 => 'One',
          // Make sure that option text is properly sanitized.
          2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
93 94 95 96
        ],
      ],
    ]);
    $this->card2->save();
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    // Field storage with list of float values.
    $this->float = FieldStorageConfig::create([
      'field_name' => 'float',
      'entity_type' => 'entity_test',
      'type' => 'list_float',
      'cardinality' => 1,
      'settings' => [
        'allowed_values' => [
          '0.0' => '0.0',
          '1.5' => '1.5',
          '2.0' => '2.0',
        ],
      ],
    ]);
    $this->float->save();

114
    // Create a web user.
115 116 117 118
    $this->drupalLogin($this->drupalCreateUser([
      'view test entity',
      'administer entity_test content',
    ]));
119 120 121
  }

  /**
122
   * Tests the 'options_buttons' widget (single select).
123
   */
124
  public function testRadioButtons() {
125
    // Create an instance of the 'single value' field.
126
    $field = FieldConfig::create([
127
      'field_storage' => $this->card1,
128
      'bundle' => 'entity_test',
129
    ]);
130
    $field->save();
131 132
    \Drupal::service('entity_display.repository')
      ->getFormDisplay('entity_test', 'entity_test')
133
      ->setComponent($this->card1->getName(), [
134
        'type' => 'options_buttons',
135
      ])
136 137
      ->save();

138
    // Create an entity.
139
    $entity = EntityTest::create([
140
      'user_id' => 1,
141
      'name' => $this->randomMachineName(),
142
    ]);
143 144
    $entity->save();
    $entity_init = clone $entity;
145 146

    // With no field data, no buttons are checked.
147
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
148 149 150
    $this->assertSession()->checkboxNotChecked('edit-card-1-0');
    $this->assertSession()->checkboxNotChecked('edit-card-1-1');
    $this->assertSession()->checkboxNotChecked('edit-card-1-2');
151
    $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>');
152
    $this->assertRaw('Some HTML encoded markup with &lt; &amp; &gt;');
153 154

    // Select first option.
155
    $edit = ['card_1' => 0];
156
    $this->submitForm($edit, 'Save');
157
    $this->assertFieldValues($entity_init, 'card_1', [0]);
158 159

    // Check that the selected button is checked.
160
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
161 162 163
    $this->assertSession()->checkboxChecked('edit-card-1-0');
    $this->assertSession()->checkboxNotChecked('edit-card-1-1');
    $this->assertSession()->checkboxNotChecked('edit-card-1-2');
164 165

    // Unselect option.
166
    $edit = ['card_1' => '_none'];
167
    $this->submitForm($edit, 'Save');
168
    $this->assertFieldValues($entity_init, 'card_1', []);
169

170
    // Check that required radios with one option is auto-selected.
171
    $this->card1->setSetting('allowed_values', [99 => 'Only allowed value']);
172
    $this->card1->save();
173
    $field->setRequired(TRUE);
174
    $field->save();
175
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
176
    $this->assertSession()->checkboxChecked('edit-card-1-99');
177 178
  }

179 180 181
  /**
   * Tests the 'options_buttons' widget (multiple select).
   */
182
  public function testCheckBoxes() {
183
    // Create an instance of the 'multiple values' field.
184
    $field = FieldConfig::create([
185
      'field_storage' => $this->card2,
186
      'bundle' => 'entity_test',
187
    ]);
188
    $field->save();
189 190
    \Drupal::service('entity_display.repository')
      ->getFormDisplay('entity_test', 'entity_test')
191
      ->setComponent($this->card2->getName(), [
192
        'type' => 'options_buttons',
193
      ])
194 195
      ->save();

196
    // Create an entity.
197
    $entity = EntityTest::create([
198
      'user_id' => 1,
199
      'name' => $this->randomMachineName(),
200
    ]);
201 202
    $entity->save();
    $entity_init = clone $entity;
203

204
    // Display form: with no field data, nothing is checked.
205
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
206 207 208
    $this->assertSession()->checkboxNotChecked('edit-card-2-0');
    $this->assertSession()->checkboxNotChecked('edit-card-2-1');
    $this->assertSession()->checkboxNotChecked('edit-card-2-2');
209
    $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>');
210 211

    // Submit form: select first and third options.
212
    $edit = [
213 214 215
      'card_2[0]' => TRUE,
      'card_2[1]' => FALSE,
      'card_2[2]' => TRUE,
216
    ];
217
    $this->submitForm($edit, 'Save');
218
    $this->assertFieldValues($entity_init, 'card_2', [0, 2]);
219 220

    // Display form: check that the right options are selected.
221
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
222 223 224
    $this->assertSession()->checkboxChecked('edit-card-2-0');
    $this->assertSession()->checkboxNotChecked('edit-card-2-1');
    $this->assertSession()->checkboxChecked('edit-card-2-2');
225 226

    // Submit form: select only first option.
227
    $edit = [
228 229 230
      'card_2[0]' => TRUE,
      'card_2[1]' => FALSE,
      'card_2[2]' => FALSE,
231
    ];
232
    $this->submitForm($edit, 'Save');
233
    $this->assertFieldValues($entity_init, 'card_2', [0]);
234

235
    // Display form: check that the right options are selected.
236
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
237 238 239
    $this->assertSession()->checkboxChecked('edit-card-2-0');
    $this->assertSession()->checkboxNotChecked('edit-card-2-1');
    $this->assertSession()->checkboxNotChecked('edit-card-2-2');
240 241

    // Submit form: select the three options while the field accepts only 2.
242
    $edit = [
243 244 245
      'card_2[0]' => TRUE,
      'card_2[1]' => TRUE,
      'card_2[2]' => TRUE,
246
    ];
247
    $this->submitForm($edit, 'Save');
248
    $this->assertText('this field cannot hold more than 2 values');
249 250

    // Submit form: uncheck all options.
251
    $edit = [
252 253 254
      'card_2[0]' => FALSE,
      'card_2[1]' => FALSE,
      'card_2[2]' => FALSE,
255
    ];
256
    $this->submitForm($edit, 'Save');
257
    // Check that the value was saved.
258
    $this->assertFieldValues($entity_init, 'card_2', []);
259 260

    // Required checkbox with one option is auto-selected.
261
    $this->card2->setSetting('allowed_values', [99 => 'Only allowed value']);
262
    $this->card2->save();
263
    $field->setRequired(TRUE);
264
    $field->save();
265
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
266
    $this->assertSession()->checkboxChecked('edit-card-2-99');
267 268
  }

269 270 271
  /**
   * Tests the 'options_select' widget (single select).
   */
272
  public function testSelectListSingle() {
273
    // Create an instance of the 'single value' field.
274
    $field = FieldConfig::create([
275
      'field_storage' => $this->card1,
276
      'bundle' => 'entity_test',
277
      'required' => TRUE,
278
    ]);
279
    $field->save();
280 281
    \Drupal::service('entity_display.repository')
      ->getFormDisplay('entity_test', 'entity_test')
282
      ->setComponent($this->card1->getName(), [
283
        'type' => 'options_select',
284
      ])
285 286
      ->save();

287
    // Create an entity.
288
    $entity = EntityTest::create([
289
      'user_id' => 1,
290
      'name' => $this->randomMachineName(),
291
    ]);
292 293
    $entity->save();
    $entity_init = clone $entity;
294

295
    // Display form.
296
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
297
    // A required field without any value has a "none" option.
298 299
    $option = $this->assertSession()->optionExists('edit-card-1', '_none');
    $this->assertSame('- Select a value -', $option->getText());
300 301

    // With no field data, nothing is selected.
302 303 304 305
    $this->assertTrue($this->assertSession()->optionExists('card_1', '_none')->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 2)->isSelected());
306
    $this->assertRaw('Some dangerous &amp; unescaped markup');
307

308
    // Submit form: select invalid 'none' option.
309
    $edit = ['card_1' => '_none'];
310
    $this->submitForm($edit, 'Save');
311
    $this->assertRaw(t('@title field is required.', ['@title' => $field->getName()]));
312

313
    // Submit form: select first option.
314
    $edit = ['card_1' => 0];
315
    $this->submitForm($edit, 'Save');
316
    $this->assertFieldValues($entity_init, 'card_1', [0]);
317 318

    // Display form: check that the right options are selected.
319
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
320
    // A required field with a value has no 'none' option.
321
    $this->assertSession()->optionNotExists('edit-card-1', '_none');
322 323 324
    $this->assertTrue($this->assertSession()->optionExists('card_1', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 2)->isSelected());
325

326
    // Make the field non required.
327
    $field->setRequired(FALSE);
328
    $field->save();
329 330

    // Display form.
331
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
332
    // A non-required field has a 'none' option.
333 334
    $option = $this->assertSession()->optionExists('edit-card-1', '_none');
    $this->assertSame('- None -', $option->getText());
335
    // Submit form: Unselect the option.
336
    $edit = ['card_1' => '_none'];
337
    $this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, 'Save');
338
    $this->assertFieldValues($entity_init, 'card_1', []);
339

340 341
    // Test optgroups.

342 343
    $this->card1->setSetting('allowed_values', []);
    $this->card1->setSetting('allowed_values_function', 'options_test_allowed_values_callback');
344
    $this->card1->save();
345 346

    // Display form: with no field data, nothing is selected
347
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
348 349 350
    $this->assertFalse($this->assertSession()->optionExists('card_1', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 2)->isSelected());
351 352 353
    $this->assertRaw('Some dangerous &amp; unescaped markup');
    $this->assertRaw('More &lt;script&gt;dangerous&lt;/script&gt; markup');
    $this->assertRaw('Group 1');
354 355

    // Submit form: select first option.
356
    $edit = ['card_1' => 0];
357
    $this->submitForm($edit, 'Save');
358
    $this->assertFieldValues($entity_init, 'card_1', [0]);
359 360

    // Display form: check that the right options are selected.
361
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
362 363 364
    $this->assertTrue($this->assertSession()->optionExists('card_1', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_1', 2)->isSelected());
365 366

    // Submit form: Unselect the option.
367
    $edit = ['card_1' => '_none'];
368
    $this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, 'Save');
369
    $this->assertFieldValues($entity_init, 'card_1', []);
370 371 372 373 374
  }

  /**
   * Tests the 'options_select' widget (multiple select).
   */
375
  public function testSelectListMultiple() {
376
    // Create an instance of the 'multiple values' field.
377
    $field = FieldConfig::create([
378
      'field_storage' => $this->card2,
379
      'bundle' => 'entity_test',
380
    ]);
381
    $field->save();
382 383
    \Drupal::service('entity_display.repository')
      ->getFormDisplay('entity_test', 'entity_test')
384
      ->setComponent($this->card2->getName(), [
385
        'type' => 'options_select',
386
      ])
387 388
      ->save();

389
    // Create an entity.
390
    $entity = EntityTest::create([
391
      'user_id' => 1,
392
      'name' => $this->randomMachineName(),
393
    ]);
394 395
    $entity->save();
    $entity_init = clone $entity;
396

397
    // Display form: with no field data, nothing is selected.
398
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
399 400 401 402
    $this->assertTrue($this->assertSession()->optionExists('card_2', '_none')->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 2)->isSelected());
403
    $this->assertRaw('Some dangerous &amp; unescaped markup');
404

405
    // Submit form: select first and third options.
406
    $edit = ['card_2[]' => [0 => 0, 2 => 2]];
407
    $this->submitForm($edit, 'Save');
408
    $this->assertFieldValues($entity_init, 'card_2', [0, 2]);
409

410
    // Display form: check that the right options are selected.
411
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
412 413 414
    $this->assertTrue($this->assertSession()->optionExists('card_2', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 1)->isSelected());
    $this->assertTrue($this->assertSession()->optionExists('card_2', 2)->isSelected());
415

416
    // Submit form: select only first option.
417
    $edit = ['card_2[]' => [0 => 0]];
418
    $this->submitForm($edit, 'Save');
419
    $this->assertFieldValues($entity_init, 'card_2', [0]);
420 421

    // Display form: check that the right options are selected.
422
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
423 424 425
    $this->assertTrue($this->assertSession()->optionExists('card_2', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 2)->isSelected());
426 427

    // Submit form: select the three options while the field accepts only 2.
428
    $edit = ['card_2[]' => [0 => 0, 1 => 1, 2 => 2]];
429
    $this->submitForm($edit, 'Save');
430
    $this->assertText('this field cannot hold more than 2 values');
431 432

    // Submit form: uncheck all options.
433
    $edit = ['card_2[]' => []];
434
    $this->submitForm($edit, 'Save');
435
    $this->assertFieldValues($entity_init, 'card_2', []);
436 437 438

    // Test the 'None' option.

439
    // Check that the 'none' option has no effect if actual options are selected
440
    // as well.
441
    $edit = ['card_2[]' => ['_none' => '_none', 0 => 0]];
442
    $this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, 'Save');
443
    $this->assertFieldValues($entity_init, 'card_2', [0]);
444 445

    // Check that selecting the 'none' option empties the field.
446
    $edit = ['card_2[]' => ['_none' => '_none']];
447
    $this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, 'Save');
448
    $this->assertFieldValues($entity_init, 'card_2', []);
449 450

    // A required select list does not have an empty key.
451
    $field->setRequired(TRUE);
452
    $field->save();
453
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
454
    $this->assertEmpty($this->assertSession()->selectExists('edit-card-2')->find('xpath', 'option[@value=""]'));
455

456 457
    // We do not have to test that a required select list with one option is
    // auto-selected because the browser does it for us.
458 459 460 461

    // Test optgroups.

    // Use a callback function defining optgroups.
462 463
    $this->card2->setSetting('allowed_values', []);
    $this->card2->setSetting('allowed_values_function', 'options_test_allowed_values_callback');
464
    $this->card2->save();
465
    $field->setRequired(FALSE);
466
    $field->save();
467 468

    // Display form: with no field data, nothing is selected.
469
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
470 471 472
    $this->assertFalse($this->assertSession()->optionExists('card_2', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 2)->isSelected());
473 474 475
    $this->assertRaw('Some dangerous &amp; unescaped markup');
    $this->assertRaw('More &lt;script&gt;dangerous&lt;/script&gt; markup');
    $this->assertRaw('Group 1');
476 477

    // Submit form: select first option.
478
    $edit = ['card_2[]' => [0 => 0]];
479
    $this->submitForm($edit, 'Save');
480
    $this->assertFieldValues($entity_init, 'card_2', [0]);
481 482

    // Display form: check that the right options are selected.
483
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
484 485 486
    $this->assertTrue($this->assertSession()->optionExists('card_2', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 1)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('card_2', 2)->isSelected());
487 488

    // Submit form: Unselect the option.
489
    $edit = ['card_2[]' => ['_none' => '_none']];
490
    $this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, 'Save');
491
    $this->assertFieldValues($entity_init, 'card_2', []);
492 493
  }

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
  /**
   * Tests the 'options_select' widget (float values).
   */
  public function testSelectListFloat() {

    // Create an instance of the 'float value' field.
    $field = FieldConfig::create([
      'field_storage' => $this->float,
      'bundle' => 'entity_test',
      'required' => TRUE,
    ]);
    $field->save();

    $this->container
      ->get('entity_type.manager')
      ->getStorage('entity_form_display')
      ->load('entity_test.entity_test.default')
      ->setComponent($this->float->getName(), ['type' => 'options_select'])
      ->save();

    // Create an entity.
    $entity = EntityTest::create([
      'user_id' => 1,
      'name' => $this->randomMachineName(),
    ]);
    $entity->save();

    // Display form.
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');

    // With no field data, nothing is selected.
    $this->assertFalse($this->assertSession()->optionExists('float', 0)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('float', 1.5)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('float', 2)->isSelected());

    // Submit form.
    $edit = ['float' => 1.5];
531
    $this->submitForm($edit, 'Save');
532 533 534 535 536 537 538 539 540
    $this->assertFieldValues($entity, 'float', [1.5]);

    // Display form: check that the right options are selected.
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
    $this->assertFalse($this->assertSession()->optionExists('float', 0)->isSelected());
    $this->assertTrue($this->assertSession()->optionExists('float', 1.5)->isSelected());
    $this->assertFalse($this->assertSession()->optionExists('float', 2)->isSelected());
  }

541 542 543
  /**
   * Tests the 'options_select' and 'options_button' widget for empty value.
   */
544
  public function testEmptyValue() {
545
    // Create an instance of the 'single value' field.
546
    $field = FieldConfig::create([
547 548 549 550 551
      'field_storage' => $this->card1,
      'bundle' => 'entity_test',
    ]);
    $field->save();

552 553 554
    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
    $display_repository = \Drupal::service('entity_display.repository');

555
    // Change it to the check boxes/radio buttons widget.
556
    $display_repository->getFormDisplay('entity_test', 'entity_test')
557 558 559 560 561 562
      ->setComponent($this->card1->getName(), [
        'type' => 'options_buttons',
      ])
      ->save();

    // Create an entity.
563
    $entity = EntityTest::create([
564 565 566 567 568 569
      'user_id' => 1,
      'name' => $this->randomMachineName(),
    ]);
    $entity->save();

    // Display form: check that _none options are present and has label.
570
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
571 572 573 574 575
    // Verify that a test radio button has a "None" choice.
    $this->assertSession()->elementExists('xpath', '//div[@id="edit-card-1"]//input[@value="_none"]');
    // Verify that a test radio button has a "N/A" choice..
    $this->assertSession()->elementExists('xpath', '//div[@id="edit-card-1"]//label[@for="edit-card-1-none"]');
    $this->assertSession()->elementTextEquals('xpath', '//div[@id="edit-card-1"]//label[@for="edit-card-1-none"]', "N/A");
576 577

    // Change it to the select widget.
578
    $display_repository->getFormDisplay('entity_test', 'entity_test')
579
      ->setComponent($this->card1->getName(), [
580
        'type' => 'options_select',
581
      ])
582 583 584
      ->save();

    // Display form: check that _none options are present and has label.
585
    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
586
    // A required field without any value has a "none" option.
587 588
    $option = $this->assertSession()->optionExists('edit-card-1', '_none');
    $this->assertSame('- None -', $option->getText());
589 590
  }

591
}