ConfigEntityListTest.php 10.5 KB
Newer Older
1 2
<?php

3
namespace Drupal\Tests\config\Functional;
4

5
use Drupal\Core\Routing\RedirectDestinationTrait;
6
use Drupal\config_test\Entity\ConfigTest;
7
use Drupal\Core\Entity\EntityStorageInterface;
8
use Drupal\Tests\BrowserTestBase;
9 10 11

/**
 * Tests the listing of configuration entities.
12 13
 *
 * @group config
14
 */
15
class ConfigEntityListTest extends BrowserTestBase {
16

17 18
  use RedirectDestinationTrait;

19 20 21 22 23
  /**
   * Modules to enable.
   *
   * @var array
   */
24
  protected static $modules = ['block', 'config_test'];
25

26 27 28 29 30
  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'classy';

31 32 33
  /**
   * {@inheritdoc}
   */
34
  protected function setUp(): void {
35 36 37
    parent::setUp();
    // Delete the override config_test entity since it is not required by this
    // test.
38
    \Drupal::entityTypeManager()->getStorage('config_test')->load('override')->delete();
39
    $this->drupalPlaceBlock('local_actions_block');
40 41
  }

42
  /**
43
   * Tests entity list builder methods.
44
   */
45
  public function testList() {
46
    $controller = \Drupal::entityTypeManager()->getListBuilder('config_test');
47

48
    // Test getStorage() method.
49
    $this->assertInstanceOf(EntityStorageInterface::class, $controller->getStorage());
50 51 52

    // Get a list of ConfigTest entities and confirm that it contains the
    // ConfigTest entity provided by the config_test module.
53
    // @see config_test.dynamic.dotted.default.yml
54
    $list = $controller->load();
55
    $this->assertCount(1, $list, '1 ConfigTest entity found.');
56
    $entity = $list['dotted.default'];
57
    $this->assertInstanceOf(ConfigTest::class, $entity);
58 59

    // Test getOperations() method.
60
    $expected_operations = [
61
      'edit' => [
62
        'title' => t('Edit'),
63
        'weight' => 10,
64
        'url' => $entity->toUrl()->setOption('query', $this->getRedirectDestination()->getAsArray()),
65 66
      ],
      'disable' => [
67
        'title' => t('Disable'),
68
        'weight' => 40,
69
        'url' => $entity->toUrl('disable')->setOption('query', $this->getRedirectDestination()->getAsArray()),
70
      ],
71
      'delete' => [
72
        'title' => t('Delete'),
73
        'weight' => 100,
74
        'url' => $entity->toUrl('delete-form')->setOption('query', $this->getRedirectDestination()->getAsArray()),
75 76
      ],
    ];
77

78
    $actual_operations = $controller->getOperations($entity);
79
    // Sort the operations to normalize link order.
80
    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
81
    $this->assertEquals($expected_operations, $actual_operations, 'The operations are identical.');
82 83

    // Test buildHeader() method.
84
    $expected_items = [
85 86 87
      'label' => 'Label',
      'id' => 'Machine name',
      'operations' => 'Operations',
88
    ];
89
    $actual_items = $controller->buildHeader();
90
    $this->assertEquals($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
91 92 93

    // Test buildRow() method.
    $build_operations = $controller->buildOperations($entity);
94
    $expected_items = [
95
      'label' => 'Default',
96
      'id' => 'dotted.default',
97
      'operations' => [
98
        'data' => $build_operations,
99 100
      ],
    ];
101
    $actual_items = $controller->buildRow($entity);
102
    $this->assertEquals($expected_items, $actual_items, 'Return value from buildRow matches expected.');
103
    // Test sorting.
104
    $storage = $controller->getStorage();
105
    $entity = $storage->create([
106 107 108
      'id' => 'alpha',
      'label' => 'Alpha',
      'weight' => 1,
109
    ]);
110
    $entity->save();
111
    $entity = $storage->create([
112 113 114
      'id' => 'omega',
      'label' => 'Omega',
      'weight' => 1,
115
    ]);
116
    $entity->save();
117
    $entity = $storage->create([
118 119 120
      'id' => 'beta',
      'label' => 'Beta',
      'weight' => 0,
121
    ]);
122 123
    $entity->save();
    $list = $controller->load();
124
    $this->assertIdentical(array_keys($list), ['beta', 'dotted.default', 'alpha', 'omega']);
125 126 127

    // Test that config entities that do not support status, do not have
    // enable/disable operations.
128
    $controller = $this->container->get('entity_type.manager')
129
      ->getListBuilder('config_test_no_status');
130 131 132 133 134

    $list = $controller->load();
    $entity = $list['default'];

    // Test getOperations() method.
135 136
    $expected_operations = [
      'edit' => [
137 138
        'title' => t('Edit'),
        'weight' => 10,
139
        'url' => $entity->toUrl()->setOption('query', $this->getRedirectDestination()->getAsArray()),
140 141
      ],
      'delete' => [
142 143
        'title' => t('Delete'),
        'weight' => 100,
144
        'url' => $entity->toUrl('delete-form')->setOption('query', $this->getRedirectDestination()->getAsArray()),
145 146
      ],
    ];
147 148 149

    $actual_operations = $controller->getOperations($entity);
    // Sort the operations to normalize link order.
150
    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
151
    $this->assertEquals($expected_operations, $actual_operations, 'The operations are identical.');
152 153 154 155 156
  }

  /**
   * Tests the listing UI.
   */
157
  public function testListUI() {
158
    // Log in as an administrative user to access the full menu trail.
159
    $this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer site configuration']));
160 161 162 163 164 165 166 167

    // Get the list callback page.
    $this->drupalGet('admin/structure/config_test');

    // Test for the page title.
    $this->assertTitle('Test configuration | Drupal');

    // Test for the table.
168
    $element = $this->xpath('//div[@class="layout-content"]//table');
169
    $this->assertCount(1, $element, 'Configuration entity list table found.');
170 171

    // Test the table header.
172
    $elements = $this->xpath('//div[@class="layout-content"]//table/thead/tr/th');
173
    $this->assertCount(3, $elements, 'Correct number of table header cells found.');
174 175

    // Test the contents of each th cell.
176
    $expected_items = ['Label', 'Machine name', 'Operations'];
177
    foreach ($elements as $key => $element) {
178
      $this->assertIdentical($element->getText(), $expected_items[$key]);
179 180 181
    }

    // Check the number of table row cells.
182
    $elements = $this->xpath('//div[@class="layout-content"]//table/tbody/tr[@class="odd"]/td');
183
    $this->assertCount(3, $elements, 'Correct number of table row cells found.');
184 185 186 187

    // Check the contents of each row cell. The first cell contains the label,
    // the second contains the machine name, and the third contains the
    // operations list.
188 189 190
    $this->assertIdentical($elements[0]->getText(), 'Default');
    $this->assertIdentical($elements[1]->getText(), 'dotted.default');
    $this->assertNotEmpty($elements[2]->find('xpath', '//ul'), 'Operations list found.');
191 192 193 194 195

    // Add a new entity using the operations link.
    $this->assertLink('Add test configuration');
    $this->clickLink('Add test configuration');
    $this->assertResponse(200);
196
    $edit = [
197 198 199
      'label' => 'Antelope',
      'id' => 'antelope',
      'weight' => 1,
200
    ];
201
    $this->drupalPostForm(NULL, $edit, t('Save'));
202

203
    // Ensure that the entity's sort method was called.
204
    $this->assertTrue(\Drupal::state()->get('config_entity_sort'), 'ConfigTest::sort() was called.');
205

206 207 208 209 210 211 212
    // Confirm that the user is returned to the listing, and verify that the
    // text of the label and machine name appears in the list (versus elsewhere
    // on the page).
    $this->assertFieldByXpath('//td', 'Antelope', "Label found for added 'Antelope' entity.");
    $this->assertFieldByXpath('//td', 'antelope', "Machine name found for added 'Antelope' entity.");

    // Edit the entity using the operations link.
213
    $this->assertLinkByHref('admin/structure/config_test/manage/antelope');
214
    $this->clickLink('Edit', 1);
215
    $this->assertResponse(200);
216
    $this->assertTitle('Edit Antelope | Drupal');
217
    $edit = ['label' => 'Albatross', 'id' => 'albatross'];
218
    $this->drupalPostForm(NULL, $edit, t('Save'));
219 220 221 222 223 224 225 226

    // Confirm that the user is returned to the listing, and verify that the
    // text of the label and machine name appears in the list (versus elsewhere
    // on the page).
    $this->assertFieldByXpath('//td', 'Albatross', "Label found for updated 'Albatross' entity.");
    $this->assertFieldByXpath('//td', 'albatross', "Machine name found for updated 'Albatross' entity.");

    // Delete the added entity using the operations link.
227 228
    $this->assertLinkByHref('admin/structure/config_test/manage/albatross/delete');
    $this->clickLink('Delete', 1);
229
    $this->assertResponse(200);
230
    $this->assertTitle('Are you sure you want to delete the test configuration Albatross? | Drupal');
231
    $this->drupalPostForm(NULL, [], t('Delete'));
232 233 234 235 236 237 238 239 240

    // Verify that the text of the label and machine name does not appear in
    // the list (though it may appear elsewhere on the page).
    $this->assertNoFieldByXpath('//td', 'Albatross', "No label found for deleted 'Albatross' entity.");
    $this->assertNoFieldByXpath('//td', 'albatross', "No machine name found for deleted 'Albatross' entity.");

    // Delete the original entity using the operations link.
    $this->clickLink('Delete');
    $this->assertResponse(200);
241
    $this->assertTitle('Are you sure you want to delete the test configuration Default? | Drupal');
242
    $this->drupalPostForm(NULL, [], t('Delete'));
243 244 245 246

    // Verify that the text of the label and machine name does not appear in
    // the list (though it may appear elsewhere on the page).
    $this->assertNoFieldByXpath('//td', 'Default', "No label found for deleted 'Default' entity.");
247
    $this->assertNoFieldByXpath('//td', 'dotted.default', "No machine name found for deleted 'Default' entity.");
248 249

    // Confirm that the empty text is displayed.
250
    $this->assertText('There are no test configuration entities yet.');
251 252
  }

253 254 255 256
  /**
   * Test paging.
   */
  public function testPager() {
257 258
    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));

259
    $storage = \Drupal::service('entity_type.manager')->getListBuilder('config_test')->getStorage();
260 261 262

    // Create 51 test entities.
    for ($i = 1; $i < 52; $i++) {
263
      $storage->create([
264 265 266 267
        'id' => str_pad($i, 2, '0', STR_PAD_LEFT),
        'label' => 'Test config entity ' . $i,
        'weight' => $i,
        'protected_property' => $i,
268
      ])->save();
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    }

    // Load the listing page.
    $this->drupalGet('admin/structure/config_test');

    // Item 51 should not be present.
    $this->assertRaw('Test config entity 50', 'Config entity 50 is shown.');
    $this->assertNoRaw('Test config entity 51', 'Config entity 51 is on the next page.');

    // Browse to the next page.
    $this->clickLink(t('Page 2'));
    $this->assertNoRaw('Test config entity 50', 'Test config entity 50 is on the previous page.');
    $this->assertRaw('dotted.default', 'Default config entity appears on page 2.');
    $this->assertRaw('Test config entity 51', 'Test config entity 51 is on page 2.');
  }

285
}