/** * Test the username formatter. */ public function testUsername() { $view_id = $this->randomMachineName(); $view = View::create(['id' => $view_id, 'base_table' => 'comment_field_data', 'display' => ['default' => ['display_plugin' => 'default', 'id' => 'default', 'display_options' => ['fields' => ['name' => ['table' => 'comment_field_data', 'field' => 'name', 'id' => 'name', 'plugin_id' => 'field', 'type' => 'comment_username'], 'subject' => ['table' => 'comment_field_data', 'field' => 'subject', 'id' => 'subject', 'plugin_id' => 'field', 'type' => 'string', 'settings' => ['link_to_entity' => TRUE]]]]]]]); $view->save(); /* @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */ $account_switcher = \Drupal::service('account_switcher'); /* @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); $account_switcher->switchTo($this->adminUser); $executable = Views::getView($view_id); $build = $executable->preview(); $this->setRawContent($renderer->renderRoot($build)); $this->verbose($this->getRawContent()); $this->assertLink('My comment title'); $this->assertLink('Anonymous comment title'); $this->assertLink($this->adminUser->label()); $this->assertLink('barry (not verified)'); $account_switcher->switchTo(new AnonymousUserSession()); $executable = Views::getView($view_id); $executable->storage->invalidateCaches(); $build = $executable->preview(); $this->setRawContent($renderer->renderRoot($build)); // No access to user-profiles, so shouldn't be able to see links. $this->assertNoLink($this->adminUser->label()); // Note: External users aren't pointing to drupal user profiles. $this->assertLink('barry (not verified)'); $this->verbose($this->getRawContent()); $this->assertLink('My comment title'); $this->assertLink('Anonymous comment title'); }
/** * Checks views field access for a given entity type and field name. * * To use this method, set up an entity of type $entity_type_id, with field * $field_name. Create an entity instance that contains content $field_content * in that field. * * This method will check that a user with permission can see the content in a * view, and a user without access permission on that field cannot. * * @param string $entity_type_id * The entity type ID. * @param string $field_name * The field name. * @param string $field_content * The expected field content. */ protected function assertFieldAccess($entity_type_id, $field_name, $field_content) { \Drupal::state()->set('views_field_access_test-field', $field_name); $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id); $view_id = $this->randomMachineName(); $data_table = $entity_type->getDataTable(); // Use the data table as long as the field is not 'uuid'. This is the only // column that can only be obtained from the base table. $base_table = $data_table && $field_name !== 'uuid' ? $data_table : $entity_type->getBaseTable(); $entity = View::create(['id' => $view_id, 'base_table' => $base_table, 'display' => ['default' => ['display_plugin' => 'default', 'id' => 'default', 'display_options' => ['fields' => [$field_name => ['table' => $base_table, 'field' => $field_name, 'id' => $field_name, 'plugin_id' => 'field']]]]]]); $entity->save(); /** @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */ $account_switcher = \Drupal::service('account_switcher'); /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); $account_switcher->switchTo($this->userWithAccess); $executable = Views::getView($view_id); $build = $executable->preview(); $this->setRawContent($renderer->renderRoot($build)); $this->assertText($field_content); $this->assertTrue(isset($executable->field[$field_name])); $account_switcher->switchTo($this->userWithoutAccess); $executable = Views::getView($view_id); $build = $executable->preview(); $this->setRawContent($renderer->renderRoot($build)); $this->assertNoText($field_content); $this->assertFalse(isset($executable->field[$field_name])); \Drupal::state()->delete('views_field_access_test-field'); }
/** * Tests XSS coming from View block labels. */ protected function doViewTest() { $view = View::create(['id' => $this->randomMachineName(), 'label' => '<script>alert("view");</script>']); $view->addDisplay('block'); $view->save(); $this->drupalGet(Url::fromRoute('block.admin_display')); $this->clickLink('<script>alert("view");</script>'); $this->assertRaw('<script>alert("view");</script>'); $this->assertNoRaw('<script>alert("view");</script>'); }
/** * {@inheritdoc} */ public function createView($options = NULL) { if ($view_template = $this->loadTemplate($options)) { $view_template['id'] = $options['id']; $view_template['label'] = $options['label']; $view_template['description'] = $options['description']; return View::create($view_template); } return NULL; }
/** * Tests XSS coming from View block labels. */ protected function doViewTest() { $view = View::create(['id' => $this->randomMachineName(), 'label' => '<script>alert("view");</script>']); $view->addDisplay('block'); $view->save(); $this->drupalGet(Url::fromRoute('block.admin_display')); $this->clickLinkPartialName('Place block'); // The block admin label is automatically XSS admin filtered. $this->assertRaw('alert("view");'); $this->assertNoRaw('<script>alert("view");</script>'); }
/** * Tests most of the handlers. */ public function testHandlers() { $this->drupalCreateContentType(array('type' => 'article')); $this->addDefaultCommentField('node', 'article'); $object_types = array_keys(ViewExecutable::getHandlerTypes()); foreach ($this->container->get('views.views_data')->get() as $base_table => $info) { if (!isset($info['table']['base'])) { continue; } $view = View::create(array('base_table' => $base_table)); $view = $view->getExecutable(); // @todo The groupwise relationship is currently broken. $exclude[] = 'taxonomy_term_field_data:tid_representative'; $exclude[] = 'users_field_data:uid_representative'; // Go through all fields and there through all handler types. foreach ($info as $field => $field_info) { // Table is a reserved key for the metainformation. if ($field != 'table' && !in_array("{$base_table}:{$field}", $exclude)) { $item = array('table' => $base_table, 'field' => $field); foreach ($object_types as $type) { if (isset($field_info[$type]['id'])) { $options = array(); if ($type == 'filter') { $handler = $this->container->get("plugin.manager.views.{$type}")->getHandler($item); // Set the value to use for the filter based on the filter type. if ($handler instanceof InOperator) { $options['value'] = array(1); } else { $options['value'] = 1; } } $view->addHandler('default', $type, $base_table, $field, $options); } } } } // Go through each step individually to see whether some parts are // failing. $view->build(); $view->preExecute(); $view->execute(); $view->render(); // Make sure all handlers extend the HandlerBase. foreach ($object_types as $type) { if (isset($view->{$type})) { foreach ($view->{$type} as $handler) { $this->assertTrue($handler instanceof HandlerBase, format_string('@type handler of class %class is an instance of HandlerBase', array('@type' => $type, '%class' => get_class($handler)))); } } } } }
/** * Tests that the views list does not use a pager. */ public function testViewsListLimit() { // Check if we can access the main views admin page. $this->drupalGet('admin/structure/views'); $this->assertResponse(200); $this->assertLink(t('Add view')); // Count default views to be subtracted from the limit. $views = count(Views::getEnabledViews()); // Create multiples views. $limit = 51; $values = $this->config('views.view.test_view_storage')->get(); for ($i = 1; $i <= $limit - $views; $i++) { $values['id'] = 'test_view_storage_new' . $i; unset($values['uuid']); $created = View::create($values); $created->save(); } $this->drupalGet('admin/structure/views'); // Check that all the rows are listed. $this->assertEqual(count($this->xpath('//tbody/tr[contains(@class,"views-ui-list-enabled")]')), $limit); }
/** * Tests the views_ui_autocomplete_tag function. */ public function testViewsUiAutocompleteTag() { \Drupal::moduleHandler()->loadInclude('views_ui', 'inc', 'admin'); // Save 15 views with a tag. $tags = array(); for ($i = 0; $i < 16; $i++) { $suffix = $i % 2 ? 'odd' : 'even'; $tag = 'autocomplete_tag_test_' . $suffix . $this->randomMachineName(); $tags[] = $tag; View::create(array('tag' => $tag, 'id' => $this->randomMachineName()))->save(); } // Make sure just ten results are returns. $controller = ViewsUIController::create($this->container); $request = $this->container->get('request_stack')->getCurrentRequest(); $request->query->set('q', 'autocomplete_tag_test'); $result = $controller->autocompleteTag($request); $matches = (array) json_decode($result->getContent(), TRUE); $this->assertEqual(count($matches), 10, 'Make sure the maximum amount of tag results is 10.'); // Make sure the returned array has the proper format. $suggestions = array_map(function ($tag) { return array('value' => $tag, 'label' => Html::escape($tag)); }, $tags); foreach ($matches as $match) { $this->assertTrue(in_array($match, $suggestions), 'Make sure the returned array has the proper format.'); } // Make sure that matching by a certain prefix works. $request->query->set('q', 'autocomplete_tag_test_even'); $result = $controller->autocompleteTag($request); $matches = (array) json_decode($result->getContent(), TRUE); $this->assertEqual(count($matches), 8, 'Make sure that only a subset is returned.'); foreach ($matches as $tag) { $this->assertTrue(array_search($tag['value'], $tags) !== FALSE, format_string('Make sure the returned tag @tag actually exists.', array('@tag' => $tag['value']))); } // Make sure an invalid result doesn't return anything. $request->query->set('q', $this->randomMachineName()); $result = $controller->autocompleteTag($request); $matches = (array) json_decode($result->getContent()); $this->assertEqual(count($matches), 0, "Make sure an invalid tag doesn't return anything."); }
/** * Tests the relationship ui for field/filter/argument/relationship. */ public function testRelationshipUI() { $views_admin = $this->drupalCreateUser(array('administer views')); $this->drupalLogin($views_admin); // Make sure the link to the field options exists. $handler_options_path = 'admin/structure/views/nojs/handler/test_handler_relationships/default/field/title'; $view_edit_path = 'admin/structure/views/view/test_handler_relationships/edit'; $this->drupalGet($view_edit_path); $this->assertLinkByHref($handler_options_path); // The test view has a relationship to node_revision so the field should // show a relationship selection. $this->drupalGet($handler_options_path); $relationship_name = 'options[relationship]'; $this->assertFieldByName($relationship_name); // Check for available options. $xpath = $this->constructFieldXpath('name', $relationship_name); $fields = $this->xpath($xpath); $options = array(); foreach ($fields as $field) { $items = $this->getAllOptions($field); foreach ($items as $item) { $options[] = $item->attributes()->value; } } $expected_options = array('none', 'nid'); $this->assertEqual($options, $expected_options); // Remove the relationship and make sure no relationship option appears. $this->drupalPostForm('admin/structure/views/nojs/handler/test_handler_relationships/default/relationship/nid', array(), t('Remove')); $this->drupalGet($handler_options_path); $this->assertNoFieldByName($relationship_name, NULL, 'Make sure that no relationship option is available'); // Create a view of comments with node relationship. View::create(['base_table' => 'comment_field_data', 'id' => 'test_get_entity_type'])->save(); $this->drupalPostForm('admin/structure/views/nojs/add-handler/test_get_entity_type/default/relationship', ['name[comment_field_data.node]' => 'comment_field_data.node'], t('Add and configure relationships')); $this->drupalPostForm(NULL, [], t('Apply')); // Add a content type filter. $this->drupalPostForm('admin/structure/views/nojs/add-handler/test_get_entity_type/default/filter', ['name[node_field_data.type]' => 'node_field_data.type'], t('Add and configure filter criteria')); $this->assertOptionSelected('edit-options-relationship', 'node'); $this->drupalPostForm(NULL, ['options[value][page]' => 'page'], t('Apply')); // Check content type filter options. $this->drupalGet('admin/structure/views/nojs/handler/test_get_entity_type/default/filter/type'); $this->assertOptionSelected('edit-options-relationship', 'node'); $this->assertFieldChecked('edit-options-value-page'); }
/** * {@inheritdoc} */ public static function create(array $values = array()) { return View::create($values); }
/** * Tests the readmore functionality. */ public function testReadMore() { /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = $this->container->get('renderer'); if (!isset($this->options['validate']['type'])) { return; } $expected_more_text = 'custom more text'; $view = Views::getView('test_display_more'); $this->executeView($view); $output = $view->preview(); $output = $renderer->renderRoot($output); $this->setRawContent($output); $result = $this->xpath('//a[@class=:class]', array(':class' => 'more-link')); $this->assertEqual($result[0]->attributes()->href, \Drupal::url('view.test_display_more.page_1'), 'The right more link is shown.'); $this->assertEqual(trim($result[0][0]), $expected_more_text, 'The right link text is shown.'); // Test the renderMoreLink method directly. This could be directly unit // tested. $more_link = $view->display_handler->renderMoreLink(); $more_link = $renderer->renderRoot($more_link); $this->setRawContent($more_link); $result = $this->xpath('//a[@class=:class]', array(':class' => 'more-link')); $this->assertEqual($result[0]->attributes()->href, \Drupal::url('view.test_display_more.page_1'), 'The right more link is shown.'); $this->assertEqual(trim($result[0][0]), $expected_more_text, 'The right link text is shown.'); // Test the useMoreText method directly. This could be directly unit // tested. $more_text = $view->display_handler->useMoreText(); $this->assertEqual($more_text, $expected_more_text, 'The right more text is chosen.'); $view = Views::getView('test_display_more'); $view->setDisplay(); $view->display_handler->setOption('use_more', 0); $this->executeView($view); $output = $view->preview(); $output = $renderer->renderRoot($output); $this->setRawContent($output); $result = $this->xpath('//a[@class=:class]', array(':class' => 'more-link')); $this->assertTrue(empty($result), 'The more link is not shown.'); $view = Views::getView('test_display_more'); $view->setDisplay(); $view->display_handler->setOption('use_more', 0); $view->display_handler->setOption('use_more_always', 0); $view->display_handler->setOption('pager', array('type' => 'some', 'options' => array('items_per_page' => 1, 'offset' => 0))); $this->executeView($view); $output = $view->preview(); $output = $renderer->renderRoot($output); $this->setRawContent($output); $result = $this->xpath('//a[@class=:class]', array(':class' => 'more-link')); $this->assertTrue(empty($result), 'The more link is not shown when view has more records.'); // Test the default value of use_more_always. $view = View::create()->getExecutable(); $this->assertTrue($view->getDisplay()->getOption('use_more_always'), 'Always display the more link by default.'); }
/** * Instantiates a view object from form values. * * @return \Drupal\views_ui\ViewUI * The instantiated view UI object. */ protected function instantiateView($form, FormStateInterface $form_state) { // Build the basic view properties and create the view. $values = array('id' => $form_state->getValue('id'), 'label' => $form_state->getValue('label'), 'description' => $form_state->getValue('description'), 'base_table' => $this->base_table, 'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId()); $view = View::create($values); // Build all display options for this view. $display_options = $this->buildDisplayOptions($form, $form_state); // Allow the fully built options to be altered. This happens before adding // the options to the view, so that once they are eventually added we will // be able to get all the overrides correct. $this->alterDisplayOptions($display_options, $form, $form_state); $this->addDisplays($view, $display_options, $form, $form_state); return new ViewUI($view); }
/** * Helper function to create a pseudo view. * * We use this to obtain our subquery SQL. */ protected function getTemporaryView() { $view = View::create(array('base_table' => $this->definition['base'])); $view->addDisplay('default'); return $view->getExecutable(); }
/** * Tests that nested loops of the display handlers won't break validation. */ public function testValidateNestedLoops() { $view = View::create(['id' => 'test_validate_nested_loops']); $executable = $view->getExecutable(); $executable->newDisplay('display_test'); $executable->newDisplay('display_test'); $errors = $executable->validate(); $total_error_count = array_reduce($errors, function ($carry, $item) { $carry += count($item); return $carry; }); // Assert that there were 9 total errors across 3 displays. $this->assertIdentical(9, $total_error_count); $this->assertIdentical(3, count($errors)); }
/** * {@inheritdoc} */ public function createView($options = NULL) { $view_values = ['id' => $options['id'], 'label' => $options['label'], 'description' => $options['description'], 'base_table' => $this->getBaseTable()]; return View::create($view_values); }
/** * Tests XSS coming from View block labels. */ protected function doViewTest() { // Create a View without a custom label for its block Display. The // admin_label of the block then becomes just the View's label. $view = View::create(['id' => $this->randomMachineName(), 'label' => '<script>alert("view1");</script>']); $view->addDisplay('block'); $view->save(); // Create a View with a custom label for its block Display. The // admin_label of the block then becomes the View's label combined with // the Display's label. $view = View::create(['id' => $this->randomMachineName(), 'label' => '<script>alert("view2");</script>']); $view->addDisplay('block', 'Fish & chips'); $view->save(); $this->drupalGet(Url::fromRoute('block.admin_display')); $this->clickLinkPartialName('Place block'); // \Drupal\views\Plugin\Derivative\ViewsBlock::getDerivativeDefinitions() // has a different code path for an admin label based only on the View // label versus one based on both the View label and the Display label. // Ensure that this test is covering both code paths by asserting the // absence of a ":" for the first View and the presence of a ":" for the // second one. Note that the second assertion is redundant with the one // further down which also checks for the Display label, but is included // here for clarity. $this->assertNoEscaped('<script>alert("view1");</script>:'); $this->assertEscaped('<script>alert("view2");</script>:'); // Assert that the blocks have their admin labels escaped and // don't appear anywhere unescaped. $this->assertEscaped('<script>alert("view1");</script>'); $this->assertNoRaw('<script>alert("view1");</script>'); $this->assertEscaped('<script>alert("view2");</script>: Fish & chips'); $this->assertNoRaw('<script>alert("view2");</script>'); $this->assertNoRaw('Fish & chips'); // Assert the Display label doesn't appear anywhere double escaped. $this->assertNoRaw('Fish & chips'); $this->assertNoRaw('Fish &amp; chips'); }
/** * Create a view setup for testing views_infinite_scroll. * * @param string $path * The path for the view. * @param array $settings * The VIS settings. */ protected function createView($path, $settings) { View::create(['label' => 'VIS Test', 'id' => $this->randomMachineName(), 'base_table' => 'node_field_data', 'display' => ['default' => ['display_plugin' => 'default', 'id' => 'default', 'display_options' => ['row' => ['type' => 'entity:node', 'options' => ['view_mode' => 'teaser']], 'pager' => ['type' => 'infinite_scroll', 'options' => ['items_per_page' => 3, 'offset' => 0, 'views_infinite_scroll' => $settings]]]], 'page_1' => ['display_plugin' => 'page', 'id' => 'page_1', 'display_options' => ['path' => $path]]]])->save(); \Drupal::service('router.builder')->rebuild(); }