7d96d0c5b57ad7404541e9481c2b36c7d688402b
[yaffs-website] / web / core / modules / views_ui / tests / src / Functional / HandlerTest.php
1 <?php
2
3 namespace Drupal\Tests\views_ui\Functional;
4
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\field\Entity\FieldConfig;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\views\Tests\ViewTestData;
9 use Drupal\views\ViewExecutable;
10
11 /**
12  * Tests handler UI for views.
13  *
14  * @group views_ui
15  * @see \Drupal\views\Plugin\views\HandlerBase
16  */
17 class HandlerTest extends UITestBase {
18
19   /**
20    * {@inheritdoc}
21    */
22   public static $modules = ['node_test_views'];
23
24   /**
25    * Views used by this test.
26    *
27    * @var array
28    */
29   public static $testViews = ['test_view_empty', 'test_view_broken', 'node', 'test_node_view'];
30
31   /**
32    * {@inheritdoc}
33    */
34   protected function setUp($import_test_views = TRUE) {
35     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    * Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition().
43    *
44    * Adds a uid column to test the relationships.
45    *
46    * @internal
47    */
48   protected function schemaDefinition() {
49     $schema = parent::schemaDefinition();
50
51     $schema['views_test_data']['fields']['uid'] = [
52       'description' => "The {users}.uid of the author of the beatle entry.",
53       'type' => 'int',
54       'unsigned' => TRUE,
55       'not null' => TRUE,
56       'default' => 0,
57     ];
58
59     return $schema;
60   }
61
62   /**
63    * Overrides \Drupal\views\Tests\ViewTestBase::viewsData().
64    *
65    * Adds:
66    * - a relationship for the uid column.
67    * - a dummy field with no help text.
68    */
69   protected function viewsData() {
70     $data = parent::viewsData();
71     $data['views_test_data']['uid'] = [
72       'title' => t('UID'),
73       'help' => t('The test data UID'),
74       'relationship' => [
75         'id' => 'standard',
76         'base' => 'users_field_data',
77         'base field' => 'uid',
78       ],
79     ];
80
81     // Create a dummy field with no help text.
82     $data['views_test_data']['no_help'] = $data['views_test_data']['name'];
83     $data['views_test_data']['no_help']['field']['title'] = t('No help');
84     $data['views_test_data']['no_help']['field']['real field'] = 'name';
85     unset($data['views_test_data']['no_help']['help']);
86
87     return $data;
88   }
89
90   /**
91    * Tests UI CRUD.
92    */
93   public function testUICRUD() {
94     $handler_types = ViewExecutable::getHandlerTypes();
95     foreach ($handler_types as $type => $type_info) {
96       // Test adding handlers.
97       $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/$type";
98
99       // Area handler types need to use a different handler.
100       if (in_array($type, ['header', 'footer', 'empty'])) {
101         $this->drupalPostForm($add_handler_url, ['name[views.area]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
102         $id = 'area';
103         $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
104       }
105       elseif ($type == 'relationship') {
106         $this->drupalPostForm($add_handler_url, ['name[views_test_data.uid]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
107         $id = 'uid';
108         $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
109       }
110       else {
111         $this->drupalPostForm($add_handler_url, ['name[views_test_data.job]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
112         $id = 'job';
113         $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/$type/$id";
114       }
115
116       $this->assertUrl($edit_handler_url, [], 'The user got redirected to the handler edit form.');
117       $random_label = $this->randomMachineName();
118       $this->drupalPostForm(NULL, ['options[admin_label]' => $random_label], t('Apply'));
119
120       $this->assertUrl('admin/structure/views/view/test_view_empty/edit/default', [], 'The user got redirected to the views edit form.');
121
122       $this->assertLinkByHref($edit_handler_url, 0, 'The handler edit link appears in the UI.');
123       $links = $this->xpath('//a[starts-with(normalize-space(text()), :label)]', [':label' => $random_label]);
124       $this->assertTrue(isset($links[0]), 'The handler edit link has the right label');
125
126       // Save the view and have a look whether the handler was added as expected.
127       $this->drupalPostForm(NULL, [], t('Save'));
128       $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
129       $display = $view->getDisplay('default');
130       $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');
131
132       // Remove the item and check that it's removed
133       $this->drupalPostForm($edit_handler_url, [], t('Remove'));
134       $this->assertNoLinkByHref($edit_handler_url, 0, 'The handler edit link does not appears in the UI after removing.');
135
136       $this->drupalPostForm(NULL, [], t('Save'));
137       $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
138       $display = $view->getDisplay('default');
139       $this->assertFalse(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was removed from the view itself.');
140     }
141
142     // Test adding a field of the user table using the uid relationship.
143     $type_info = $handler_types['relationship'];
144     $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/relationship";
145     $this->drupalPostForm($add_handler_url, ['name[views_test_data.uid]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
146
147     $add_handler_url = "admin/structure/views/nojs/add-handler/test_view_empty/default/field";
148     $type_info = $handler_types['field'];
149     $this->drupalPostForm($add_handler_url, ['name[users_field_data.name]' => TRUE], t('Add and configure @handler', ['@handler' => $type_info['ltitle']]));
150     $id = 'name';
151     $edit_handler_url = "admin/structure/views/nojs/handler/test_view_empty/default/field/$id";
152
153     $this->assertUrl($edit_handler_url, [], 'The user got redirected to the handler edit form.');
154     $this->assertFieldByName('options[relationship]', 'uid', 'Ensure the relationship select is filled with the UID relationship.');
155     $this->drupalPostForm(NULL, [], t('Apply'));
156
157     $this->drupalPostForm(NULL, [], t('Save'));
158     $view = $this->container->get('entity.manager')->getStorage('view')->load('test_view_empty');
159     $display = $view->getDisplay('default');
160     $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');
161   }
162
163   /**
164    * Tests escaping of field labels in help text.
165    */
166   public function testHandlerHelpEscaping() {
167     // Setup a field with two instances using a different label.
168     // Ensure that the label is escaped properly.
169
170     $this->drupalCreateContentType(['type' => 'article']);
171     $this->drupalCreateContentType(['type' => 'page']);
172
173     FieldStorageConfig::create([
174       'field_name' => 'field_test',
175       'entity_type' => 'node',
176       'type' => 'string',
177     ])->save();
178
179     FieldConfig::create([
180       'field_name' => 'field_test',
181       'entity_type' => 'node',
182       'bundle' => 'page',
183       'label' => 'The giraffe" label',
184     ])->save();
185
186     FieldConfig::create([
187       'field_name' => 'field_test',
188       'entity_type' => 'node',
189       'bundle' => 'article',
190       'label' => 'The <em>giraffe"</em> label <script>alert("the return of the xss")</script>',
191     ])->save();
192
193     $this->drupalGet('admin/structure/views/nojs/add-handler/content/default/field');
194     $this->assertEscaped('The <em>giraffe"</em> label <script>alert("the return of the xss")</script>');
195     $this->assertEscaped('Appears in: page, article. Also known as: Content: The giraffe" label');
196   }
197
198   /**
199    * Tests broken handlers.
200    */
201   public function testBrokenHandlers() {
202     $handler_types = ViewExecutable::getHandlerTypes();
203     foreach ($handler_types as $type => $type_info) {
204       $this->drupalGet('admin/structure/views/view/test_view_broken/edit');
205
206       $href = "admin/structure/views/nojs/handler/test_view_broken/default/$type/id_broken";
207
208       $result = $this->xpath('//a[contains(@href, :href)]', [':href' => $href]);
209       $this->assertEqual(count($result), 1, new FormattableMarkup('Handler (%type) edit link found.', ['%type' => $type]));
210
211       $text = 'Broken/missing handler';
212
213       $this->assertIdentical($result[0]->getText(), $text, 'Ensure the broken handler text was found.');
214
215       $this->drupalGet($href);
216       $result = $this->xpath('//h1[@class="page-title"]');
217       $this->assertContains($text, $result[0]->getText(), 'Ensure the broken handler text was found.');
218
219       $original_configuration = [
220         'field' => 'id_broken',
221         'id' => 'id_broken',
222         'relationship' => 'none',
223         'table' => 'views_test_data',
224         'plugin_id' => 'numeric',
225       ];
226
227       foreach ($original_configuration as $key => $value) {
228         $this->assertText(new FormattableMarkup('@key: @value', ['@key' => $key, '@value' => $value]));
229       }
230     }
231   }
232
233   /**
234    * Ensures that neither node type or node ID appears multiple times.
235    *
236    * @see \Drupal\views\EntityViewsData
237    */
238   public function testNoDuplicateFields() {
239     $handler_types = ['field', 'filter', 'sort', 'argument'];
240
241     foreach ($handler_types as $handler_type) {
242       $add_handler_url = 'admin/structure/views/nojs/add-handler/test_node_view/default/' . $handler_type;
243       $this->drupalGet($add_handler_url);
244
245       $this->assertNoDuplicateField('ID', 'Content');
246       $this->assertNoDuplicateField('ID', 'Content revision');
247       $this->assertNoDuplicateField('Content type', 'Content');
248       $this->assertNoDuplicateField('UUID', 'Content');
249       $this->assertNoDuplicateField('Revision ID', 'Content');
250       $this->assertNoDuplicateField('Revision ID', 'Content revision');
251     }
252   }
253
254   /**
255    * Ensures that no missing help text is shown.
256    *
257    * @see \Drupal\views\EntityViewsData
258    */
259   public function testErrorMissingHelp() {
260     // Test that the error message is not shown for entity fields but an empty
261     // description field is shown instead.
262     $this->drupalGet('admin/structure/views/nojs/add-handler/test_node_view/default/field');
263     $this->assertNoText('Error: missing help');
264     $this->assertRaw('<td class="description"></td>', 'Empty description found');
265
266     // Test that no error message is shown for other fields.
267     $this->drupalGet('admin/structure/views/nojs/add-handler/test_view_empty/default/field');
268     $this->assertNoText('Error: missing help');
269   }
270
271   /**
272    * Asserts that fields only appear once.
273    *
274    * @param string $field_name
275    *   The field name.
276    * @param string $entity_type
277    *   The entity type to which the field belongs.
278    */
279   public function assertNoDuplicateField($field_name, $entity_type) {
280     $elements = $this->xpath('//td[.=:entity_type]/preceding-sibling::td[@class="title" and .=:title]', [':title' => $field_name, ':entity_type' => $entity_type]);
281     $this->assertEqual(1, count($elements), $field_name . ' appears just once in ' . $entity_type . '.');
282   }
283
284 }