HandlerTest.php 10.9 KB
Newer Older
1 2
<?php

3
namespace Drupal\Tests\views_ui\Functional;
4

5
use Drupal\Component\Utility\SafeMarkup;
6 7
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
8
use Drupal\views\Tests\ViewTestData;
9 10 11
use Drupal\views\ViewExecutable;

/**
12
 * Tests handler UI for views.
13
 *
14
 * @group views_ui
15 16 17 18
 * @see \Drupal\views\Plugin\views\HandlerBase
 */
class HandlerTest extends UITestBase {

19 20 21
  /**
   * {@inheritdoc}
   */
22
  public static $modules = ['node_test_views'];
23

24 25 26 27 28
  /**
   * Views used by this test.
   *
   * @var array
   */
29
  public static $testViews = ['test_view_empty', 'test_view_broken', 'node', 'test_node_view'];
30

31 32 33
  /**
   * {@inheritdoc}
   */
34 35
  protected function setUp($import_test_views = TRUE) {
    parent::setUp($import_test_views);
36

37
    $this->placeBlock('page_title_block');
38
    ViewTestData::createTestViews(get_class($this), ['node_test_views']);
39 40
  }

41 42 43 44 45 46 47 48
  /**
   * Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition().
   *
   * Adds a uid column to test the relationships.
   */
  protected function schemaDefinition() {
    $schema = parent::schemaDefinition();

49
    $schema['views_test_data']['fields']['uid'] = [
50 51 52 53 54
      'description' => "The {users}.uid of the author of the beatle entry.",
      'type' => 'int',
      'unsigned' => TRUE,
      'not null' => TRUE,
      'default' => 0
55
    ];
56 57 58 59 60 61 62

    return $schema;
  }

  /**
   * Overrides \Drupal\views\Tests\ViewTestBase::viewsData().
   *
63 64 65
   * Adds:
   * - a relationship for the uid column.
   * - a dummy field with no help text.
66 67 68
   */
  protected function viewsData() {
    $data = parent::viewsData();
69
    $data['views_test_data']['uid'] = [
70 71
      'title' => t('UID'),
      'help' => t('The test data UID'),
72
      'relationship' => [
73
        'id' => 'standard',
74
        'base' => 'users_field_data',
75
        'base field' => 'uid'
76 77
      ]
    ];
78

79 80 81 82 83 84
    // Create a dummy field with no help text.
    $data['views_test_data']['no_help'] = $data['views_test_data']['name'];
    $data['views_test_data']['no_help']['field']['title'] = t('No help');
    $data['views_test_data']['no_help']['field']['real field'] = 'name';
    unset($data['views_test_data']['no_help']['help']);

85 86 87
    return $data;
  }

88 89 90 91
  /**
   * Tests UI CRUD.
   */
  public function testUICRUD() {
92
    $handler_types = ViewExecutable::getHandlerTypes();
93 94
    foreach ($handler_types as $type => $type_info) {
      // Test adding handlers.
95
      $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/$type";
96 97

      // Area handler types need to use a different handler.
98 99
      if (in_array($type, ['header', 'footer', 'empty'])) {
        $this->drupalPostForm($add_handler_url, ['name[views.area]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
100
        $id = 'area';
101
        $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
102 103
      }
      elseif ($type == 'relationship') {
104
        $this->drupalPostForm($add_handler_url, ['name[views_test_data.uid]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
105
        $id = 'uid';
106
        $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
107 108
      }
      else {
109
        $this->drupalPostForm($add_handler_url, ['name[views_test_data.job]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
110
        $id = 'job';
111
        $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
112 113
      }

114
      $this->assertUrl($edit_handler_url, [], 'The user got redirected to the handler edit form.');
115
      $random_label = $this->randomMachineName();
116
      $this->drupalPostForm(NULL, ['options[admin_label]' => $random_label], t('Apply'));
117

118
      $this->assertUrl('admin/structure/views/view/test_view_empty/edit/default', [], 'The user got redirected to the views edit form.');
119 120

      $this->assertLinkByHref($edit_handler_url, 0, 'The handler edit link appears in the UI.');
121
      $links = $this->xpath('//a[starts-with(normalize-space(text()), :label)]', [':label' => $random_label]);
122
      $this->assertTrue(isset($links[0]), 'The handler edit link has the right label');
123

124
      // Save the view and have a look whether the handler was added as expected.
125
      $this->drupalPostForm(NULL, [], t('Save'));
126
      $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
127 128 129 130
      $display = $view->getDisplay('default');
      $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');

      // Remove the item and check that it's removed
131
      $this->drupalPostForm($edit_handler_url, [], t('Remove'));
132
      $this->assertNoLinkByHref($edit_handler_url, 0, 'The handler edit link does not appears in the UI after removing.');
133

134
      $this->drupalPostForm(NULL, [], t('Save'));
135
      $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
136 137
      $display = $view->getDisplay('default');
      $this->assertFalse(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was removed from the view itself.');
138
    }
139 140 141

    // Test adding a field of the user table using the uid relationship.
    $type_info = $handler_types['relationship'];
142
    $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/relationship";
143
    $this->drupalPostForm($add_handler_url, ['name[views_test_data.uid]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
144

145
    $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/field";
146
    $type_info = $handler_types['field'];
147
    $this->drupalPostForm($add_handler_url, ['name[users_field_data.name]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
148
    $id = 'name';
149
    $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/field/$id";
150

151
    $this->assertUrl($edit_handler_url, [], 'The user got redirected to the handler edit form.');
152
    $this->assertFieldByName('options[relationship]', 'uid', 'Ensure the relationship select is filled with the UID relationship.');
153
    $this->drupalPostForm(NULL, [], t('Apply'));
154

155
    $this->drupalPostForm(NULL, [], t('Save'));
156
    $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
157 158
    $display = $view->getDisplay('default');
    $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');
159 160
  }

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
  /**
   * Tests escaping of field labels in help text.
   */
  public function testHandlerHelpEscaping() {
    // Setup a field with two instances using a different label.
    // Ensure that the label is escaped properly.

    $this->drupalCreateContentType(['type' => 'article']);
    $this->drupalCreateContentType(['type' => 'page']);

    FieldStorageConfig::create([
      'field_name' => 'field_test',
      'entity_type' => 'node',
      'type' => 'string',
    ])->save();

    FieldConfig::create([
      'field_name' => 'field_test',
      'entity_type' => 'node',
      'bundle' => 'page',
      'label' => 'The giraffe" label'
    ])->save();

    FieldConfig::create([
      'field_name' => 'field_test',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'The <em>giraffe"</em> label <script>alert("the return of the xss")</script>'
    ])->save();

    $this->drupalGet('admin/structure/views/nojs/add-handler/content/default/field');
192 193
    $this->assertEscaped('The <em>giraffe"</em> label <script>alert("the return of the xss")</script>');
    $this->assertEscaped('Appears in: page, article. Also known as: Content: The giraffe" label');
194 195
  }

196 197 198 199
  /**
   * Tests broken handlers.
   */
  public function testBrokenHandlers() {
200
    $handler_types = ViewExecutable::getHandlerTypes();
201 202 203
    foreach ($handler_types as $type => $type_info) {
      $this->drupalGet('admin/structure/views/view/test_view_broken/edit');

204
      $href = "admin/structure/views/nojs/handler/test_view_broken/default/$type/id_broken";
205

206 207
      $result = $this->xpath('//a[contains(@href, :href)]', [':href' => $href]);
      $this->assertEqual(count($result), 1, SafeMarkup::format('Handler (%type) edit link found.', ['%type' => $type]));
208

209
      $text = 'Broken/missing handler';
210

211
      $this->assertIdentical($result[0]->getText(), $text, 'Ensure the broken handler text was found.');
212 213

      $this->drupalGet($href);
214
      $result = $this->xpath('//h1[@class="page-title"]');
215
      $this->assertContains($text, $result[0]->getText(), 'Ensure the broken handler text was found.');
216

217 218 219 220 221 222 223
      $original_configuration = [
        'field' => 'id_broken',
        'id' => 'id_broken',
        'relationship' => 'none',
        'table' => 'views_test_data',
        'plugin_id' => 'numeric',
      ];
224

225
      foreach ($original_configuration as $key => $value) {
226
        $this->assertText(SafeMarkup::format('@key: @value', ['@key' => $key, '@value' => $value]));
227 228 229 230
      }
    }
  }

231 232 233 234 235 236 237 238 239 240 241 242
  /**
   * Ensures that neither node type or node ID appears multiple times.
   *
   * @see \Drupal\views\EntityViewsData
   */
  public function testNoDuplicateFields() {
    $handler_types = ['field', 'filter', 'sort', 'argument'];

    foreach ($handler_types as $handler_type) {
      $add_handler_url = 'admin/structure/views/nojs/add-handler/test_node_view/default/' . $handler_type;
      $this->drupalGet($add_handler_url);

243 244 245
      $this->assertNoDuplicateField('ID', 'Content');
      $this->assertNoDuplicateField('ID', 'Content revision');
      $this->assertNoDuplicateField('Content type', 'Content');
246 247 248 249 250 251
      $this->assertNoDuplicateField('UUID', 'Content');
      $this->assertNoDuplicateField('Revision ID', 'Content');
      $this->assertNoDuplicateField('Revision ID', 'Content revision');
    }
  }

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  /**
   * Ensures that no missing help text is shown.
   *
   * @see \Drupal\views\EntityViewsData
   */
  public function testErrorMissingHelp() {
    // Test that the error message is not shown for entity fields but an empty
    // description field is shown instead.
    $this->drupalGet('admin/structure/views/nojs/add-handler/test_node_view/default/field');
    $this->assertNoText('Error: missing help');
    $this->assertRaw('<td class="description"></td>', 'Empty description found');

    // Test that no error message is shown for other fields.
    $this->drupalGet('admin/structure/views/nojs/add-handler/test_view_empty/default/field');
    $this->assertNoText('Error: missing help');
  }

269 270 271 272 273 274 275 276 277 278
  /**
   * Asserts that fields only appear once.
   *
   * @param string $field_name
   *   The field name.
   * @param string $entity_type
   *   The entity type to which the field belongs.
   */
  public function assertNoDuplicateField($field_name, $entity_type) {
    $elements = $this->xpath('//td[.=:entity_type]/preceding-sibling::td[@class="title" and .=:title]', [':title' => $field_name, ':entity_type' => $entity_type]);
279
    $this->assertEqual(1, count($elements), $field_name . ' appears just once in ' . $entity_type . '.');
280
  }
281

282
}