Core and composer updates
This commit is contained in:
parent
a82634bb98
commit
62cac30480
1118 changed files with 21770 additions and 6306 deletions
|
@ -0,0 +1,79 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: test_area_result
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: views_test_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
defaults:
|
||||
fields: false
|
||||
pager: false
|
||||
sorts: false
|
||||
fields:
|
||||
id:
|
||||
field: id
|
||||
id: id
|
||||
relationship: none
|
||||
table: views_test_data
|
||||
plugin_id: numeric
|
||||
pager:
|
||||
options:
|
||||
offset: 0
|
||||
type: none
|
||||
sorts:
|
||||
id:
|
||||
field: id
|
||||
id: id
|
||||
order: ASC
|
||||
relationship: none
|
||||
table: views_test_data
|
||||
plugin_id: numeric
|
||||
empty:
|
||||
title:
|
||||
field: title
|
||||
id: title
|
||||
table: views
|
||||
plugin_id: title
|
||||
title: test_title_empty
|
||||
header:
|
||||
result:
|
||||
id: result
|
||||
table: views
|
||||
field: result
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: true
|
||||
content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
|
||||
plugin_id: result
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
||||
page_1:
|
||||
display_options:
|
||||
path: test-area-result
|
||||
defaults:
|
||||
header: false
|
||||
header:
|
||||
result:
|
||||
id: result
|
||||
table: views
|
||||
field: result
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: false
|
||||
content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
|
||||
plugin_id: result
|
||||
display_plugin: page
|
||||
display_title: 'Page 1'
|
||||
id: page_1
|
||||
position: 1
|
220
web/core/modules/views/tests/src/Functional/DefaultViewsTest.php
Normal file
220
web/core/modules/views/tests/src/Functional/DefaultViewsTest.php
Normal file
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\comment\CommentInterface;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
|
||||
/**
|
||||
* Tests the default views provided by views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class DefaultViewsTest extends ViewTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
use EntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views', 'node', 'search', 'comment', 'taxonomy', 'block', 'user'];
|
||||
|
||||
/**
|
||||
* An array of argument arrays to use for default views.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $viewArgMap = [
|
||||
'backlinks' => [1],
|
||||
'taxonomy_term' => [1],
|
||||
'glossary' => ['all'],
|
||||
];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
// Create Basic page node type.
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => Unicode::strtolower($this->randomMachineName()),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'help' => '',
|
||||
'nodes' => ['page' => 'page'],
|
||||
'weight' => mt_rand(0, 10),
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
// Create a field.
|
||||
$field_name = Unicode::strtolower($this->randomMachineName());
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$vocabulary->id() => $vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'page', $field_name, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
// Create a time in the past for the archive.
|
||||
$time = REQUEST_TIME - 3600;
|
||||
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
|
||||
for ($i = 0; $i <= 10; $i++) {
|
||||
$user = $this->drupalCreateUser();
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
$values = ['created' => $time, 'type' => 'page'];
|
||||
$values[$field_name][]['target_id'] = $term->id();
|
||||
|
||||
// Make every other node promoted.
|
||||
if ($i % 2) {
|
||||
$values['promote'] = TRUE;
|
||||
}
|
||||
$values['body'][]['value'] = \Drupal::l('Node ' . 1, new Url('entity.node.canonical', ['node' => 1]));
|
||||
|
||||
$node = $this->drupalCreateNode($values);
|
||||
|
||||
$comment = [
|
||||
'uid' => $user->id(),
|
||||
'status' => CommentInterface::PUBLISHED,
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment'
|
||||
];
|
||||
Comment::create($comment)->save();
|
||||
}
|
||||
|
||||
// Some views, such as the "Who's Online" view, only return results if at
|
||||
// least one user is logged in.
|
||||
$account = $this->drupalCreateUser([]);
|
||||
$this->drupalLogin($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all Default views work as expected.
|
||||
*/
|
||||
public function testDefaultViews() {
|
||||
// Get all default views.
|
||||
$controller = $this->container->get('entity.manager')->getStorage('view');
|
||||
$views = $controller->loadMultiple();
|
||||
|
||||
foreach ($views as $name => $view_storage) {
|
||||
$view = $view_storage->getExecutable();
|
||||
$view->initDisplay();
|
||||
foreach ($view->storage->get('display') as $display_id => $display) {
|
||||
$view->setDisplay($display_id);
|
||||
|
||||
// Add any args if needed.
|
||||
if (array_key_exists($name, $this->viewArgMap)) {
|
||||
$view->preExecute($this->viewArgMap[$name]);
|
||||
}
|
||||
|
||||
$this->assert(TRUE, format_string('View @view will be executed.', ['@view' => $view->storage->id()]));
|
||||
$view->execute();
|
||||
|
||||
$tokens = ['@name' => $name, '@display_id' => $display_id];
|
||||
$this->assertTrue($view->executed, format_string('@name:@display_id has been executed.', $tokens));
|
||||
|
||||
$count = count($view->result);
|
||||
$this->assertTrue($count > 0, format_string('@count results returned', ['@count' => $count]));
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new term with random properties in vocabulary $vid.
|
||||
*/
|
||||
public function createTerm($vocabulary) {
|
||||
$filter_formats = filter_formats();
|
||||
$format = array_pop($filter_formats);
|
||||
$term = Term::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
// Use the first available text format.
|
||||
'format' => $format->id(),
|
||||
'vid' => $vocabulary->id(),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
]);
|
||||
$term->save();
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the archive view.
|
||||
*/
|
||||
public function testArchiveView() {
|
||||
// Create additional nodes compared to the one in the setup method.
|
||||
// Create two nodes in the same month, and one in each following month.
|
||||
$node = [
|
||||
'created' => 280299600, // Sun, 19 Nov 1978 05:00:00 GMT
|
||||
];
|
||||
$this->drupalCreateNode($node);
|
||||
$this->drupalCreateNode($node);
|
||||
$node = [
|
||||
'created' => 282891600, // Tue, 19 Dec 1978 05:00:00 GMT
|
||||
];
|
||||
$this->drupalCreateNode($node);
|
||||
$node = [
|
||||
'created' => 285570000, // Fri, 19 Jan 1979 05:00:00 GMT
|
||||
];
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
$view = Views::getView('archive');
|
||||
$view->setDisplay('page_1');
|
||||
$this->executeView($view);
|
||||
$columns = ['nid', 'created_year_month', 'num_records'];
|
||||
$column_map = array_combine($columns, $columns);
|
||||
// Create time of additional nodes created in the setup method.
|
||||
$created_year_month = date('Ym', REQUEST_TIME - 3600);
|
||||
$expected_result = [
|
||||
[
|
||||
'nid' => 1,
|
||||
'created_year_month' => $created_year_month,
|
||||
'num_records' => 11,
|
||||
],
|
||||
[
|
||||
'nid' => 15,
|
||||
'created_year_month' => 197901,
|
||||
'num_records' => 1,
|
||||
],
|
||||
[
|
||||
'nid' => 14,
|
||||
'created_year_month' => 197812,
|
||||
'num_records' => 1,
|
||||
],
|
||||
[
|
||||
'nid' => 12,
|
||||
'created_year_month' => 197811,
|
||||
'num_records' => 2,
|
||||
],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $column_map);
|
||||
|
||||
$view->storage->setStatus(TRUE);
|
||||
$view->save();
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
$this->drupalGet('archive');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Entity;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Tests views base field access.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class BaseFieldAccessTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_entity_test_protected_access'];
|
||||
|
||||
/**
|
||||
* Modules to enable
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'views', 'views_test_config', 'entity_test', 'node', 'views_entity_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
/** @var \Drupal\Core\Entity\EntityDefinitionUpdateManager $update_manager */
|
||||
$update_manager = $this->container->get('entity.definition_update_manager');
|
||||
\Drupal::entityManager()->clearCachedDefinitions();
|
||||
$update_manager->applyUpdates();
|
||||
ViewTestData::createTestViews(get_class($this), ['comment_test_views']);
|
||||
\Drupal::state()->set('entity_test.views_data', [
|
||||
'entity_test' => [
|
||||
'test_text_access' => [
|
||||
'field' => [
|
||||
'id' => 'standard',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity_1 = EntityTest::create([
|
||||
'test_text_access' => 'no access value',
|
||||
]);
|
||||
$entity_1->save();
|
||||
$entity_2 = EntityTest::create([
|
||||
'test_text_access' => 'ok to see this one',
|
||||
]);
|
||||
$entity_2->save();
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test access to protected base fields.
|
||||
*/
|
||||
public function testProtectedField() {
|
||||
$this->drupalGet('test-entity-protected-access');
|
||||
$this->assertText('ok to see this one');
|
||||
$this->assertNoText('no access value');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Entity;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
|
||||
/**
|
||||
* Tests the field plugin base integration with the entity system.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FieldEntityTest extends ViewTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_field_get_entity'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'comment'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(FALSE);
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the getEntity method.
|
||||
*/
|
||||
public function testGetEntity() {
|
||||
// The view is a view of comments, their nodes and their authors, so there
|
||||
// are three layers of entities.
|
||||
|
||||
$account = User::create(['name' => $this->randomMachineName(), 'bundle' => 'user']);
|
||||
$account->save();
|
||||
|
||||
$node = Node::create([
|
||||
'uid' => $account->id(),
|
||||
'type' => 'page',
|
||||
'title' => $this->randomString(),
|
||||
]);
|
||||
$node->save();
|
||||
$comment = Comment::create([
|
||||
'uid' => $account->id(),
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment'
|
||||
]);
|
||||
$comment->save();
|
||||
|
||||
$user = $this->drupalCreateUser(['access comments']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$view = Views::getView('test_field_get_entity');
|
||||
$this->executeView($view);
|
||||
$row = $view->result[0];
|
||||
|
||||
// Tests entities on the base level.
|
||||
$entity = $view->field['cid']->getEntity($row);
|
||||
$this->assertEqual($entity->id(), $comment->id(), 'Make sure the right comment entity got loaded.');
|
||||
// Tests entities as relationship on first level.
|
||||
$entity = $view->field['nid']->getEntity($row);
|
||||
$this->assertEqual($entity->id(), $node->id(), 'Make sure the right node entity got loaded.');
|
||||
// Tests entities as relationships on second level.
|
||||
$entity = $view->field['uid']->getEntity($row);
|
||||
$this->assertEqual($entity->id(), $account->id(), 'Make sure the right user entity got loaded.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Entity;
|
||||
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Symfony\Component\CssSelector\CssSelectorConverter;
|
||||
|
||||
/**
|
||||
* Tests the rendering of fields (base fields) and their translations.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FieldEntityTranslationTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language', 'locale', 'content_translation', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_entity_field_renderers'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'article',
|
||||
'label' => 'Article',
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
/** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
|
||||
$content_translation_manager = \Drupal::service('content_translation.manager');
|
||||
|
||||
$content_translation_manager->setEnabled('node', 'article', TRUE);
|
||||
|
||||
$language = ConfigurableLanguage::create([
|
||||
'id' => 'es',
|
||||
'label' => 'Spanish',
|
||||
]);
|
||||
$language->save();
|
||||
// Rebuild the container to setup the language path processors.
|
||||
$this->rebuildContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that different translation mechanisms can be used for base fields.
|
||||
*/
|
||||
public function testTranslationRows() {
|
||||
$node = Node::create([
|
||||
'type' => 'article',
|
||||
'title' => 'example EN',
|
||||
'sticky' => FALSE,
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$translation = $node->addTranslation('es');
|
||||
$translation->title->value = 'example ES';
|
||||
$translation->sticky->value = TRUE;
|
||||
$translation->save();
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/entity_translation');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
[
|
||||
'title' => 'example ES',
|
||||
'sticky' => 'On',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/entity_default');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/site_default');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/language_interface');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/language_interface', ['language' => new Language(['id' => 'es'])]);
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example ES',
|
||||
'sticky' => 'On',
|
||||
],
|
||||
[
|
||||
'title' => 'example ES',
|
||||
'sticky' => 'On',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/en');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
[
|
||||
'title' => 'example EN',
|
||||
'sticky' => 'Off',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('test_entity_field_renderers/es');
|
||||
$this->assertRows([
|
||||
[
|
||||
'title' => 'example ES',
|
||||
'sticky' => 'On',
|
||||
],
|
||||
[
|
||||
'title' => 'example ES',
|
||||
'sticky' => 'On',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the rendered results are working as expected.
|
||||
*
|
||||
* @param array $expected
|
||||
* The expected rows of the result.
|
||||
*/
|
||||
protected function assertRows($expected = []) {
|
||||
$actual = [];
|
||||
$rows = $this->cssSelect('div.views-row');
|
||||
foreach ($rows as $row) {
|
||||
$actual[] = [
|
||||
'title' => $row->find('xpath', (new CssSelectorConverter())->toXPath('.views-field-title span.field-content a'))->getText(),
|
||||
'sticky' => $row->find('xpath', (new CssSelectorConverter())->toXPath('.views-field-sticky span.field-content'))->getText(),
|
||||
];
|
||||
}
|
||||
$this->assertEqual($actual, $expected);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Entity;
|
||||
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the generic entity bundle filter.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FilterEntityBundleTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_entity_type_filter'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Entity bundle data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $entityBundles;
|
||||
|
||||
/**
|
||||
* An array of entities.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $entities = [];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(FALSE);
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'test_bundle']);
|
||||
$this->drupalCreateContentType(['type' => 'test_bundle_2']);
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
|
||||
|
||||
$this->entityBundles = $this->container->get('entity_type.bundle.info')->getBundleInfo('node');
|
||||
|
||||
$this->entities['count'] = 0;
|
||||
|
||||
foreach ($this->entityBundles as $key => $info) {
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$entity = Node::create([
|
||||
'title' => $this->randomString(),
|
||||
'uid' => 1,
|
||||
'type' => $key,
|
||||
]);
|
||||
$entity->save();
|
||||
$this->entities[$key][$entity->id()] = $entity;
|
||||
$this->entities['count']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the generic bundle filter.
|
||||
*/
|
||||
public function testFilterEntity() {
|
||||
$view = Views::getView('test_entity_type_filter');
|
||||
|
||||
// Tests \Drupal\views\Plugin\views\filter\Bundle::calculateDependencies().
|
||||
$expected = [
|
||||
'config' => [
|
||||
'node.type.test_bundle',
|
||||
'node.type.test_bundle_2',
|
||||
],
|
||||
'module' => [
|
||||
'node'
|
||||
],
|
||||
];
|
||||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Test we have all the results, with all types selected.
|
||||
$this->assertEqual(count($view->result), $this->entities['count']);
|
||||
|
||||
// Test the valueOptions of the filter handler.
|
||||
$expected = [];
|
||||
|
||||
foreach ($this->entityBundles as $key => $info) {
|
||||
$expected[$key] = $info['label'];
|
||||
}
|
||||
$this->assertIdentical($view->filter['type']->getValueOptions(), $expected);
|
||||
|
||||
$view->destroy();
|
||||
|
||||
// Test each bundle type.
|
||||
foreach ($this->entityBundles as $key => $info) {
|
||||
// Test each bundle type.
|
||||
$view->initDisplay();
|
||||
$filters = $view->display_handler->getOption('filters');
|
||||
$filters['type']['value'] = [$key => $key];
|
||||
$view->display_handler->setOption('filters', $filters);
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(count($view->result), count($this->entities[$key]));
|
||||
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
// Test an invalid bundle type to make sure we have no results.
|
||||
$view->initDisplay();
|
||||
$filters = $view->display_handler->getOption('filters');
|
||||
$filters['type']['value'] = ['type_3' => 'type_3'];
|
||||
$view->display_handler->setOption('filters', $filters);
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(count($view->result), 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Entity;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language_test\Entity\NoLanguageEntityTest;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the view creation of non-translatable entities.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewNonTranslatableEntityTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'entity_test',
|
||||
'content_translation',
|
||||
'language_test',
|
||||
'views_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests displaying a view of non-translatable entities.
|
||||
*/
|
||||
public function testViewNoTranslatableEntity() {
|
||||
// Add a new language.
|
||||
ConfigurableLanguage::createFromLangcode('sr')->save();
|
||||
|
||||
// Create a non-translatable entity.
|
||||
$no_language_entity = NoLanguageEntityTest::create();
|
||||
$no_language_entity->save();
|
||||
|
||||
// Visit the view page and assert it is displayed properly.
|
||||
$this->drupalGet('no-entity-translation-view');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('No Entity Translation View');
|
||||
$this->assertText($no_language_entity->uuid());
|
||||
}
|
||||
|
||||
}
|
124
web/core/modules/views/tests/src/Functional/GlossaryTest.php
Normal file
124
web/core/modules/views/tests/src/Functional/GlossaryTest.php
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Tests\AssertViewsCacheTagsTrait;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests glossary functionality of views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class GlossaryTest extends ViewTestBase {
|
||||
|
||||
use AssertViewsCacheTagsTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Tests the default glossary view.
|
||||
*/
|
||||
public function testGlossaryView() {
|
||||
// Create a content type and add some nodes, with a non-random title.
|
||||
$type = $this->drupalCreateContentType();
|
||||
$nodes_per_char = [
|
||||
'd' => 1,
|
||||
'r' => 4,
|
||||
'u' => 10,
|
||||
'p' => 2,
|
||||
'a' => 3,
|
||||
'l' => 6,
|
||||
];
|
||||
$nodes_by_char = [];
|
||||
foreach ($nodes_per_char as $char => $count) {
|
||||
$setting = [
|
||||
'type' => $type->id()
|
||||
];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$node = $setting;
|
||||
$node['title'] = $char . $this->randomString(3);
|
||||
$node = $this->drupalCreateNode($node);
|
||||
$nodes_by_char[$char][] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute glossary view
|
||||
$view = Views::getView('glossary');
|
||||
$view->setDisplay('attachment_1');
|
||||
$view->executeDisplay('attachment_1');
|
||||
|
||||
// Check that the amount of nodes per char.
|
||||
foreach ($view->result as $item) {
|
||||
$this->assertEqual($nodes_per_char[$item->title_truncated], $item->num_records);
|
||||
}
|
||||
|
||||
// Enable the glossary to be displayed.
|
||||
$view->storage->enable()->save();
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
$url = Url::fromRoute('view.glossary.page_1');
|
||||
|
||||
// Verify cache tags.
|
||||
$this->assertPageCacheContextsAndTags(
|
||||
$url,
|
||||
[
|
||||
'timezone',
|
||||
'languages:' . LanguageInterface::TYPE_CONTENT,
|
||||
'languages:' . LanguageInterface::TYPE_INTERFACE,
|
||||
'theme',
|
||||
'url',
|
||||
'user.node_grants:view',
|
||||
'user.permissions',
|
||||
'route',
|
||||
],
|
||||
[
|
||||
'config:views.view.glossary',
|
||||
// Listed for letter 'a'
|
||||
'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
|
||||
// Link for letter 'd'.
|
||||
'node:1',
|
||||
// Link for letter 'p'.
|
||||
'node:16',
|
||||
// Link for letter 'r'.
|
||||
'node:2',
|
||||
// Link for letter 'l'.
|
||||
'node:21',
|
||||
// Link for letter 'u'.
|
||||
'node:6',
|
||||
'node_list',
|
||||
'user:0',
|
||||
'user_list',
|
||||
'http_response',
|
||||
'rendered',
|
||||
// FinishResponseSubscriber adds this cache tag to responses that have
|
||||
// the 'user.permissions' cache context for anonymous users.
|
||||
'config:user.role.anonymous',
|
||||
]
|
||||
);
|
||||
|
||||
// Check the actual page response.
|
||||
$this->drupalGet($url);
|
||||
$this->assertResponse(200);
|
||||
foreach ($nodes_per_char as $char => $count) {
|
||||
$href = Url::fromRoute('view.glossary.page_1', ['arg_0' => $char])->toString();
|
||||
$label = Unicode::strtoupper($char);
|
||||
// Get the summary link for a certain character. Filter by label and href
|
||||
// to ensure that both of them are correct.
|
||||
$result = $this->xpath('//a[contains(@href, :href) and normalize-space(text())=:label]/..', [':href' => $href, ':label' => $label]);
|
||||
$this->assertTrue(count($result));
|
||||
// The rendered output looks like "<a href=''>X</a> | (count)" so let's
|
||||
// figure out the int.
|
||||
$result_count = explode(' ', trim(str_replace(['|', '(', ')'], '', $result[0]->getText())))[1];
|
||||
$this->assertEqual($result_count, $count, 'The expected number got rendered.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the http_status_code area handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\area\HTTPStatusCode
|
||||
*/
|
||||
class AreaHTTPStatusCodeTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_http_status_code'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Tests the area handler.
|
||||
*/
|
||||
public function testHTTPStatusCodeHandler() {
|
||||
$this->drupalGet('test-http-status-code');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Change the HTTP status code to 418.
|
||||
$view = Views::getView('test_http_status_code');
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['empty']['http_status_code']['status_code'] = 418;
|
||||
$view->save();
|
||||
|
||||
// Test that the HTTP response is "I'm a teapot".
|
||||
$this->drupalGet('test-http-status-code');
|
||||
$this->assertResponse(418);
|
||||
}
|
||||
|
||||
}
|
217
web/core/modules/views/tests/src/Functional/Handler/AreaTest.php
Normal file
217
web/core/modules/views/tests/src/Functional/Handler/AreaTest.php
Normal file
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the plugin base of the area handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\area\AreaPluginBase
|
||||
* @see \Drupal\views_test\Plugin\views\area\TestExample
|
||||
*/
|
||||
class AreaTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_example_area', 'test_example_area_access'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views']['test_example'] = [
|
||||
'title' => 'Test Example area',
|
||||
'help' => 'A area handler which just exists for tests.',
|
||||
'area' => [
|
||||
'id' => 'test_example'
|
||||
]
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the generic UI of a area handler.
|
||||
*/
|
||||
public function testUI() {
|
||||
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$types = ['header', 'footer', 'empty'];
|
||||
$labels = [];
|
||||
foreach ($types as $type) {
|
||||
$edit_path = 'admin/structure/views/nojs/handler/test_example_area/default/' . $type . '/test_example';
|
||||
|
||||
// First setup an empty label.
|
||||
$this->drupalPostForm($edit_path, [], t('Apply'));
|
||||
$this->assertText('Test Example area');
|
||||
|
||||
// Then setup a no empty label.
|
||||
$labels[$type] = $this->randomMachineName();
|
||||
$this->drupalPostForm($edit_path, ['options[admin_label]' => $labels[$type]], t('Apply'));
|
||||
// Make sure that the new label appears on the site.
|
||||
$this->assertText($labels[$type]);
|
||||
|
||||
// Test that the settings (empty/admin_label) are accessible.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertField('options[admin_label]');
|
||||
if ($type !== 'empty') {
|
||||
$this->assertField('options[empty]');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the rendering of an area.
|
||||
*/
|
||||
public function testRenderArea() {
|
||||
$view = Views::getView('test_example_area');
|
||||
$view->initHandlers();
|
||||
|
||||
// Insert a random string with XSS injection in the test area plugin.
|
||||
// Ensure that the string is rendered for the header, footer, and empty
|
||||
// text with the markup properly escaped.
|
||||
$header_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
|
||||
$footer_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
|
||||
$empty_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
|
||||
|
||||
$view->header['test_example']->options['string'] = $header_string;
|
||||
$view->header['test_example']->options['empty'] = TRUE;
|
||||
|
||||
$view->footer['test_example']->options['string'] = $footer_string;
|
||||
$view->footer['test_example']->options['empty'] = TRUE;
|
||||
|
||||
$view->empty['test_example']->options['string'] = $empty_string;
|
||||
|
||||
// Check whether the strings exist in the output and are sanitized.
|
||||
$output = $view->preview();
|
||||
$output = $this->container->get('renderer')->renderRoot($output);
|
||||
$this->assertTrue(strpos($output, Xss::filterAdmin($header_string)) !== FALSE, 'Views header exists in the output and is sanitized');
|
||||
$this->assertTrue(strpos($output, Xss::filterAdmin($footer_string)) !== FALSE, 'Views footer exists in the output and is sanitized');
|
||||
$this->assertTrue(strpos($output, Xss::filterAdmin($empty_string)) !== FALSE, 'Views empty exists in the output and is sanitized');
|
||||
$this->assertTrue(strpos($output, '<script') === FALSE, 'Script tags were escaped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the access for an area.
|
||||
*/
|
||||
public function testAreaAccess() {
|
||||
// Test with access denied for the area handler.
|
||||
$view = Views::getView('test_example_area_access');
|
||||
$view->initDisplay();
|
||||
$view->initHandlers();
|
||||
$handlers = $view->display_handler->getHandlers('empty');
|
||||
$this->assertEqual(0, count($handlers));
|
||||
|
||||
$output = $view->preview();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
// The area output should not be present since access was denied.
|
||||
$this->assertFalse(strpos($output, 'a custom string') !== FALSE);
|
||||
$view->destroy();
|
||||
|
||||
// Test with access granted for the area handler.
|
||||
$view = Views::getView('test_example_area_access');
|
||||
$view->initDisplay();
|
||||
$view->display_handler->overrideOption('empty', [
|
||||
'test_example' => [
|
||||
'field' => 'test_example',
|
||||
'id' => 'test_example',
|
||||
'table' => 'views',
|
||||
'plugin_id' => 'test_example',
|
||||
'string' => 'a custom string',
|
||||
'custom_access' => TRUE,
|
||||
],
|
||||
]);
|
||||
$view->initHandlers();
|
||||
$handlers = $view->display_handler->getHandlers('empty');
|
||||
|
||||
$output = $view->preview();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->assertTrue(strpos($output, 'a custom string') !== FALSE);
|
||||
$this->assertEqual(1, count($handlers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests global tokens.
|
||||
*/
|
||||
public function testRenderAreaToken() {
|
||||
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$view = Views::getView('test_example_area');
|
||||
$view->initHandlers();
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_example_area/default/empty/test_example');
|
||||
|
||||
// Test that the list is token present.
|
||||
$element = $this->xpath('//ul[@class="global-tokens"]');
|
||||
$this->assertTrue($element, 'Token list found on the options form.');
|
||||
|
||||
$empty_handler = &$view->empty['test_example'];
|
||||
|
||||
// Test the list of available tokens.
|
||||
$available = $empty_handler->getAvailableGlobalTokens();
|
||||
foreach (['site', 'view'] as $type) {
|
||||
$this->assertTrue(!empty($available[$type]) && is_array($available[$type]));
|
||||
// Test that each item exists in the list.
|
||||
foreach ($available[$type] as $token => $info) {
|
||||
$this->assertText("[$type:$token]");
|
||||
}
|
||||
}
|
||||
|
||||
// Test the rendered output of a token.
|
||||
$empty_handler->options['string'] = '[site:name]';
|
||||
|
||||
// Test we have the site:name token in the output.
|
||||
$output = $view->preview();
|
||||
$output = $this->container->get('renderer')->renderRoot($output);
|
||||
$expected = \Drupal::token()->replace('[site:name]');
|
||||
$this->assertTrue(strpos($output, $expected) !== FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests overriding the view title using the area title handler.
|
||||
*/
|
||||
public function testTitleArea() {
|
||||
$view = Views::getView('frontpage');
|
||||
$view->initDisplay('page_1');
|
||||
|
||||
// Add the title area handler to the empty area.
|
||||
$view->displayHandlers->get('page_1')->overrideOption('empty', [
|
||||
'title' => [
|
||||
'id' => 'title',
|
||||
'table' => 'views',
|
||||
'field' => 'title',
|
||||
'admin_label' => '',
|
||||
'empty' => '0',
|
||||
'title' => 'Overridden title',
|
||||
'plugin_id' => 'title',
|
||||
],
|
||||
]);
|
||||
|
||||
$view->storage->enable()->save();
|
||||
|
||||
$this->drupalGet('node');
|
||||
$this->assertText('Overridden title', 'Overridden title found.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests the title area handler with a web test.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\area\Title
|
||||
*/
|
||||
class AreaTitleWebTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_area_title'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the title area handler.
|
||||
*/
|
||||
public function testTitleText() {
|
||||
// Confirm that the view has the normal title before making the view return
|
||||
// no result.
|
||||
$this->drupalGet('test-area-title');
|
||||
$this->assertTitle('test_title_header | Drupal');
|
||||
|
||||
// Change the view to return no result.
|
||||
/** @var \Drupal\views\Entity\View $view */
|
||||
$view = View::load('test_area_title');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['name'] = [
|
||||
'field' => 'name',
|
||||
'id' => 'name',
|
||||
'table' => 'views_test_data',
|
||||
'relationship' => 'none',
|
||||
'plugin_id' => 'string',
|
||||
// Add a value which does not exist. The dataset is defined in
|
||||
// \Drupal\views\Tests\ViewTestData::dataSet().
|
||||
'value' => 'Euler',
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-area-title');
|
||||
$this->assertTitle('test_title_empty | Drupal');
|
||||
|
||||
// Change the view to return a result instead.
|
||||
/** @var \Drupal\views\Entity\View $view */
|
||||
$view = View::load('test_area_title');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['name'] = [
|
||||
'field' => 'name',
|
||||
'id' => 'name',
|
||||
'table' => 'views_test_data',
|
||||
'relationship' => 'none',
|
||||
'plugin_id' => 'string',
|
||||
// Change to a value which does exist. The dataset is defined in
|
||||
// \Drupal\views\Tests\ViewTestData::dataSet().
|
||||
'value' => 'Ringo',
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-area-title');
|
||||
$this->assertTitle('test_title_header | Drupal');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the core Drupal\views\Plugin\views\argument\StringArgument handler.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ArgumentStringTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_glossary'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Tests the glossary feature.
|
||||
*/
|
||||
public function testGlossary() {
|
||||
// Setup some nodes, one with a, two with b and three with c.
|
||||
$counter = 1;
|
||||
foreach (['a', 'b', 'c'] as $char) {
|
||||
for ($i = 0; $i < $counter; $i++) {
|
||||
$edit = [
|
||||
'title' => $char . $this->randomMachineName(),
|
||||
];
|
||||
$this->drupalCreateNode($edit);
|
||||
}
|
||||
}
|
||||
|
||||
$view = Views::getView('test_glossary');
|
||||
$this->executeView($view);
|
||||
|
||||
$count_field = 'nid';
|
||||
foreach ($view->result as &$row) {
|
||||
if (strpos($view->field['title']->getValue($row), 'a') === 0) {
|
||||
$this->assertEqual(1, $row->{$count_field});
|
||||
}
|
||||
if (strpos($view->field['title']->getValue($row), 'b') === 0) {
|
||||
$this->assertEqual(2, $row->{$count_field});
|
||||
}
|
||||
if (strpos($view->field['title']->getValue($row), 'c') === 0) {
|
||||
$this->assertEqual(3, $row->{$count_field});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the dropbutton field handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\system\Plugin\views\field\Dropbutton
|
||||
*/
|
||||
class FieldDropButtonTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_dropbutton'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests dropbutton field.
|
||||
*/
|
||||
public function testDropbutton() {
|
||||
// Create some test nodes.
|
||||
$nodes = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$nodes[] = $this->drupalCreateNode();
|
||||
}
|
||||
|
||||
$this->drupalGet('test-dropbutton');
|
||||
foreach ($nodes as $node) {
|
||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', [':path' => '/node/' . $node->id(), ':title' => $node->label()]);
|
||||
$this->assertEqual(count($result), 1, 'Just one node title link was found.');
|
||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', [':path' => '/node/' . $node->id(), ':title' => 'Custom Text']);
|
||||
$this->assertEqual(count($result), 1, 'Just one custom link was found.');
|
||||
}
|
||||
|
||||
// Check if the dropbutton.js library is available.
|
||||
$this->drupalGet('admin/content');
|
||||
$this->assertRaw('dropbutton.js');
|
||||
// Check if the dropbutton.js library is available on a cached page to
|
||||
// ensure that bubbleable metadata is not lost in the views render workflow.
|
||||
$this->drupalGet('admin/content');
|
||||
$this->assertRaw('dropbutton.js');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FieldEntityOperationsTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_entity_operations'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'language', 'views_ui'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create Article content type.
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity operations field.
|
||||
*/
|
||||
public function testEntityOperations() {
|
||||
// Add languages and refresh the container so the entity manager will have
|
||||
// fresh data.
|
||||
ConfigurableLanguage::createFromLangcode('hu')->save();
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Create some test entities. Every other entity is Hungarian while all
|
||||
// have a Spanish translation.
|
||||
$entities = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$entity = Node::create([
|
||||
'title' => $this->randomString(),
|
||||
'type' => 'article',
|
||||
'langcode' => $i % 2 === 0 ? 'hu' : 'en',
|
||||
]);
|
||||
$entity->save();
|
||||
$translation = $entity->addTranslation('es');
|
||||
$translation->set('title', $entity->getTitle() . ' in Spanish');
|
||||
$translation->save();
|
||||
$entities[$i] = $entity;
|
||||
}
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access administration pages', 'administer nodes', 'bypass node access']);
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('test-entity-operations');
|
||||
/** @var $entity \Drupal\entity_test\Entity\EntityTest */
|
||||
foreach ($entities as $entity) {
|
||||
/** @var \Drupal\Core\Language\LanguageInterface $language */
|
||||
foreach ($entity->getTranslationLanguages() as $language) {
|
||||
$entity = $entity->getTranslation($language->getId());
|
||||
$operations = \Drupal::entityManager()->getListBuilder('node')->getOperations($entity);
|
||||
$this->assertTrue(count($operations) > 0, 'There are operations.');
|
||||
foreach ($operations as $operation) {
|
||||
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
|
||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', [':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => (string) $operation['title']]);
|
||||
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', ['@operation' => $operation['title']]));
|
||||
// Entities which were created in Hungarian should link to the Hungarian
|
||||
// edit form, others to the English one (which has no path prefix here).
|
||||
$base_path = \Drupal::request()->getBasePath();
|
||||
$parts = explode('/', str_replace($base_path, '', $operation['url']->toString()));
|
||||
$expected_prefix = ($language->getId() != 'en' ? $language->getId() : 'node');
|
||||
$this->assertEqual($parts[1], $expected_prefix, 'Entity operation links to the correct language for the entity.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that we can't enable click sorting on the operation field.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_entity_operations/page_2/style_options');
|
||||
$this->assertField('style_options[info][title][sortable]');
|
||||
$this->assertNoField('style_options[info][operations][sortable]');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests the "Display all values in the same row" setting.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\field\EntityField
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FieldGroupRowsTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_group_rows', 'test_ungroup_rows'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'field_test'];
|
||||
|
||||
/**
|
||||
* Field that will be created to test the group/ungroup rows functionality
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $fieldName = 'field_group_rows';
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create content type with unlimited text field.
|
||||
$node_type = $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
// Create the unlimited text field.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'text',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
// Create an instance of the text field on the content type.
|
||||
$field = [
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => $node_type->id(),
|
||||
];
|
||||
FieldConfig::create($field)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the "Grouped rows" functionality.
|
||||
*/
|
||||
public function testGroupRows() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$edit = [
|
||||
'title' => $this->randomMachineName(),
|
||||
$this->fieldName => ['a', 'b', 'c'],
|
||||
];
|
||||
$this->drupalCreateNode($edit);
|
||||
|
||||
$view = Views::getView('test_group_rows');
|
||||
|
||||
// Test grouped rows.
|
||||
$this->executeView($view);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertEqual($output, 'a, b, c');
|
||||
|
||||
// Change the group_rows checkbox to false.
|
||||
$view = Views::getView('test_group_rows');
|
||||
$view->setHandlerOption('default', 'field', $this->fieldName, 'group_rows', FALSE);
|
||||
|
||||
// Test ungrouped rows.
|
||||
$this->executeView($view);
|
||||
$view->render();
|
||||
|
||||
$view->row_index = 0;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertEqual($output, 'a');
|
||||
$view->row_index = 1;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[1]);
|
||||
});
|
||||
$this->assertEqual($output, 'b');
|
||||
$view->row_index = 2;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[2]);
|
||||
});
|
||||
$this->assertEqual($output, 'c');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the "Display all values in the same row" setting.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FieldGroupRowsWebTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_group_rows', 'test_ungroup_rows'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* The page node type.
|
||||
*
|
||||
* @var \Drupal\node\NodeTypeInterface
|
||||
*/
|
||||
protected $nodeType;
|
||||
|
||||
/**
|
||||
* The used field name in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* The field storage.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
/**
|
||||
* The field config.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldConfig
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create content type with unlimited text field.
|
||||
$this->nodeType = $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
// Create the unlimited text field.
|
||||
$this->fieldName = 'field_views_testing_group_rows';
|
||||
$this->fieldStorage = FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'text',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
]);
|
||||
$this->fieldStorage->save();
|
||||
|
||||
// Create an instance of the text field on the content type.
|
||||
$this->field = FieldConfig::create([
|
||||
'field_storage' => $this->fieldStorage,
|
||||
'bundle' => $this->nodeType->id(),
|
||||
]);
|
||||
$this->field->save();
|
||||
|
||||
$edit = [
|
||||
'title' => $this->randomMachineName(),
|
||||
$this->fieldName => ['a', 'b', 'c'],
|
||||
];
|
||||
$this->drupalCreateNode($edit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing when "Display all values in the same row" is checked.
|
||||
*/
|
||||
public function testGroupRows() {
|
||||
$this->drupalGet('test-group-rows');
|
||||
$result = $this->cssSelect('div.views-field-field-views-testing-group- div');
|
||||
|
||||
$rendered_value = [];
|
||||
foreach ($result as $row) {
|
||||
$rendered_value[] = $row->getText();
|
||||
}
|
||||
$this->assertEqual(['a, b, c'], $rendered_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing when "Display all values in the same row" is unchecked.
|
||||
*/
|
||||
public function testUngroupedRows() {
|
||||
$this->drupalGet('test-ungroup-rows');
|
||||
$result = $this->cssSelect('div.views-field-field-views-testing-group- div');
|
||||
$rendered_value = [];
|
||||
foreach ($result as $row) {
|
||||
$rendered_value[] = $row->getText();
|
||||
}
|
||||
$this->assertEqual(['a', 'b', 'c'], $rendered_value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,656 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests fields from within a UI.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\field\FieldPluginBase
|
||||
*/
|
||||
class FieldWebTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view', 'test_field_classes', 'test_field_output', 'test_click_sort'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Maps between the key in the expected result and the query result.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $columnMap = [
|
||||
'views_test_data_name' => 'name',
|
||||
];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views_test_data']['job']['field']['id'] = 'test_field';
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the click sorting functionality.
|
||||
*/
|
||||
public function testClickSorting() {
|
||||
$this->drupalGet('test_click_sort');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Only the id and name should be click sortable, but not the name.
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'asc']]));
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'name', 'sort' => 'desc']]));
|
||||
$this->assertNoLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'created']]));
|
||||
|
||||
// Check that the view returns the click sorting cache contexts.
|
||||
$expected_contexts = [
|
||||
'languages:language_interface',
|
||||
'theme',
|
||||
'url.query_args',
|
||||
];
|
||||
$this->assertCacheContexts($expected_contexts);
|
||||
|
||||
// Clicking a click sort should change the order.
|
||||
$this->clickLink(t('ID'));
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'desc']]));
|
||||
// Check that the output has the expected order (asc).
|
||||
$ids = $this->clickSortLoadIdsFromOutput();
|
||||
$this->assertEqual($ids, range(1, 5));
|
||||
|
||||
$this->clickLink(t('ID Sort descending'));
|
||||
// Check that the output has the expected order (desc).
|
||||
$ids = $this->clickSortLoadIdsFromOutput();
|
||||
$this->assertEqual($ids, range(5, 1, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Small helper function to get all ids in the output.
|
||||
*
|
||||
* @return array
|
||||
* A list of beatle ids.
|
||||
*/
|
||||
protected function clickSortLoadIdsFromOutput() {
|
||||
$fields = $this->xpath("//td[contains(@class, 'views-field-id')]");
|
||||
$ids = [];
|
||||
foreach ($fields as $field) {
|
||||
$ids[] = (int) $field->getText();
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertion helper which checks whether a string is part of another string.
|
||||
*
|
||||
* @param string $haystack
|
||||
* The value to search in.
|
||||
* @param string $needle
|
||||
* The value to search for.
|
||||
* @param string $message
|
||||
* The message to display along with the assertion.
|
||||
* @param string $group
|
||||
* The type of assertion - examples are "Browser", "PHP".
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertSubString($haystack, $needle, $message = '', $group = 'Other') {
|
||||
return $this->assertTrue(strpos($haystack, $needle) !== FALSE, $message, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertion helper which checks whether a string is not part of another string.
|
||||
*
|
||||
* @param string $haystack
|
||||
* The value to search in.
|
||||
* @param string $needle
|
||||
* The value to search for.
|
||||
* @param string $message
|
||||
* The message to display along with the assertion.
|
||||
* @param string $group
|
||||
* The type of assertion - examples are "Browser", "PHP".
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertNotSubString($haystack, $needle, $message = '', $group = 'Other') {
|
||||
return $this->assertTrue(strpos($haystack, $needle) === FALSE, $message, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a content and return the html element.
|
||||
*
|
||||
* @param string $content
|
||||
* The html to parse.
|
||||
*
|
||||
* @return array
|
||||
* An array containing simplexml objects.
|
||||
*/
|
||||
protected function parseContent($content) {
|
||||
$htmlDom = new \DOMDocument();
|
||||
@$htmlDom->loadHTML('<?xml encoding="UTF-8">' . $content);
|
||||
$elements = simplexml_import_dom($htmlDom);
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an xpath search on a certain content.
|
||||
*
|
||||
* The search is relative to the root element of the $content variable.
|
||||
*
|
||||
* @param string $content
|
||||
* The html to parse.
|
||||
* @param string $xpath
|
||||
* The xpath string to use in the search.
|
||||
* @param array $arguments
|
||||
* Some arguments for the xpath.
|
||||
*
|
||||
* @return array|false
|
||||
* The return value of the xpath search. For details on the xpath string
|
||||
* format and return values see the SimpleXML documentation,
|
||||
* http://php.net/manual/function.simplexml-element-xpath.php.
|
||||
*/
|
||||
protected function xpathContent($content, $xpath, array $arguments = []) {
|
||||
if ($elements = $this->parseContent($content)) {
|
||||
$xpath = $this->buildXPathQuery($xpath, $arguments);
|
||||
$result = $elements->xpath($xpath);
|
||||
// Some combinations of PHP / libxml versions return an empty array
|
||||
// instead of the documented FALSE. Forcefully convert any falsish values
|
||||
// to an empty array to allow foreach(...) constructions.
|
||||
return $result ? $result : [];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rewriting the output to a link.
|
||||
*/
|
||||
public function testAlterUrl() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
$view->initHandlers();
|
||||
$this->executeView($view);
|
||||
$row = $view->result[0];
|
||||
$id_field = $view->field['id'];
|
||||
|
||||
// Setup the general settings required to build a link.
|
||||
$id_field->options['alter']['make_link'] = TRUE;
|
||||
$id_field->options['alter']['path'] = $path = $this->randomMachineName();
|
||||
|
||||
// Tests that the suffix/prefix appears on the output.
|
||||
$id_field->options['alter']['prefix'] = $prefix = $this->randomMachineName();
|
||||
$id_field->options['alter']['suffix'] = $suffix = $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $prefix);
|
||||
$this->assertSubString($output, $suffix);
|
||||
unset($id_field->options['alter']['prefix']);
|
||||
unset($id_field->options['alter']['suffix']);
|
||||
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $path, 'Make sure that the path is part of the output');
|
||||
|
||||
// Some generic test code adapted from the UrlTest class, which tests
|
||||
// mostly the different options for the path.
|
||||
foreach ([FALSE, TRUE] as $absolute) {
|
||||
$alter = &$id_field->options['alter'];
|
||||
$alter['path'] = 'node/123';
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['absolute' => $absolute]);
|
||||
$alter['absolute'] = $absolute;
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['fragment' => 'foo', 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123#foo';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123?foo';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => 'bar', 'bar' => 'baz'], 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123?foo=bar&bar=baz';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
|
||||
|
||||
// @todo The route-based URL generator strips out NULL attributes.
|
||||
// $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute]);
|
||||
$expected_result = Url::fromUserInput('/node/123', ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute])->toString();
|
||||
$alter['path'] = 'node/123?foo#bar';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
|
||||
|
||||
$expected_result = \Drupal::url('<front>', [], ['absolute' => $absolute]);
|
||||
$alter['path'] = '<front>';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
}
|
||||
|
||||
// Tests the replace spaces with dashes feature.
|
||||
$id_field->options['alter']['replace_spaces'] = TRUE;
|
||||
$id_field->options['alter']['path'] = $path = $this->randomMachineName() . ' ' . $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, str_replace(' ', '-', $path));
|
||||
$id_field->options['alter']['replace_spaces'] = FALSE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
// The url has a space in it, so to check we have to decode the url output.
|
||||
$this->assertSubString(urldecode($output), $path);
|
||||
|
||||
// Tests the external flag.
|
||||
// Switch on the external flag should output an external url as well.
|
||||
$id_field->options['alter']['external'] = TRUE;
|
||||
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, 'http://www.drupal.org');
|
||||
|
||||
// Setup a not external url, which shouldn't lead to an external url.
|
||||
$id_field->options['alter']['external'] = FALSE;
|
||||
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertNotSubString($output, 'http://www.drupal.org');
|
||||
|
||||
// Tests the transforming of the case setting.
|
||||
$id_field->options['alter']['path'] = $path = $this->randomMachineName();
|
||||
$id_field->options['alter']['path_case'] = 'none';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $path);
|
||||
|
||||
// Switch to uppercase and lowercase.
|
||||
$id_field->options['alter']['path_case'] = 'upper';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, strtoupper($path));
|
||||
$id_field->options['alter']['path_case'] = 'lower';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, strtolower($path));
|
||||
|
||||
// Switch to ucfirst and ucwords.
|
||||
$id_field->options['alter']['path_case'] = 'ucfirst';
|
||||
$id_field->options['alter']['path'] = 'drupal has a great community';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, UrlHelper::encodePath('Drupal has a great community'));
|
||||
|
||||
$id_field->options['alter']['path_case'] = 'ucwords';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, UrlHelper::encodePath('Drupal Has A Great Community'));
|
||||
unset($id_field->options['alter']['path_case']);
|
||||
|
||||
// Tests the linkclass setting and see whether it actually exists in the
|
||||
// output.
|
||||
$id_field->options['alter']['link_class'] = $class = $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@class, :class)]', [':class' => $class]);
|
||||
$this->assertTrue($elements);
|
||||
// @fixme link_class, alt, rel cannot be unset, which should be fixed.
|
||||
$id_field->options['alter']['link_class'] = '';
|
||||
|
||||
// Tests the alt setting.
|
||||
$id_field->options['alter']['alt'] = $rel = $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@title, :alt)]', [':alt' => $rel]);
|
||||
$this->assertTrue($elements);
|
||||
$id_field->options['alter']['alt'] = '';
|
||||
|
||||
// Tests the rel setting.
|
||||
$id_field->options['alter']['rel'] = $rel = $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@rel, :rel)]', [':rel' => $rel]);
|
||||
$this->assertTrue($elements);
|
||||
$id_field->options['alter']['rel'] = '';
|
||||
|
||||
// Tests the target setting.
|
||||
$id_field->options['alter']['target'] = $target = $this->randomMachineName();
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@target, :target)]', [':target' => $target]);
|
||||
$this->assertTrue($elements);
|
||||
unset($id_field->options['alter']['target']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the field/label/wrapper classes.
|
||||
*/
|
||||
public function testFieldClasses() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$view = Views::getView('test_field_classes');
|
||||
$view->initHandlers();
|
||||
|
||||
// Tests whether the default field classes are added.
|
||||
$id_field = $view->field['id'];
|
||||
|
||||
$id_field->options['element_default_classes'] = FALSE;
|
||||
// Setup some kind of label by default.
|
||||
$id_field->options['label'] = $this->randomMachineName();
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'field-content']));
|
||||
$this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'field__label']));
|
||||
|
||||
$id_field->options['element_default_classes'] = TRUE;
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
// Per default the label and the element of the field are spans.
|
||||
$this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', [':class' => 'field-content']));
|
||||
$this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', [':class' => 'views-label']));
|
||||
$this->assertTrue($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'views-field']));
|
||||
|
||||
// Tests the element wrapper classes/element.
|
||||
$random_class = $this->randomMachineName();
|
||||
|
||||
// Set some common wrapper element types and see whether they appear with and without a custom class set.
|
||||
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
|
||||
$id_field->options['element_wrapper_type'] = $element_type;
|
||||
|
||||
// Set a custom wrapper element css class.
|
||||
$id_field->options['element_wrapper_class'] = $random_class;
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertTrue($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
|
||||
// Set no custom css class.
|
||||
$id_field->options['element_wrapper_class'] = '';
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertFalse($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]/{$element_type}"));
|
||||
}
|
||||
|
||||
// Tests the label class/element.
|
||||
|
||||
// Set some common label element types and see whether they appear with and without a custom class set.
|
||||
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
|
||||
$id_field->options['element_label_type'] = $element_type;
|
||||
|
||||
// Set a custom label element css class.
|
||||
$id_field->options['element_label_class'] = $random_class;
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
|
||||
// Set no custom css class.
|
||||
$id_field->options['element_label_class'] = '';
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}"));
|
||||
}
|
||||
|
||||
// Tests the element classes/element.
|
||||
|
||||
// Set some common element element types and see whether they appear with and without a custom class set.
|
||||
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
|
||||
$id_field->options['element_type'] = $element_type;
|
||||
|
||||
// Set a custom label element css class.
|
||||
$id_field->options['element_class'] = $random_class;
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
|
||||
// Set no custom css class.
|
||||
$id_field->options['element_class'] = '';
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
|
||||
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}"));
|
||||
}
|
||||
|
||||
// Tests the available html elements.
|
||||
$element_types = $id_field->getElements();
|
||||
$expected_elements = [
|
||||
'',
|
||||
0,
|
||||
'div',
|
||||
'span',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'p',
|
||||
'strong',
|
||||
'em',
|
||||
'marquee'
|
||||
];
|
||||
|
||||
$this->assertEqual(array_keys($element_types), $expected_elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests trimming/read-more/ellipses.
|
||||
*/
|
||||
public function testTextRendering() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_field_output');
|
||||
$view->initHandlers();
|
||||
$name_field = $view->field['name'];
|
||||
|
||||
// Tests stripping of html elements.
|
||||
$this->executeView($view);
|
||||
$random_text = $this->randomMachineName();
|
||||
$name_field->options['alter']['alter_text'] = TRUE;
|
||||
$name_field->options['alter']['text'] = $html_text = '<div class="views-test">' . $random_text . '</div>';
|
||||
$row = $view->result[0];
|
||||
|
||||
$name_field->options['alter']['strip_tags'] = TRUE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled.');
|
||||
$this->assertNotSubString($output, $html_text, 'Find no text with the html if stripping of views field output is enabled.');
|
||||
|
||||
// Tests preserving of html tags.
|
||||
$name_field->options['alter']['preserve_tags'] = '<div>';
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled but a div is allowed.');
|
||||
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is enabled but a div is allowed.');
|
||||
|
||||
$name_field->options['alter']['strip_tags'] = FALSE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is disabled.');
|
||||
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is disabled.');
|
||||
|
||||
// Tests for removing whitespace and the beginning and the end.
|
||||
$name_field->options['alter']['alter_text'] = FALSE;
|
||||
$views_test_data_name = $row->views_test_data_name;
|
||||
$row->views_test_data_name = ' ' . $views_test_data_name . ' ';
|
||||
$name_field->options['alter']['trim_whitespace'] = TRUE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
|
||||
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is enabled.');
|
||||
$this->assertNotSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is enabled.');
|
||||
|
||||
$name_field->options['alter']['trim_whitespace'] = FALSE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is disabled.');
|
||||
$this->assertSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is disabled.');
|
||||
|
||||
// Tests for trimming to a maximum length.
|
||||
$name_field->options['alter']['trim'] = TRUE;
|
||||
$name_field->options['alter']['word_boundary'] = FALSE;
|
||||
|
||||
// Tests for simple trimming by string length.
|
||||
$row->views_test_data_name = $this->randomMachineName(8);
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
$trimmed_name = Unicode::substr($row->views_test_data_name, 0, 5);
|
||||
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (@trimmed) appears in the rendered output (@output).', ['@trimmed' => $trimmed_name, '@output' => $output]));
|
||||
$this->assertNotSubString($output, $row->views_test_data_name, format_string("Make sure the untrimmed value (@untrimmed) shouldn't appear in the rendered output (@output).", ['@untrimmed' => $row->views_test_data_name, '@output' => $output]));
|
||||
|
||||
$name_field->options['alter']['max_length'] = 9;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the untrimmed (@untrimmed) output appears in the rendered output (@output).', ['@trimmed' => $trimmed_name, '@output' => $output]));
|
||||
|
||||
// Take word_boundary into account for the tests.
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
$name_field->options['alter']['word_boundary'] = TRUE;
|
||||
$random_text_2 = $this->randomMachineName(2);
|
||||
$random_text_4 = $this->randomMachineName(4);
|
||||
$random_text_8 = $this->randomMachineName(8);
|
||||
$tuples = [
|
||||
// Create one string which doesn't fit at all into the limit.
|
||||
[
|
||||
'value' => $random_text_8,
|
||||
'trimmed_value' => '',
|
||||
'trimmed' => TRUE
|
||||
],
|
||||
// Create one string with two words which doesn't fit both into the limit.
|
||||
[
|
||||
'value' => $random_text_8 . ' ' . $random_text_8,
|
||||
'trimmed_value' => '',
|
||||
'trimmed' => TRUE
|
||||
],
|
||||
// Create one string which contains of two words, of which only the first
|
||||
// fits into the limit.
|
||||
[
|
||||
'value' => $random_text_4 . ' ' . $random_text_8,
|
||||
'trimmed_value' => $random_text_4,
|
||||
'trimmed' => TRUE
|
||||
],
|
||||
// Create one string which contains of two words, of which both fits into
|
||||
// the limit.
|
||||
[
|
||||
'value' => $random_text_2 . ' ' . $random_text_2,
|
||||
'trimmed_value' => $random_text_2 . ' ' . $random_text_2,
|
||||
'trimmed' => FALSE
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($tuples as $tuple) {
|
||||
$row->views_test_data_name = $tuple['value'];
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
|
||||
if ($tuple['trimmed']) {
|
||||
$this->assertNotSubString($output, $tuple['value'], format_string('The untrimmed value (@untrimmed) should not appear in the trimmed output (@output).', ['@untrimmed' => $tuple['value'], '@output' => $output]));
|
||||
}
|
||||
if (!empty($tuple['trimmed_value'])) {
|
||||
$this->assertSubString($output, $tuple['trimmed_value'], format_string('The trimmed value (@trimmed) should appear in the trimmed output (@output).', ['@trimmed' => $tuple['trimmed_value'], '@output' => $output]));
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for displaying a readmore link when the output got trimmed.
|
||||
$row->views_test_data_name = $this->randomMachineName(8);
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
$name_field->options['alter']['more_link'] = TRUE;
|
||||
$name_field->options['alter']['more_link_text'] = $more_text = $this->randomMachineName();
|
||||
$name_field->options['alter']['more_link_path'] = $more_path = $this->randomMachineName();
|
||||
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $more_text, 'Make sure a read more text is displayed if the output got trimmed');
|
||||
$this->assertTrue($this->xpathContent($output, '//a[contains(@href, :path)]', [':path' => $more_path]), 'Make sure the read more link points to the right destination.');
|
||||
|
||||
$name_field->options['alter']['more_link'] = FALSE;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertNotSubString($output, $more_text, 'Make sure no read more text appears.');
|
||||
$this->assertFalse($this->xpathContent($output, '//a[contains(@href, :path)]', [':path' => $more_path]), 'Make sure no read more link appears.');
|
||||
|
||||
// Check for the ellipses.
|
||||
$row->views_test_data_name = $this->randomMachineName(8);
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, '…', 'An ellipsis should appear if the output is trimmed');
|
||||
$name_field->options['alter']['max_length'] = 10;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertNotSubString($output, '…', 'No ellipsis should appear if the output is not trimmed');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\config\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the core Drupal\views\Plugin\views\filter\Date handler.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class FilterDateTest extends ViewTestBase {
|
||||
use SchemaCheckTestTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_filter_date_between'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui', 'datetime'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Add a date field so we can test datetime handling.
|
||||
NodeType::create([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
])->save();
|
||||
|
||||
// Setup a field storage and field, but also change the views data for the
|
||||
// entity_test entity type.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'field_date',
|
||||
'type' => 'datetime',
|
||||
'entity_type' => 'node',
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
$field = FieldConfig::create([
|
||||
'field_name' => 'field_date',
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
// Add some basic test nodes.
|
||||
$this->nodes = [];
|
||||
$this->nodes[] = $this->drupalCreateNode(['created' => 100000, 'field_date' => 10000]);
|
||||
$this->nodes[] = $this->drupalCreateNode(['created' => 200000, 'field_date' => 20000]);
|
||||
$this->nodes[] = $this->drupalCreateNode(['created' => 300000, 'field_date' => 30000]);
|
||||
$this->nodes[] = $this->drupalCreateNode(['created' => time() + 86400, 'field_date' => time() + 86400]);
|
||||
|
||||
$this->map = [
|
||||
'nid' => 'nid',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs other test methods.
|
||||
*/
|
||||
public function testDateFilter() {
|
||||
$this->_testOffset();
|
||||
$this->_testBetween();
|
||||
$this->_testUiValidation();
|
||||
$this->_testFilterDateUI();
|
||||
$this->_testFilterDatetimeUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the general offset functionality.
|
||||
*/
|
||||
protected function _testOffset() {
|
||||
$view = Views::getView('test_filter_date_between');
|
||||
|
||||
// Test offset for simple operator.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = '>';
|
||||
$view->filter['created']->value['type'] = 'offset';
|
||||
$view->filter['created']->value['value'] = '+1 hour';
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[3]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test offset for between operator.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = 'between';
|
||||
$view->filter['created']->value['type'] = 'offset';
|
||||
$view->filter['created']->value['max'] = '+2 days';
|
||||
$view->filter['created']->value['min'] = '+1 hour';
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[3]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the filter operator between/not between.
|
||||
*/
|
||||
protected function _testBetween() {
|
||||
$view = Views::getView('test_filter_date_between');
|
||||
|
||||
// Test between with min and max.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = 'between';
|
||||
$view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
|
||||
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[1]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test between with just max.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = 'between';
|
||||
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[0]->id()],
|
||||
['nid' => $this->nodes[1]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test not between with min and max.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = 'not between';
|
||||
$view->filter['created']->value['min'] = format_date(100000, 'custom', 'Y-m-d H:i:s');
|
||||
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
|
||||
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[2]->id()],
|
||||
['nid' => $this->nodes[3]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test not between with just max.
|
||||
$view->initHandlers();
|
||||
$view->filter['created']->operator = 'not between';
|
||||
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
|
||||
$view->executeDisplay('default');
|
||||
$expected_result = [
|
||||
['nid' => $this->nodes[2]->id()],
|
||||
['nid' => $this->nodes[3]->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the validation callbacks works.
|
||||
*/
|
||||
protected function _testUiValidation() {
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views', 'administer site configuration']));
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/test_filter_date_between/edit');
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
|
||||
|
||||
$edit = [];
|
||||
// Generate a definitive wrong value, which should be checked by validation.
|
||||
$edit['options[value][value]'] = $this->randomString() . '-------';
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->assertText(t('Invalid date format.'), 'Make sure that validation is run and the invalidate date format is identified.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test date filter UI.
|
||||
*/
|
||||
protected function _testFilterDateUI() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views']));
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
|
||||
$this->drupalPostForm(NULL, [], t('Expose filter'));
|
||||
$this->drupalPostForm(NULL, [], t('Grouped filters'));
|
||||
|
||||
$edit = [];
|
||||
$edit['options[group_info][group_items][1][title]'] = 'simple-offset';
|
||||
$edit['options[group_info][group_items][1][operator]'] = '>';
|
||||
$edit['options[group_info][group_items][1][value][type]'] = 'offset';
|
||||
$edit['options[group_info][group_items][1][value][value]'] = '+1 hour';
|
||||
$edit['options[group_info][group_items][2][title]'] = 'between-offset';
|
||||
$edit['options[group_info][group_items][2][operator]'] = 'between';
|
||||
$edit['options[group_info][group_items][2][value][type]'] = 'offset';
|
||||
$edit['options[group_info][group_items][2][value][min]'] = '+1 hour';
|
||||
$edit['options[group_info][group_items][2][value][max]'] = '+2 days';
|
||||
$edit['options[group_info][group_items][3][title]'] = 'between-date';
|
||||
$edit['options[group_info][group_items][3][operator]'] = 'between';
|
||||
$edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
|
||||
$edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
|
||||
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
|
||||
foreach ($edit as $name => $value) {
|
||||
$this->assertFieldByName($name, $value);
|
||||
if (strpos($name, '[value][type]')) {
|
||||
$radio = $this->cssSelect('input[name="' . $name . '"][checked="checked"][type="radio"]');
|
||||
$this->assertEqual($radio[0]->getAttribute('value'), $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
|
||||
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
|
||||
|
||||
// Test that the exposed filter works as expected.
|
||||
$path = 'test_filter_date_between-path';
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between/edit', [], 'Add Page');
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_date_between/page_1/path', ['path' => $path], 'Apply');
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
$this->drupalGet($path);
|
||||
$this->drupalPostForm(NULL, [], 'Apply');
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 4);
|
||||
$this->drupalPostForm(NULL, ['created' => '1'], 'Apply');
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 1);
|
||||
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
|
||||
$this->drupalPostForm(NULL, ['created' => '2'], 'Apply');
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 1);
|
||||
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
|
||||
$this->drupalPostForm(NULL, ['created' => '3'], 'Apply');
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 1);
|
||||
$this->assertEqual($results[0]->getText(), $this->nodes[1]->id());
|
||||
|
||||
// Change the filter to a single filter to test the schema when the operator
|
||||
// is not exposed.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created', [], t('Single filter'));
|
||||
$edit = [];
|
||||
$edit['options[operator]'] = '>';
|
||||
$edit['options[value][type]'] = 'date';
|
||||
$edit['options[value][value]'] = format_date(350000, 'custom', 'Y-m-d H:i:s');
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
|
||||
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
|
||||
|
||||
// Test that the filter works as expected.
|
||||
$this->drupalGet($path);
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 1);
|
||||
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
|
||||
$this->drupalPostForm(NULL, ['created' => format_date(250000, 'custom', 'Y-m-d H:i:s')], 'Apply');
|
||||
$results = $this->cssSelect('.view-content .field-content');
|
||||
$this->assertEqual(count($results), 2);
|
||||
$this->assertEqual($results[0]->getText(), $this->nodes[2]->id());
|
||||
$this->assertEqual($results[1]->getText(), $this->nodes[3]->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datetime grouped filter UI.
|
||||
*/
|
||||
protected function _testFilterDatetimeUI() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views']));
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_filter_date_between/default/filter', ['name[node__field_date.field_date_value]' => 'node__field_date.field_date_value'], t('Add and configure filter criteria'));
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Expose filter'));
|
||||
$this->drupalPostForm(NULL, [], t('Grouped filters'));
|
||||
|
||||
$edit = [];
|
||||
$edit['options[group_info][group_items][1][title]'] = 'simple-offset';
|
||||
$edit['options[group_info][group_items][1][operator]'] = '>';
|
||||
$edit['options[group_info][group_items][1][value][type]'] = 'offset';
|
||||
$edit['options[group_info][group_items][1][value][value]'] = '+1 hour';
|
||||
$edit['options[group_info][group_items][2][title]'] = 'between-offset';
|
||||
$edit['options[group_info][group_items][2][operator]'] = 'between';
|
||||
$edit['options[group_info][group_items][2][value][type]'] = 'offset';
|
||||
$edit['options[group_info][group_items][2][value][min]'] = '+1 hour';
|
||||
$edit['options[group_info][group_items][2][value][max]'] = '+2 days';
|
||||
$edit['options[group_info][group_items][3][title]'] = 'between-date';
|
||||
$edit['options[group_info][group_items][3][operator]'] = 'between';
|
||||
$edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
|
||||
$edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
|
||||
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
|
||||
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the exposed date filter is displayed without errors.
|
||||
*/
|
||||
public function testExposedFilter() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views']));
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created', [], t('Expose filter'));
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between/edit', [], t('Add Page'));
|
||||
$edit = [
|
||||
'path' => 'exposed-date-filter',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_date_between/page_1/path', $edit, t('Apply'));
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
$this->drupalGet('exposed-date-filter');
|
||||
$this->assertField('created');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
use Drupal\views\Plugin\views\filter\InOperator;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests instances of all handlers.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class HandlerAllTest extends ViewTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'aggregator',
|
||||
'book',
|
||||
'block',
|
||||
'comment',
|
||||
'contact',
|
||||
'field',
|
||||
'filter',
|
||||
'file',
|
||||
'forum',
|
||||
'history',
|
||||
'language',
|
||||
'locale',
|
||||
'node',
|
||||
'search',
|
||||
'statistics',
|
||||
'taxonomy',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests most of the handlers.
|
||||
*/
|
||||
public function testHandlers() {
|
||||
$this->drupalCreateContentType(['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(['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 = [
|
||||
'table' => $base_table,
|
||||
'field' => $field,
|
||||
];
|
||||
foreach ($object_types as $type) {
|
||||
if (isset($field_info[$type]['id'])) {
|
||||
$options = [];
|
||||
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'] = [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',
|
||||
[
|
||||
'@type' => $type,
|
||||
'%class' => get_class($handler),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Handler;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Entity\View;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests abstract handler definitions.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class HandlerTest extends ViewTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view', 'test_view_handler_weight', 'test_handler_relationships', 'test_handler_test_access', 'test_filter_in_operator_ui'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views_ui', 'comment', 'node'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
// Override the name handler to be able to call placeholder() from outside.
|
||||
$data['views_test_data']['name']['field']['id'] = 'test_field';
|
||||
|
||||
// Setup one field with an access callback and one with an access callback
|
||||
// and arguments.
|
||||
$data['views_test_data']['access_callback'] = $data['views_test_data']['id'];
|
||||
$data['views_test_data']['access_callback_arguments'] = $data['views_test_data']['id'];
|
||||
foreach (ViewExecutable::getHandlerTypes() as $type => $info) {
|
||||
if (isset($data['views_test_data']['access_callback'][$type]['id'])) {
|
||||
$data['views_test_data']['access_callback'][$type]['access callback'] = 'views_test_data_handler_test_access_callback';
|
||||
|
||||
$data['views_test_data']['access_callback_arguments'][$type]['access callback'] = 'views_test_data_handler_test_access_callback_argument';
|
||||
$data['views_test_data']['access_callback_arguments'][$type]['access arguments'] = [TRUE];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the breakString method.
|
||||
*/
|
||||
public function testBreakString() {
|
||||
// Check defaults.
|
||||
$this->assertEqual((object) ['value' => [], 'operator' => NULL], HandlerBase::breakString(''));
|
||||
|
||||
// Test ors
|
||||
$handler = HandlerBase::breakString('word1 word2+word');
|
||||
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
|
||||
$this->assertEqual('or', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word1+word2+word');
|
||||
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
|
||||
$this->assertEqual('or', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word1 word2 word');
|
||||
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
|
||||
$this->assertEqual('or', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word-1+word-2+word');
|
||||
$this->assertEqualValue(['word-1', 'word-2', 'word'], $handler);
|
||||
$this->assertEqual('or', $handler->operator);
|
||||
$handler = HandlerBase::breakString('wõrd1+wõrd2+wõrd');
|
||||
$this->assertEqualValue(['wõrd1', 'wõrd2', 'wõrd'], $handler);
|
||||
$this->assertEqual('or', $handler->operator);
|
||||
|
||||
// Test ands.
|
||||
$handler = HandlerBase::breakString('word1,word2,word');
|
||||
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word1 word2,word');
|
||||
$this->assertEqualValue(['word1 word2', 'word'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word1,word2 word');
|
||||
$this->assertEqualValue(['word1', 'word2 word'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
$handler = HandlerBase::breakString('word-1,word-2,word');
|
||||
$this->assertEqualValue(['word-1', 'word-2', 'word'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
$handler = HandlerBase::breakString('wõrd1,wõrd2,wõrd');
|
||||
$this->assertEqualValue(['wõrd1', 'wõrd2', 'wõrd'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
|
||||
// Test a single word
|
||||
$handler = HandlerBase::breakString('word');
|
||||
$this->assertEqualValue(['word'], $handler);
|
||||
$this->assertEqual('and', $handler->operator);
|
||||
|
||||
$s1 = $this->randomMachineName();
|
||||
// Generate three random numbers which can be used below;
|
||||
$n1 = rand(0, 100);
|
||||
$n2 = rand(0, 100);
|
||||
$n3 = rand(0, 100);
|
||||
|
||||
// Test "or"s.
|
||||
$handlerBase = HandlerBase::breakString("$s1 $n2+$n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1+$n2+$n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1 $n2 $n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1 $n2++$n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
// Test "and"s.
|
||||
$handlerBase = HandlerBase::breakString("$s1,$n2,$n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1,,$n2,$n3");
|
||||
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
|
||||
// Enforce int values.
|
||||
$handlerBase = HandlerBase::breakString("$n1,$n2,$n3", TRUE);
|
||||
$this->assertEqualValue([$n1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$n1+$n2+$n3", TRUE);
|
||||
$this->assertEqualValue([$n1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1,$n2,$n3", TRUE);
|
||||
$this->assertEqualValue([(int) $s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1+$n2+$n3", TRUE);
|
||||
$this->assertEqualValue([(int) $s1, $n2, $n3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
// Generate three random decimals which can be used below;
|
||||
$d1 = rand(0, 10) / 10;
|
||||
$d2 = rand(0, 10) / 10;
|
||||
$d3 = rand(0, 10) / 10;
|
||||
|
||||
// Test "or"s.
|
||||
$handlerBase = HandlerBase::breakString("$s1 $d1+$d2");
|
||||
$this->assertEqualValue([$s1, $d1, $d2], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1+$d1+$d3");
|
||||
$this->assertEqualValue([$s1, $d1, $d3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1 $d2 $d3");
|
||||
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1 $d2++$d3");
|
||||
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
|
||||
$this->assertEqual('or', $handlerBase->operator);
|
||||
|
||||
// Test "and"s.
|
||||
$handlerBase = HandlerBase::breakString("$s1,$d2,$d3");
|
||||
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
|
||||
$handlerBase = HandlerBase::breakString("$s1,,$d2,$d3");
|
||||
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
|
||||
$this->assertEqual('and', $handlerBase->operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the order of handlers is the same before and after saving.
|
||||
*/
|
||||
public function testHandlerWeights() {
|
||||
$handler_types = ['fields', 'filters', 'sorts'];
|
||||
|
||||
$view = Views::getView('test_view_handler_weight');
|
||||
$view->initDisplay();
|
||||
|
||||
// Store the order of handlers before saving the view.
|
||||
$original_order = [];
|
||||
foreach ($handler_types as $type) {
|
||||
$original_order[$type] = array_keys($view->display_handler->getOption($type));
|
||||
}
|
||||
|
||||
// Save the view and see if our filters are in the same order.
|
||||
$view->save();
|
||||
$view = views::getView('test_view_handler_weight');
|
||||
$view->initDisplay();
|
||||
|
||||
foreach ($handler_types as $type) {
|
||||
$loaded_order = array_keys($view->display_handler->getOption($type));
|
||||
$this->assertIdentical($original_order[$type], $loaded_order);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a value is the same as the value on a certain handler.
|
||||
*
|
||||
* @param $expected
|
||||
* The expected value to check.
|
||||
* @param \Drupal\views\Plugin\views\ViewsHandlerInterface $handler
|
||||
* The handler that has the $handler->value property to compare with first.
|
||||
* @param string $message
|
||||
* The message to display along with the assertion.
|
||||
* @param string $group
|
||||
* The type of assertion - examples are "Browser", "PHP".
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertEqualValue($expected, $handler, $message = '', $group = 'Other') {
|
||||
if (empty($message)) {
|
||||
$message = t('Comparing @first and @second', ['@first' => implode(',', $expected), '@second' => implode(',', $handler->value)]);
|
||||
}
|
||||
|
||||
return $this->assert($expected == $handler->value, $message, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the relationship ui for field/filter/argument/relationship.
|
||||
*/
|
||||
public function testRelationshipUI() {
|
||||
$views_admin = $this->drupalCreateUser(['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.
|
||||
$fields = $this->getSession()->getPage()->findAll('named_exact', ['field', $relationship_name]);
|
||||
$options = [];
|
||||
foreach ($fields as $field) {
|
||||
$items = $field->findAll('css', 'option');
|
||||
foreach ($items as $item) {
|
||||
$options[] = $item->getAttribute('value');
|
||||
}
|
||||
}
|
||||
$expected_options = ['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', [], 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');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the relationship method on the base class.
|
||||
*/
|
||||
public function testSetRelationship() {
|
||||
$view = Views::getView('test_handler_relationships');
|
||||
$view->setDisplay();
|
||||
// Setup a broken relationship.
|
||||
$view->addHandler('default', 'relationship', $this->randomMachineName(), $this->randomMachineName(), [], 'broken_relationship');
|
||||
// Setup a valid relationship.
|
||||
$view->addHandler('default', 'relationship', 'comment_field_data', 'node', ['relationship' => 'cid'], 'valid_relationship');
|
||||
$view->initHandlers();
|
||||
$field = $view->field['title'];
|
||||
|
||||
$field->options['relationship'] = NULL;
|
||||
$field->setRelationship();
|
||||
$this->assertFalse($field->relationship, 'Make sure that an empty relationship does not create a relationship on the field.');
|
||||
|
||||
$field->options['relationship'] = $this->randomMachineName();
|
||||
$field->setRelationship();
|
||||
$this->assertFalse($field->relationship, 'Make sure that a random relationship does not create a relationship on the field.');
|
||||
|
||||
$field->options['relationship'] = 'broken_relationship';
|
||||
$field->setRelationship();
|
||||
$this->assertFalse($field->relationship, 'Make sure that a broken relationship does not create a relationship on the field.');
|
||||
|
||||
$field->options['relationship'] = 'valid_relationship';
|
||||
$field->setRelationship();
|
||||
$this->assertFalse(!empty($field->relationship), 'Make sure that the relationship alias was not set without building a views query before.');
|
||||
|
||||
// Remove the invalid relationship.
|
||||
unset($view->relationship['broken_relationship']);
|
||||
|
||||
$view->build();
|
||||
$field->setRelationship();
|
||||
$this->assertEqual($field->relationship, $view->relationship['valid_relationship']->alias, 'Make sure that a valid relationship does create the right relationship query alias.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the placeholder function.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\HandlerBase::placeholder()
|
||||
*/
|
||||
public function testPlaceholder() {
|
||||
$view = Views::getView('test_view');
|
||||
$view->initHandlers();
|
||||
$view->initQuery();
|
||||
|
||||
$handler = $view->field['name'];
|
||||
$table = $handler->table;
|
||||
$field = $handler->field;
|
||||
$string = ':' . $table . '_' . $field;
|
||||
|
||||
// Make sure the placeholder variables are like expected.
|
||||
$this->assertEqual($handler->getPlaceholder(), $string);
|
||||
$this->assertEqual($handler->getPlaceholder(), $string . 1);
|
||||
$this->assertEqual($handler->getPlaceholder(), $string . 2);
|
||||
|
||||
// Set another table/field combination and make sure there are new
|
||||
// placeholders.
|
||||
$table = $handler->table = $this->randomMachineName();
|
||||
$field = $handler->field = $this->randomMachineName();
|
||||
$string = ':' . $table . '_' . $field;
|
||||
|
||||
// Make sure the placeholder variables are like expected.
|
||||
$this->assertEqual($handler->getPlaceholder(), $string);
|
||||
$this->assertEqual($handler->getPlaceholder(), $string . 1);
|
||||
$this->assertEqual($handler->getPlaceholder(), $string . 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests access to a handler.
|
||||
*
|
||||
* @see views_test_data_handler_test_access_callback
|
||||
*/
|
||||
public function testAccess() {
|
||||
$view = Views::getView('test_handler_test_access');
|
||||
$views_data = $this->viewsData();
|
||||
$views_data = $views_data['views_test_data'];
|
||||
|
||||
// Enable access to callback only field and deny for callback + arguments.
|
||||
$this->config('views_test_data.tests')->set('handler_access_callback', TRUE)->save();
|
||||
$this->config('views_test_data.tests')->set('handler_access_callback_argument', FALSE)->save();
|
||||
$view->initDisplay();
|
||||
$view->initHandlers();
|
||||
|
||||
foreach ($views_data['access_callback'] as $type => $info) {
|
||||
if (!in_array($type, ['title', 'help'])) {
|
||||
$this->assertTrue($view->field['access_callback'] instanceof HandlerBase, 'Make sure the user got access to the access_callback field ');
|
||||
$this->assertFalse(isset($view->field['access_callback_arguments']), 'Make sure the user got no access to the access_callback_arguments field ');
|
||||
}
|
||||
}
|
||||
|
||||
// Enable access to the callback + argument handlers and deny for callback.
|
||||
$this->config('views_test_data.tests')->set('handler_access_callback', FALSE)->save();
|
||||
$this->config('views_test_data.tests')->set('handler_access_callback_argument', TRUE)->save();
|
||||
$view->destroy();
|
||||
$view->initDisplay();
|
||||
$view->initHandlers();
|
||||
|
||||
foreach ($views_data['access_callback'] as $type => $info) {
|
||||
if (!in_array($type, ['title', 'help'])) {
|
||||
$this->assertFalse(isset($view->field['access_callback']), 'Make sure the user got no access to the access_callback field ');
|
||||
$this->assertTrue($view->field['access_callback_arguments'] instanceof HandlerBase, 'Make sure the user got access to the access_callback_arguments field ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests pluggable access for views.
|
||||
*
|
||||
* @group views
|
||||
* @todo It probably make sense to split the test up by one for role/perm/none
|
||||
* and the two generic ones.
|
||||
*/
|
||||
class AccessTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_access_none', 'test_access_static', 'test_access_dynamic'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Web user for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
/**
|
||||
* Normal user for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $normalUser;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['views_test_data']);
|
||||
|
||||
$this->webUser = $this->drupalCreateUser();
|
||||
|
||||
$normal_role = $this->drupalCreateRole([]);
|
||||
$this->normalUser = $this->drupalCreateUser(['views_test_data test permission']);
|
||||
$this->normalUser->addRole($normal_role);
|
||||
// @todo when all the plugin information is cached make a reset function and
|
||||
// call it here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests none access plugin.
|
||||
*/
|
||||
public function testAccessNone() {
|
||||
$view = Views::getView('test_access_none');
|
||||
$view->setDisplay();
|
||||
|
||||
$this->assertTrue($view->display_handler->access($this->webUser));
|
||||
$this->assertTrue($view->display_handler->access($this->normalUser));
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Test abstract access plugin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests static access check.
|
||||
*
|
||||
* @see \Drupal\views_test\Plugin\views\access\StaticTest
|
||||
*/
|
||||
public function testStaticAccessPlugin() {
|
||||
$view = Views::getView('test_access_static');
|
||||
$view->setDisplay();
|
||||
|
||||
$access_plugin = $view->display_handler->getPlugin('access');
|
||||
|
||||
$this->assertFalse($access_plugin->access($this->normalUser));
|
||||
$this->drupalGet('test_access_static');
|
||||
$this->assertResponse(403);
|
||||
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['access']['options']['access'] = TRUE;
|
||||
$access_plugin->options['access'] = TRUE;
|
||||
$view->save();
|
||||
// Saving a view will cause the router to be rebuilt when the kernel
|
||||
// termination event fires. Simulate that here.
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
|
||||
$this->assertTrue($access_plugin->access($this->normalUser));
|
||||
|
||||
$this->drupalGet('test_access_static');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views_test_data\Plugin\views\argument_default\ArgumentDefaultTest as ArgumentDefaultTestPlugin;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
/**
|
||||
* Tests pluggable argument_default for views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ArgumentDefaultTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = [
|
||||
'test_view',
|
||||
'test_argument_default_fixed',
|
||||
'test_argument_default_current_user',
|
||||
'test_argument_default_node',
|
||||
'test_argument_default_query_param',
|
||||
];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui', 'block'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the argument default test plugin.
|
||||
*
|
||||
* @see \Drupal\views_test_data\Plugin\views\argument_default\ArgumentDefaultTest
|
||||
*/
|
||||
public function testArgumentDefaultPlugin() {
|
||||
$view = Views::getView('test_view');
|
||||
|
||||
// Add a new argument and set the test plugin for the argument_default.
|
||||
$options = [
|
||||
'default_argument_type' => 'argument_default_test',
|
||||
'default_argument_options' => [
|
||||
'value' => 'John'
|
||||
],
|
||||
'default_action' => 'default'
|
||||
];
|
||||
$id = $view->addHandler('default', 'argument', 'views_test_data', 'name', $options);
|
||||
$view->initHandlers();
|
||||
$plugin = $view->argument[$id]->getPlugin('argument_default');
|
||||
$this->assertTrue($plugin instanceof ArgumentDefaultTestPlugin, 'The correct argument default plugin is used.');
|
||||
|
||||
// Check that the value of the default argument is as expected.
|
||||
$this->assertEqual($view->argument[$id]->getDefaultArgument(), 'John', 'The correct argument default value is returned.');
|
||||
// Don't pass in a value for the default argument and make sure the query
|
||||
// just returns John.
|
||||
$this->executeView($view);
|
||||
$this->assertEqual($view->argument[$id]->getValue(), 'John', 'The correct argument value is used.');
|
||||
$expected_result = [['name' => 'John']];
|
||||
$this->assertIdenticalResultset($view, $expected_result, ['views_test_data_name' => 'name']);
|
||||
|
||||
// Pass in value as argument to be sure that not the default value is used.
|
||||
$view->destroy();
|
||||
$this->executeView($view, ['George']);
|
||||
$this->assertEqual($view->argument[$id]->getValue(), 'George', 'The correct argument value is used.');
|
||||
$expected_result = [['name' => 'George']];
|
||||
$this->assertIdenticalResultset($view, $expected_result, ['views_test_data_name' => 'name']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the use of a default argument plugin that provides no options.
|
||||
*/
|
||||
public function testArgumentDefaultNoOptions() {
|
||||
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// The current_user plugin has no options form, and should pass validation.
|
||||
$argument_type = 'current_user';
|
||||
$edit = [
|
||||
'options[default_argument_type]' => $argument_type,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_argument_default_current_user/default/argument/uid', $edit, t('Apply'));
|
||||
|
||||
// Note, the undefined index error has two spaces after it.
|
||||
$error = [
|
||||
'%type' => 'Notice',
|
||||
'@message' => 'Undefined index: ' . $argument_type,
|
||||
'%function' => 'views_handler_argument->validateOptionsForm()',
|
||||
];
|
||||
$message = t('%type: @message in %function', $error);
|
||||
$this->assertNoRaw($message, format_string('Did not find error message: @message.', ['@message' => $message]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests fixed default argument.
|
||||
*/
|
||||
public function testArgumentDefaultFixed() {
|
||||
$random = $this->randomMachineName();
|
||||
$view = Views::getView('test_argument_default_fixed');
|
||||
$view->setDisplay();
|
||||
$options = $view->display_handler->getOption('arguments');
|
||||
$options['null']['default_argument_options']['argument'] = $random;
|
||||
$view->display_handler->overrideOption('arguments', $options);
|
||||
$view->initHandlers();
|
||||
|
||||
$this->assertEqual($view->argument['null']->getDefaultArgument(), $random, 'Fixed argument should be used by default.');
|
||||
|
||||
// Make sure that a normal argument provided is used
|
||||
$random_string = $this->randomMachineName();
|
||||
$view->executeDisplay('default', [$random_string]);
|
||||
|
||||
$this->assertEqual($view->args[0], $random_string, 'Provided argument should be used.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Test php default argument.
|
||||
*/
|
||||
//function testArgumentDefaultPhp() {}
|
||||
|
||||
/**
|
||||
* Test node default argument.
|
||||
*/
|
||||
public function testArgumentDefaultNode() {
|
||||
// Create a user that has permission to place a view block.
|
||||
$permissions = [
|
||||
'administer views',
|
||||
'administer blocks',
|
||||
'bypass node access',
|
||||
'access user profiles',
|
||||
'view all revisions',
|
||||
];
|
||||
$views_admin = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($views_admin);
|
||||
|
||||
// Create nodes where should show themselves again as view block.
|
||||
$node_type = NodeType::create(['type' => 'page', 'label' => 'Page']);
|
||||
$node_type->save();
|
||||
$node1 = Node::create(['title' => 'Test node 1', 'type' => 'page']);
|
||||
$node1->save();
|
||||
$node2 = Node::create(['title' => 'Test node 2', 'type' => 'page']);
|
||||
$node2->save();
|
||||
|
||||
// Place the block, visit the pages that display the block, and check that
|
||||
// the nodes we expect appear in the respective pages.
|
||||
$id = 'view-block-id';
|
||||
$this->drupalPlaceBlock("views_block:test_argument_default_node-block_1", ['id' => $id]);
|
||||
$xpath = '//*[@id="block-' . $id . '"]';
|
||||
$this->drupalGet('node/' . $node1->id());
|
||||
$this->assertTrue(strpos($this->xpath($xpath)[0]->getText(), $node1->getTitle()));
|
||||
$this->drupalGet('node/' . $node2->id());
|
||||
$this->assertTrue(strpos($this->xpath($xpath)[0]->getText(), $node2->getTitle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the query parameter default argument.
|
||||
*/
|
||||
public function testArgumentDefaultQueryParameter() {
|
||||
$view = Views::getView('test_argument_default_query_param');
|
||||
|
||||
$request = Request::create(Url::fromUri('internal:/whatever', ['absolute' => TRUE])->toString());
|
||||
|
||||
// Check the query parameter default argument fallback value.
|
||||
$view->setRequest($request);
|
||||
$view->initHandlers();
|
||||
$this->assertEqual($view->argument['type']->getDefaultArgument(), 'all');
|
||||
|
||||
// Check the query parameter default argument with a value.
|
||||
$request->query->add(['the_node_type' => 'page']);
|
||||
$view->setRequest($request);
|
||||
$view->initHandlers();
|
||||
$this->assertEqual($view->argument['type']->getDefaultArgument(), 'page');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests tag cache plugin.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\cache\Tag
|
||||
*/
|
||||
class CacheTagTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_tag_cache'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* The node storage.
|
||||
*
|
||||
* @var \Drupal\node\NodeStorage
|
||||
*/
|
||||
protected $nodeStorage;
|
||||
|
||||
/**
|
||||
* The node view builder.
|
||||
*
|
||||
* @var \Drupal\node\NodeViewBuilder
|
||||
*/
|
||||
protected $nodeViewBuilder;
|
||||
|
||||
/**
|
||||
* The user view builder.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityViewBuilder
|
||||
*/
|
||||
protected $userViewBuilder;
|
||||
|
||||
/**
|
||||
* An array of page nodes.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface[]
|
||||
*/
|
||||
protected $pages;
|
||||
|
||||
/**
|
||||
* An article node.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface
|
||||
*/
|
||||
protected $article;
|
||||
|
||||
/**
|
||||
* A test user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
|
||||
$this->nodeStorage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->nodeViewBuilder = $this->container->get('entity.manager')->getViewBuilder('node');
|
||||
$this->userViewBuilder = $this->container->get('entity.manager')->getViewBuilder('user');
|
||||
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$this->pages[] = $this->drupalCreateNode(['title' => "Test $i", 'type' => 'page']);
|
||||
}
|
||||
$this->article = $this->drupalCreateNode(['title' => "Test article", 'type' => 'article']);
|
||||
$this->user = $this->drupalCreateUser();
|
||||
|
||||
// Mark the current request safe, in order to make render cache working, see
|
||||
// \Drupal\Core\Render\RenderCache::get.
|
||||
\Drupal::request()->setMethod('GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the render cache for a given view.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view.
|
||||
*
|
||||
* @return array|false
|
||||
* The render cache result or FALSE if not existent.
|
||||
*/
|
||||
protected function getRenderCache(ViewExecutable $view) {
|
||||
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
|
||||
$render_cache = \Drupal::service('render_cache');
|
||||
$view->element = ['#cache' => []];
|
||||
$build = $view->buildRenderable();
|
||||
$build['#cache']['contexts'] = Cache::mergeContexts($build['#cache']['contexts'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
|
||||
|
||||
return $render_cache->get($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the tag cache plugin.
|
||||
*/
|
||||
public function testTagCaching() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$view = Views::getView('test_tag_cache');
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Saving the view should invalidate the tags.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$view->storage->save();
|
||||
|
||||
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after the view is saved.');
|
||||
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after the view is saved.');
|
||||
|
||||
$view->destroy();
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Test invalidating the nodes in this view invalidates the cache.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$this->nodeViewBuilder->resetCache($this->pages);
|
||||
|
||||
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after resetCache is called with pages.');
|
||||
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after resetCache is called with pages.');
|
||||
|
||||
$view->destroy();
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Test saving a node in this view invalidates the cache.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$node = reset($this->pages);
|
||||
$node->save();
|
||||
|
||||
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after a page node is saved.');
|
||||
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after a page node is saved.');
|
||||
|
||||
$view->destroy();
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Test saving a node not in this view invalidates the cache too.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$this->article->save();
|
||||
|
||||
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after an article node is saved.');
|
||||
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after an article node is saved.');
|
||||
|
||||
$view->destroy();
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Test that invalidating a tag for a user, does not invalidate the cache,
|
||||
// as the user entity type will not be contained in the views cache tags.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$this->userViewBuilder->resetCache([$this->user]);
|
||||
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found after a user is invalidated.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found after a user is invalidated.');
|
||||
|
||||
$view->destroy();
|
||||
// Invalidate the views cache tags in order to invalidate the render
|
||||
// caching.
|
||||
\Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTagsToInvalidate());
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
// Test the cacheFlush method invalidates the cache.
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
|
||||
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
|
||||
|
||||
$cache_plugin->cacheFlush();
|
||||
|
||||
$cache_plugin = $view->display_handler->getPlugin('cache');
|
||||
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after the cacheFlush() method is called.');
|
||||
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after the cacheFlush() method is called.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests pluggable caching for views via a web test.
|
||||
*
|
||||
* @group views
|
||||
* @see views_plugin_cache
|
||||
*/
|
||||
class CacheWebTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_display'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the output caching on an actual page.
|
||||
*/
|
||||
public function testCacheOutputOnPage() {
|
||||
$view = Views::getView('test_display');
|
||||
$view->storage->setStatus(TRUE);
|
||||
$view->setDisplay('page_1');
|
||||
$view->display_handler->overrideOption('cache', [
|
||||
'type' => 'time',
|
||||
'options' => [
|
||||
'results_lifespan' => '3600',
|
||||
'output_lifespan' => '3600'
|
||||
]
|
||||
]);
|
||||
$view->save();
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
|
||||
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
|
||||
$render_cache = \Drupal::service('render_cache');
|
||||
$cache_element = DisplayPluginBase::buildBasicRenderable('test_display', 'page_1');
|
||||
$cache_element['#cache'] += ['contexts' => $this->container->getParameter('renderer.config')['required_cache_contexts']];
|
||||
$this->assertFalse($render_cache->get($cache_element));
|
||||
|
||||
$this->drupalGet('test-display');
|
||||
$this->assertResponse(200);
|
||||
$this->assertTrue($render_cache->get($cache_element));
|
||||
$cache_tags = [
|
||||
'config:user.role.anonymous',
|
||||
'config:views.view.test_display',
|
||||
'node_list',
|
||||
'rendered'
|
||||
];
|
||||
$this->assertCacheTags($cache_tags);
|
||||
|
||||
$this->drupalGet('test-display');
|
||||
$this->assertResponse(200);
|
||||
$this->assertTrue($render_cache->get($cache_element));
|
||||
$this->assertCacheTags($cache_tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a display without caching still contains the cache metadata.
|
||||
*/
|
||||
public function testDisplayWithoutCacheStillBubblesMetadata() {
|
||||
$view = Views::getView('test_display');
|
||||
|
||||
$uncached_block = $view->buildRenderable('block_1', [], FALSE);
|
||||
$cached_block = $view->buildRenderable('block_1', [], TRUE);
|
||||
$this->assertEqual($uncached_block['#cache']['contexts'], $cached_block['#cache']['contexts'], 'Cache contexts are the same when you render the view cached and uncached.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextDefinitionInterface;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* A test for contextual filters exposed as block context.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ContextualFiltersBlockContextTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'block_test_views', 'views_ui', 'node'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view_block_with_context'];
|
||||
|
||||
/**
|
||||
* Test node type.
|
||||
*
|
||||
* @var \Drupal\node\NodeTypeInterface
|
||||
*/
|
||||
protected $nodeType;
|
||||
|
||||
/**
|
||||
* Test nodes.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface[]
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['block_test_views']);
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->nodeType = $this->container->get('entity_type.manager')
|
||||
->getStorage('node_type')
|
||||
->create([
|
||||
'name' => 'Test node type',
|
||||
'type' => 'test',
|
||||
]);
|
||||
$this->nodeType->save();
|
||||
|
||||
$this->nodes[0] = $this->container->get('entity_type.manager')
|
||||
->getStorage('node')
|
||||
->create(['type' => $this->nodeType->id(), 'title' => 'First test node']);
|
||||
$this->nodes[0]->save();
|
||||
|
||||
$this->nodes[1] = $this->container->get('entity_type.manager')
|
||||
->getStorage('node')
|
||||
->create(['type' => $this->nodeType->id(), 'title' => 'Second test node']);
|
||||
$this->nodes[1]->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exposed context.
|
||||
*/
|
||||
public function testBlockContext() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views', 'administer blocks']));
|
||||
|
||||
// Check if context was correctly propagated to the block.
|
||||
$definition = $this->container->get('plugin.manager.block')
|
||||
->getDefinition('views_block:test_view_block_with_context-block_1');
|
||||
$this->assertTrue($definition['context']['nid'] instanceof ContextDefinitionInterface);
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
|
||||
$context = $definition['context']['nid'];
|
||||
$this->assertEqual($context->getDataType(), 'entity:node', 'Context definition data type is correct.');
|
||||
$this->assertEqual($context->getLabel(), 'Content: ID', 'Context definition label is correct.');
|
||||
$this->assertFalse($context->isRequired(), 'Context is not required.');
|
||||
|
||||
// Place test block via block UI to check if contexts are correctly exposed.
|
||||
$this->drupalGet(
|
||||
'admin/structure/block/add/views_block:test_view_block_with_context-block_1/classy',
|
||||
['query' => ['region' => 'content']]
|
||||
);
|
||||
$edit = [
|
||||
'settings[context_mapping][nid]' => '@node.node_route_context:node',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Save block');
|
||||
|
||||
// Check if mapping saved correctly.
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$block = $this->container->get('entity_type.manager')
|
||||
->getStorage('block')
|
||||
->load('views_block__test_view_block_with_context_block_1');
|
||||
$expected_settings = [
|
||||
'id' => 'views_block:test_view_block_with_context-block_1',
|
||||
'label' => '',
|
||||
'provider' => 'views',
|
||||
'label_display' => 'visible',
|
||||
'views_label' => '',
|
||||
'items_per_page' => 'none',
|
||||
'context_mapping' => ['nid' => '@node.node_route_context:node']
|
||||
];
|
||||
$this->assertEqual($block->getPlugin()->getConfiguration(), $expected_settings, 'Block settings are correct.');
|
||||
|
||||
// Make sure view behaves as expected.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText('Test view: No results found.');
|
||||
|
||||
$this->drupalGet($this->nodes[0]->toUrl());
|
||||
$this->assertText('Test view row: First test node');
|
||||
|
||||
$this->drupalGet($this->nodes[1]->toUrl());
|
||||
$this->assertText('Test view row: Second test node');
|
||||
|
||||
// Check the second block which should expose two integer contexts, one
|
||||
// based on the numeric plugin and the other based on numeric validation.
|
||||
$definition = $this->container->get('plugin.manager.block')
|
||||
->getDefinition('views_block:test_view_block_with_context-block_2');
|
||||
$this->assertTrue($definition['context']['created'] instanceof ContextDefinitionInterface);
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
|
||||
$context = $definition['context']['created'];
|
||||
$this->assertEqual($context->getDataType(), 'integer', 'Context definition data type is correct.');
|
||||
$this->assertEqual($context->getLabel(), 'Content: Authored on', 'Context definition label is correct.');
|
||||
$this->assertFalse($context->isRequired(), 'Context is not required.');
|
||||
|
||||
$this->assertTrue($definition['context']['vid'] instanceof ContextDefinitionInterface);
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
|
||||
$context = $definition['context']['vid'];
|
||||
$this->assertEqual($context->getDataType(), 'integer', 'Context definition data type is correct.');
|
||||
$this->assertEqual($context->getLabel(), 'Content: Revision ID', 'Context definition label is correct.');
|
||||
$this->assertFalse($context->isRequired(), 'Context is not required.');
|
||||
|
||||
$this->assertTrue($definition['context']['title'] instanceof ContextDefinitionInterface);
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
|
||||
$context = $definition['context']['title'];
|
||||
$this->assertEqual($context->getDataType(), 'string', 'Context definition data type is correct.');
|
||||
$this->assertEqual($context->getLabel(), 'Content: Title', 'Context definition label is correct.');
|
||||
$this->assertFalse($context->isRequired(), 'Context is not required.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the ability to disable and enable view displays.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\display\Feed
|
||||
*/
|
||||
class DisabledDisplayTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_disabled_display'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'node', 'views'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that views displays can be disabled.
|
||||
*
|
||||
* This method only checks the page displays via a HTTP request, but should
|
||||
* the .enabled property disappear from the schema both the load and save
|
||||
* calls will start failing.
|
||||
*/
|
||||
public function testDisabledDisplays() {
|
||||
// The displays defined in this view.
|
||||
$display_ids = ['attachment_1', 'block_1', 'embed_1', 'feed_1', 'page_2'];
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->drupalCreateNode();
|
||||
|
||||
// Load the test view and initialize its displays.
|
||||
$view = $this->container->get('entity.manager')->getStorage('view')->load('test_disabled_display');
|
||||
$view->getExecutable()->setDisplay();
|
||||
|
||||
// Enabled page display should return content.
|
||||
$this->drupalGet('test-disabled-display');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual($result[0]->getText(), 'test_disabled_display', 'The enabled page_1 display is accessible.');
|
||||
|
||||
// Disabled page view should 404.
|
||||
$this->drupalGet('test-disabled-display-2');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Enable each disabled display and save the view.
|
||||
foreach ($display_ids as $display_id) {
|
||||
$view->getExecutable()->displayHandlers->get($display_id)->setOption('enabled', TRUE);
|
||||
$view->save();
|
||||
$enabled = $view->getExecutable()->displayHandlers->get($display_id)->isEnabled();
|
||||
$this->assertTrue($enabled, 'Display ' . $display_id . ' is now enabled');
|
||||
}
|
||||
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
|
||||
// Check that the originally disabled page_2 display is now enabled.
|
||||
$this->drupalGet('test-disabled-display-2');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual($result[0]->getText(), 'test_disabled_display', 'The enabled page_2 display is accessible.');
|
||||
|
||||
// Disable each disabled display and save the view.
|
||||
foreach ($display_ids as $display_id) {
|
||||
$view->getExecutable()->displayHandlers->get($display_id)->setOption('enabled', FALSE);
|
||||
$view->save();
|
||||
$enabled = $view->getExecutable()->displayHandlers->get($display_id)->isEnabled();
|
||||
$this->assertFalse($enabled, 'Display ' . $display_id . ' is now disabled');
|
||||
}
|
||||
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// Check that the page_1 display still works.
|
||||
$this->drupalGet('test-disabled-display');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Check that the page_2 display is now disabled again.
|
||||
$this->drupalGet('test-disabled-display-2');
|
||||
$this->assertResponse(404);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the attachment display plugin.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\display\Attachment
|
||||
*/
|
||||
class DisplayAttachmentTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_display_attachment', 'test_attached_disabled'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the attachment plugin.
|
||||
*/
|
||||
public function testAttachment() {
|
||||
$this->drupalGet('test-display-attachment');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "view-content")]');
|
||||
$this->assertEqual(count($result), 2, 'Both actual view and the attachment is rendered.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
|
||||
$this->assertEqual(count($result), 0, 'The attachment is not rendered after the actual view.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
|
||||
$this->assertEqual(count($result), 1, 'The attachment is rendered before the actual view.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nothing is output when the attachment displays are disabled.
|
||||
*/
|
||||
public function testDisabledAttachments() {
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->drupalCreateNode();
|
||||
|
||||
// Ensure that the feed_1 display is attached to the page_1 display.
|
||||
$view = Views::getView('test_attached_disabled');
|
||||
$view->setDisplay('page_1');
|
||||
$attached_displays = $view->display_handler->getAttachedDisplays();
|
||||
$this->assertTrue(in_array('attachment_1', $attached_displays), 'The attachment_1 display is attached to the page display.');
|
||||
$this->assertTrue(in_array('attachment_2', $attached_displays), 'The attachment_2 display is attached to the page display.');
|
||||
|
||||
// Check that the attachments are output on the page display.
|
||||
$this->drupalGet('test-attached-disabled');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "view-content")]');
|
||||
$this->assertEqual(count($result), 3, 'The page view and the attachments are rendered.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
|
||||
$this->assertEqual(count($result), 1, 'The attachment is rendered before the page view.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
|
||||
$this->assertEqual(count($result), 1, 'The attachment is rendered after the page view.');
|
||||
|
||||
// Disable the attachment_1 display.
|
||||
$view->displayHandlers->get('attachment_1')->setOption('enabled', FALSE);
|
||||
$view->save();
|
||||
|
||||
// Test that the before attachment is not displayed.
|
||||
$this->drupalGet('/test-attached-disabled');
|
||||
$result = $this->xpath('//div[contains(@class, "view-content")]');
|
||||
$this->assertEqual(count($result), 2, 'The page view and only one attachment are rendered.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
|
||||
$this->assertEqual(count($result), 0, 'The attachment_1 is not rendered.');
|
||||
|
||||
// Disable the attachment_2 display.
|
||||
$view->displayHandlers->get('attachment_2')->setOption('enabled', FALSE);
|
||||
$view->save();
|
||||
|
||||
// Test that the after attachment is not displayed.
|
||||
$this->drupalGet('/test-attached-disabled');
|
||||
$result = $this->xpath('//div[contains(@class, "view-content")]');
|
||||
$this->assertEqual(count($result), 1, 'The page view is rendered without attachments.');
|
||||
|
||||
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
|
||||
$this->assertEqual(count($result), 0, 'The attachment_2 is not rendered.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the entity reference display plugin.
|
||||
*
|
||||
* @group views
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\display\EntityReference
|
||||
*/
|
||||
class DisplayEntityReferenceTest extends ViewTestBase {
|
||||
|
||||
use EntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_display_entity_reference'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['entity_test', 'field', 'views_ui'];
|
||||
|
||||
/**
|
||||
* The used field name in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* The used entity reference field name in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityRefFieldName;
|
||||
|
||||
/**
|
||||
* The field storage.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
/**
|
||||
* The field config.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldConfig
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer views']));
|
||||
|
||||
// Create the text field.
|
||||
$this->fieldName = 'field_test_entity_ref_display';
|
||||
$this->fieldStorage = FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'text',
|
||||
]);
|
||||
$this->fieldStorage->save();
|
||||
|
||||
// Create an instance of the text field on the content type.
|
||||
$this->field = FieldConfig::create([
|
||||
'field_storage' => $this->fieldStorage,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$this->field->save();
|
||||
|
||||
// Add an entity reference field to reference the same base table.
|
||||
$this->entityRefFieldName = 'field_test_entity_ref_entity_ref';
|
||||
$this->createEntityReferenceField('entity_test', 'entity_test', $this->entityRefFieldName, NULL, 'entity_test');
|
||||
|
||||
// Create some entities to search. Add a common string to the name and
|
||||
// the text field in two entities so we can test that we can search in both.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
EntityTest::create([
|
||||
'bundle' => 'entity_test',
|
||||
'name' => 'name' . $i,
|
||||
$this->fieldName => 'text',
|
||||
])->save();
|
||||
EntityTest::create([
|
||||
'bundle' => 'entity_test',
|
||||
'name' => 'name',
|
||||
$this->fieldName => 'text' . $i,
|
||||
])->save();
|
||||
}
|
||||
EntityTest::create([
|
||||
'bundle' => 'entity_test',
|
||||
'name' => 'name',
|
||||
$this->fieldName => 'tex',
|
||||
])->save();
|
||||
EntityTest::create([
|
||||
'bundle' => 'entity_test',
|
||||
'name' => 'name',
|
||||
$this->fieldName => 'TEX',
|
||||
])->save();
|
||||
EntityTest::create([
|
||||
'bundle' => 'entity_test',
|
||||
'name' => 'name',
|
||||
$this->fieldName => 'sometext',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the entity reference display plugin.
|
||||
*/
|
||||
public function testEntityReferenceDisplay() {
|
||||
// Add the new field to the fields.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/field', ['name[entity_test__' . $this->fieldName . '.' . $this->fieldName . ']' => TRUE], t('Add and configure fields'));
|
||||
$this->drupalPostForm(NULL, [], t('Apply'));
|
||||
|
||||
// Test that the right fields are shown on the display settings form.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_display_entity_reference/entity_reference_1/style_options');
|
||||
$this->assertText('Test entity: Name');
|
||||
$this->assertText('Test entity: ' . $this->field->label());
|
||||
|
||||
// Add the new field to the search fields.
|
||||
$this->drupalPostForm(NULL, ['style_options[search_fields][' . $this->fieldName . ']' => $this->fieldName], t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
|
||||
// Add the required settings to test a search operation.
|
||||
$options = [
|
||||
'match' => '1',
|
||||
'match_operator' => 'CONTAINS',
|
||||
'limit' => 0,
|
||||
'ids' => NULL,
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Test that we have searched in both fields.
|
||||
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
|
||||
$view->destroy();
|
||||
|
||||
// Test the 'CONTAINS' match_operator.
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
$options = [
|
||||
'match' => 'tex',
|
||||
'match_operator' => 'CONTAINS',
|
||||
'limit' => 0,
|
||||
'ids' => NULL,
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 13, 'Search returned thirteen rows');
|
||||
$view->destroy();
|
||||
|
||||
// Test the 'STARTS_WITH' match_operator.
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
$options = [
|
||||
'match' => 'tex',
|
||||
'match_operator' => 'STARTS_WITH',
|
||||
'limit' => 0,
|
||||
'ids' => NULL,
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 12, 'Search returned twelve rows');
|
||||
$view->destroy();
|
||||
|
||||
// Test the '=' match_operator.
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
$options = [
|
||||
'match' => 'tex',
|
||||
'match_operator' => '=',
|
||||
'limit' => 0,
|
||||
'ids' => NULL,
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
|
||||
$view->destroy();
|
||||
|
||||
// Add a relationship and a field using that relationship.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/relationship', ['name[entity_test.user_id]' => TRUE], t('Add and configure relationships'));
|
||||
$this->drupalPostForm(NULL, [], t('Apply'));
|
||||
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/field', ['name[users_field_data.uid]' => TRUE], t('Add and configure fields'));
|
||||
$this->drupalPostForm(NULL, [], t('Apply'));
|
||||
|
||||
// Add the new field to the search fields.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_display_entity_reference/entity_reference_1/style_options', ['style_options[search_fields][uid]' => 'uid'], t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
// Test that the search still works with the ralated field.
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
|
||||
// Add the required settings to test a search operation.
|
||||
$options = [
|
||||
'match' => '2',
|
||||
'match_operator' => 'CONTAINS',
|
||||
'limit' => 0,
|
||||
'ids' => NULL,
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Run validation when using a relationship to the same base table.
|
||||
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
|
||||
$view->destroy();
|
||||
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/relationship', ['name[entity_test__field_test_entity_ref_entity_ref.field_test_entity_ref_entity_ref]' => TRUE], t('Add and configure relationships'));
|
||||
$this->drupalPostForm(NULL, [], t('Apply'));
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
// Test that the search still works with the related field.
|
||||
$view = Views::getView('test_display_entity_reference');
|
||||
$view->setDisplay('entity_reference_1');
|
||||
|
||||
// Add IDs to trigger validation.
|
||||
$options = [
|
||||
'match' => '1',
|
||||
'match_operator' => 'CONTAINS',
|
||||
'limit' => 0,
|
||||
'ids' => [1, 2],
|
||||
];
|
||||
$view->display_handler->setOption('entity_reference_options', $options);
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the views page display plugin as webtest.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class DisplayPageWebTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_page_display', 'test_page_display_arguments', 'test_page_display_menu', 'test_page_display_path'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['menu_ui', 'block', 'views_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests arguments.
|
||||
*/
|
||||
public function testArguments() {
|
||||
$this->drupalGet('test_route_without_arguments');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 5, 'All entries was returned');
|
||||
|
||||
$this->drupalGet('test_route_without_arguments/1');
|
||||
$this->assertResponse(404);
|
||||
|
||||
$this->drupalGet('test_route_with_argument/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url']);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
|
||||
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
|
||||
|
||||
$this->drupalGet('test_route_with_suffix/1/suffix');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
|
||||
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
|
||||
|
||||
$this->drupalGet('test_route_with_suffix_and_argument/1/suffix/2');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 0, 'No result was returned.');
|
||||
|
||||
$this->drupalGet('test_route_with_suffix_and_argument/1/suffix/1');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
|
||||
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
|
||||
|
||||
$this->drupalGet('test_route_with_long_argument/1');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
|
||||
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests menu settings of page displays.
|
||||
*/
|
||||
public function testPageDisplayMenu() {
|
||||
// Check local tasks.
|
||||
$this->drupalGet('test_page_display_menu');
|
||||
$this->assertResponse(200);
|
||||
$element = $this->xpath('//ul[contains(@class, :ul_class)]//a[contains(@class, :a_class)]/child::text()', [
|
||||
':ul_class' => 'tabs primary',
|
||||
':a_class' => 'is-active',
|
||||
]);
|
||||
$this->assertEqual($element[0]->getText(), t('Test default tab'));
|
||||
$this->assertTitle(t('Test default page | Drupal'));
|
||||
|
||||
$this->drupalGet('test_page_display_menu/default');
|
||||
$this->assertResponse(404);
|
||||
|
||||
$this->drupalGet('test_page_display_menu/local');
|
||||
$this->assertResponse(200);
|
||||
$element = $this->xpath('//ul[contains(@class, :ul_class)]//a[contains(@class, :a_class)]/child::text()', [
|
||||
':ul_class' => 'tabs primary',
|
||||
':a_class' => 'is-active',
|
||||
]);
|
||||
$this->assertEqual($element[0]->getText(), t('Test local tab'));
|
||||
$this->assertTitle(t('Test local page | Drupal'));
|
||||
|
||||
// Check an ordinary menu link.
|
||||
$admin_user = $this->drupalCreateUser(['administer menu']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalPlaceBlock('system_menu_block:tools');
|
||||
$this->drupalGet('<front>');
|
||||
|
||||
$menu_link = $this->cssSelect('nav.block-menu ul.menu a');
|
||||
$this->assertEqual($menu_link[0]->getText(), 'Test menu link');
|
||||
|
||||
// Update the menu link.
|
||||
$this->drupalPostForm("admin/structure/menu/link/views_view:views.test_page_display_menu.page_3/edit", [
|
||||
'title' => 'New title',
|
||||
], t('Save'));
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$menu_link = $this->cssSelect('nav.block-menu ul.menu a');
|
||||
$this->assertEqual($menu_link[0]->getText(), 'New title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the title is not displayed in the output.
|
||||
*/
|
||||
public function testTitleOutput() {
|
||||
$this->drupalGet('test_page_display_200');
|
||||
|
||||
$view = Views::getView('test_page_display');
|
||||
$xpath = $this->cssSelect('div.view:contains("' . $view->getTitle() . '")');
|
||||
$this->assertFalse($xpath, 'The view title was not displayed in the view markup.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the views page path functionality.
|
||||
*/
|
||||
public function testPagePaths() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->assertPagePath('0');
|
||||
$this->assertPagePath('9999');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that we can successfully change a view page display path.
|
||||
*
|
||||
* @param string $path
|
||||
* Path that will be set as the view page display path.
|
||||
*
|
||||
* @return bool
|
||||
* Assertion result.
|
||||
*/
|
||||
public function assertPagePath($path) {
|
||||
$view = Views::getView('test_page_display_path');
|
||||
$view->initDisplay('page_1');
|
||||
$view->displayHandlers->get('page_1')->overrideOption('path', $path);
|
||||
$view->save();
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
// Check if we successfully changed the path.
|
||||
$this->drupalGet($path);
|
||||
$success = $this->assertResponse(200);
|
||||
// Check if we don't get any error on the view edit page.
|
||||
$this->drupalGet('admin/structure/views/view/test_page_display_path');
|
||||
return $success && $this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views_test_data\Plugin\views\display\DisplayTest as DisplayTestPlugin;
|
||||
|
||||
/**
|
||||
* Tests the basic display plugin.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class DisplayTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid', 'test_display_empty', 'test_exposed_relationship_admin_ui'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views_ui', 'node', 'block'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['administer views']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Create 10 nodes.
|
||||
for ($i = 0; $i <= 10; $i++) {
|
||||
$this->drupalCreateNode(['promote' => TRUE]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the display test plugin.
|
||||
*
|
||||
* @see \Drupal\views_test_data\Plugin\views\display\DisplayTest
|
||||
*/
|
||||
public function testDisplayPlugin() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$view = Views::getView('test_view');
|
||||
|
||||
// Add a new 'display_test' display and test it's there.
|
||||
$view->storage->addDisplay('display_test');
|
||||
$displays = $view->storage->get('display');
|
||||
|
||||
$this->assertTrue(isset($displays['display_test_1']), 'Added display has been assigned to "display_test_1"');
|
||||
|
||||
// Check the display options are like expected.
|
||||
$options = [
|
||||
'display_options' => [],
|
||||
'display_plugin' => 'display_test',
|
||||
'id' => 'display_test_1',
|
||||
'display_title' => 'Display test',
|
||||
'position' => 1,
|
||||
];
|
||||
$this->assertEqual($displays['display_test_1'], $options);
|
||||
|
||||
// Add another one to ensure that position is counted up.
|
||||
$view->storage->addDisplay('display_test');
|
||||
$displays = $view->storage->get('display');
|
||||
$options = [
|
||||
'display_options' => [],
|
||||
'display_plugin' => 'display_test',
|
||||
'id' => 'display_test_2',
|
||||
'display_title' => 'Display test 2',
|
||||
'position' => 2,
|
||||
];
|
||||
$this->assertEqual($displays['display_test_2'], $options);
|
||||
|
||||
// Move the second display before the first one in order to test custom
|
||||
// sorting.
|
||||
$displays['display_test_1']['position'] = 2;
|
||||
$displays['display_test_2']['position'] = 1;
|
||||
$view->storage->set('display', $displays);
|
||||
$view->save();
|
||||
|
||||
$view->setDisplay('display_test_1');
|
||||
|
||||
$this->assertTrue($view->display_handler instanceof DisplayTestPlugin, 'The correct display handler instance is on the view object.');
|
||||
|
||||
// Check the test option.
|
||||
$this->assertIdentical($view->display_handler->getOption('test_option'), '');
|
||||
|
||||
$style = $view->display_handler->getOption('style');
|
||||
$style['type'] = 'test_style';
|
||||
$view->display_handler->setOption('style', $style);
|
||||
$view->initDisplay();
|
||||
$view->initStyle();
|
||||
$view->style_plugin->setUsesRowPlugin(FALSE);
|
||||
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
|
||||
$this->assertTrue(strpos($output, '<h1></h1>') !== FALSE, 'An empty value for test_option found in output.');
|
||||
|
||||
// Change this option and check the title of out output.
|
||||
$view->display_handler->overrideOption('test_option', 'Test option title');
|
||||
$view->save();
|
||||
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
|
||||
// Test we have our custom <h1> tag in the output of the view.
|
||||
$this->assertTrue(strpos($output, '<h1>Test option title</h1>') !== FALSE, 'The test_option value found in display output title.');
|
||||
|
||||
// Test that the display category/summary is in the UI.
|
||||
$this->drupalGet('admin/structure/views/view/test_view/edit/display_test_1');
|
||||
$this->assertText('Display test settings');
|
||||
// Ensure that the order is as expected.
|
||||
$result = $this->xpath('//ul[@id="views-display-menu-tabs"]/li/a/child::text()');
|
||||
$this->assertEqual($result[0]->getText(), 'Display test 2');
|
||||
$this->assertEqual($result[1]->getText(), 'Display test');
|
||||
|
||||
$this->clickLink('Test option title');
|
||||
|
||||
$test_option = $this->randomString();
|
||||
$this->drupalPostForm(NULL, ['test_option' => $test_option], t('Apply'));
|
||||
|
||||
// Check the new value has been saved by checking the UI summary text.
|
||||
$this->drupalGet('admin/structure/views/view/test_view/edit/display_test_1');
|
||||
$this->assertLink($test_option);
|
||||
|
||||
// Test the enable/disable status of a display.
|
||||
$view->display_handler->setOption('enabled', FALSE);
|
||||
$this->assertFalse($view->display_handler->isEnabled(), 'Make sure that isEnabled returns FALSE on a disabled display.');
|
||||
$view->display_handler->setOption('enabled', TRUE);
|
||||
$this->assertTrue($view->display_handler->isEnabled(), 'Make sure that isEnabled returns TRUE on a disabled display.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the overriding of filter_groups.
|
||||
*/
|
||||
public function testFilterGroupsOverriding() {
|
||||
$view = Views::getView('test_filter_groups');
|
||||
$view->initDisplay();
|
||||
|
||||
// mark is as overridden, yes FALSE, means overridden.
|
||||
$view->displayHandlers->get('page')->setOverride('filter_groups', FALSE);
|
||||
$this->assertFalse($view->displayHandlers->get('page')->isDefaulted('filter_groups'), "Make sure that 'filter_groups' is marked as overridden.");
|
||||
$this->assertFalse($view->displayHandlers->get('page')->isDefaulted('filters'), "Make sure that 'filters'' is marked as overridden.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the getAttachedDisplays method.
|
||||
*/
|
||||
public function testGetAttachedDisplays() {
|
||||
$view = Views::getView('test_get_attach_displays');
|
||||
|
||||
// Both the feed_1 and the feed_2 display are attached to the page display.
|
||||
$view->setDisplay('page_1');
|
||||
$this->assertEqual($view->display_handler->getAttachedDisplays(), ['feed_1', 'feed_2']);
|
||||
|
||||
$view->setDisplay('feed_1');
|
||||
$this->assertEqual($view->display_handler->getAttachedDisplays(), []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the readmore validation.
|
||||
*/
|
||||
public function testReadMoreNoDisplay() {
|
||||
$view = Views::getView('test_display_more');
|
||||
// Confirm that the view validates when there is a page display.
|
||||
$errors = $view->validate();
|
||||
$this->assertTrue(empty($errors), 'More link validation has no errors.');
|
||||
|
||||
// Confirm that the view does not validate when the page display is disabled.
|
||||
$view->setDisplay('page_1');
|
||||
$view->display_handler->setOption('enabled', FALSE);
|
||||
$view->setDisplay('default');
|
||||
$errors = $view->validate();
|
||||
$this->assertTrue(!empty($errors), 'More link validation has some errors.');
|
||||
$this->assertEqual($errors['default'][0], 'Display "Master" uses a "more" link but there are no displays it can link to. You need to specify a custom URL.', 'More link validation has the right error.');
|
||||
|
||||
// Confirm that the view does not validate when the page display does not exist.
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay('default');
|
||||
$view->display_handler->setOption('use_more', 1);
|
||||
$errors = $view->validate();
|
||||
$this->assertTrue(!empty($errors), 'More link validation has some errors.');
|
||||
$this->assertEqual($errors['default'][0], 'Display "Master" uses a "more" link but there are no displays it can link to. You need to specify a custom URL.', 'More link validation has the right error.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests invalid display plugins.
|
||||
*/
|
||||
public function testInvalidDisplayPlugins() {
|
||||
$this->drupalGet('test_display_invalid');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Change the page plugin id to an invalid one. Bypass the entity system
|
||||
// so no menu rebuild was executed (so the path is still available).
|
||||
$config = $this->config('views.view.test_display_invalid');
|
||||
$config->set('display.page_1.display_plugin', 'invalid');
|
||||
$config->save();
|
||||
|
||||
$this->drupalGet('test_display_invalid');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('The "invalid" plugin does not exist.');
|
||||
|
||||
// Rebuild the router, and ensure that the path is not accessible anymore.
|
||||
views_invalidate_cache();
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
|
||||
$this->drupalGet('test_display_invalid');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Change the display plugin ID back to the correct ID.
|
||||
$config = $this->config('views.view.test_display_invalid');
|
||||
$config->set('display.page_1.display_plugin', 'page');
|
||||
$config->save();
|
||||
|
||||
// Place the block display.
|
||||
$block = $this->drupalPlaceBlock('views_block:test_display_invalid-block_1', ['label' => 'Invalid display']);
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertResponse(200);
|
||||
$result = $this->xpath('//div[@id = :id]', [':id' => 'block-' . $block->id()]);
|
||||
$this->assertEquals(1, count($result));
|
||||
|
||||
// Change the block plugin ID to an invalid one.
|
||||
$config = $this->config('views.view.test_display_invalid');
|
||||
$config->set('display.block_1.display_plugin', 'invalid');
|
||||
$config->save();
|
||||
|
||||
// Test the page is still displayed, the block not present, and has the
|
||||
// plugin warning message.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('The "invalid" plugin does not exist.');
|
||||
$result = $this->xpath('//div[@id = :id]', [':id' => 'block-' . $block->id()]);
|
||||
$this->assertEquals(0, count($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests display validation when a required relationship is missing.
|
||||
*/
|
||||
public function testMissingRelationship() {
|
||||
$view = Views::getView('test_exposed_relationship_admin_ui');
|
||||
|
||||
// Remove the relationship that is not used by other handlers.
|
||||
$view->removeHandler('default', 'relationship', 'uid_1');
|
||||
$errors = $view->validate();
|
||||
// Check that no error message is shown.
|
||||
$this->assertTrue(empty($errors['default']), 'No errors found when removing unused relationship.');
|
||||
|
||||
// Unset cached relationships (see DisplayPluginBase::getHandlers())
|
||||
unset($view->display_handler->handlers['relationship']);
|
||||
|
||||
// Remove the relationship used by other handlers.
|
||||
$view->removeHandler('default', 'relationship', 'uid');
|
||||
// Validate display
|
||||
$errors = $view->validate();
|
||||
// Check that the error messages are shown.
|
||||
$this->assertTrue(count($errors['default']) == 2, 'Error messages found for required relationship');
|
||||
$this->assertEqual($errors['default'][0], t('The %handler_type %handler uses a relationship that has been removed.', ['%handler_type' => 'field', '%handler' => 'User: Last login']));
|
||||
$this->assertEqual($errors['default'][1], t('The %handler_type %handler uses a relationship that has been removed.', ['%handler_type' => 'field', '%handler' => 'User: Created']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the outputIsEmpty method on the display.
|
||||
*/
|
||||
public function testOutputIsEmpty() {
|
||||
$view = Views::getView('test_display_empty');
|
||||
$this->executeView($view);
|
||||
$this->assertTrue(count($view->result) > 0, 'Ensure the result of the view is not empty.');
|
||||
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty.');
|
||||
$view->destroy();
|
||||
|
||||
// Add a filter, so the view result is empty.
|
||||
$view->setDisplay('default');
|
||||
$item = [
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'id',
|
||||
'id' => 'id',
|
||||
'value' => ['value' => 7297]
|
||||
];
|
||||
$view->setHandler('default', 'filter', 'id', $item);
|
||||
$this->executeView($view);
|
||||
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
|
||||
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the empty text still appears.');
|
||||
$view->destroy();
|
||||
|
||||
// Remove the empty area, but mark the header area to still appear.
|
||||
$view->removeHandler('default', 'empty', 'area');
|
||||
$item = $view->getHandler('default', 'header', 'area');
|
||||
$item['empty'] = TRUE;
|
||||
$view->setHandler('default', 'header', 'area', $item);
|
||||
$this->executeView($view);
|
||||
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
|
||||
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the header text still appears.');
|
||||
$view->destroy();
|
||||
|
||||
// Hide the header on empty results.
|
||||
$item = $view->getHandler('default', 'header', 'area');
|
||||
$item['empty'] = FALSE;
|
||||
$view->setHandler('default', 'header', 'area', $item);
|
||||
$this->executeView($view);
|
||||
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
|
||||
$this->assertTrue($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as empty.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translation rendering settings based on entity translatability.
|
||||
*/
|
||||
public function testTranslationSetting() {
|
||||
\Drupal::service('module_installer')->install(['file']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// By default there should be no language settings.
|
||||
$this->checkTranslationSetting();
|
||||
\Drupal::service('module_installer')->install(['language']);
|
||||
|
||||
// Enabling the language module should not make a difference.
|
||||
$this->checkTranslationSetting();
|
||||
|
||||
// Making the site multilingual should let translatable entity types support
|
||||
// translation rendering.
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
$this->checkTranslationSetting(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a node and a file based view for the translation setting.
|
||||
*
|
||||
* The file based view should never expose that setting. The node based view
|
||||
* should if the site is multilingual.
|
||||
*
|
||||
* @param bool $expected_node_translatability
|
||||
* Whether the node based view should be expected to support translation
|
||||
* settings.
|
||||
*/
|
||||
protected function checkTranslationSetting($expected_node_translatability = FALSE) {
|
||||
$not_supported_text = 'The view is not based on a translatable entity type or the site is not multilingual.';
|
||||
$supported_text = 'All content that supports translations will be displayed in the selected language.';
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/display/content/page_1/rendering_language');
|
||||
if ($expected_node_translatability) {
|
||||
$this->assertNoText($not_supported_text);
|
||||
$this->assertText($supported_text);
|
||||
}
|
||||
else {
|
||||
$this->assertText($not_supported_text);
|
||||
$this->assertNoText($supported_text);
|
||||
}
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/display/files/page_1/rendering_language');
|
||||
$this->assertText($not_supported_text);
|
||||
$this->assertNoText($supported_text);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests exposed forms functionality.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ExposedFormTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_exposed_form_buttons', 'test_exposed_block', 'test_exposed_form_sort_items_per_page'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui', 'block', 'entity_test'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
|
||||
// Create some random nodes.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->drupalCreateNode(['type' => 'article']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the submit button.
|
||||
*/
|
||||
public function testSubmitButton() {
|
||||
// Test the submit button value defaults to 'Apply'.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->assertResponse(200);
|
||||
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
|
||||
|
||||
// Rename the label of the submit button.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$view->setDisplay();
|
||||
|
||||
$exposed_form = $view->display_handler->getOption('exposed_form');
|
||||
$exposed_form['options']['submit_button'] = $expected_label = $this->randomMachineName();
|
||||
$view->display_handler->setOption('exposed_form', $exposed_form);
|
||||
$view->save();
|
||||
|
||||
// Make sure the submit button label changed.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', $expected_label);
|
||||
|
||||
// Make sure an empty label uses the default 'Apply' button value too.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$view->setDisplay();
|
||||
|
||||
$exposed_form = $view->display_handler->getOption('exposed_form');
|
||||
$exposed_form['options']['submit_button'] = '';
|
||||
$view->display_handler->setOption('exposed_form', $exposed_form);
|
||||
$view->save();
|
||||
|
||||
// Make sure the submit button label shows 'Apply'.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the exposed form with a non-standard identifier.
|
||||
*/
|
||||
public function testExposedIdentifier() {
|
||||
// Alter the identifier of the filter to a random string.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$view->setDisplay();
|
||||
$identifier = 'new_identifier';
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'type' => [
|
||||
'exposed' => TRUE,
|
||||
'field' => 'type',
|
||||
'id' => 'type',
|
||||
'table' => 'node_field_data',
|
||||
'plugin_id' => 'in_operator',
|
||||
'entity_type' => 'node',
|
||||
'entity_field' => 'type',
|
||||
'expose' => [
|
||||
'identifier' => $identifier,
|
||||
'label' => 'Content: Type',
|
||||
'operator_id' => 'type_op',
|
||||
'reduce' => FALSE,
|
||||
'description' => 'Exposed overridden description'
|
||||
],
|
||||
]
|
||||
]);
|
||||
$view->save();
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => [$identifier => 'article']]);
|
||||
$this->assertFieldById(Html::getId('edit-' . $identifier), 'article', "Article type filter set with new identifier.");
|
||||
|
||||
// Alter the identifier of the filter to a random string containing
|
||||
// restricted characters.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$view->setDisplay();
|
||||
$identifier = 'bad identifier';
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'type' => [
|
||||
'exposed' => TRUE,
|
||||
'field' => 'type',
|
||||
'id' => 'type',
|
||||
'table' => 'node_field_data',
|
||||
'plugin_id' => 'in_operator',
|
||||
'entity_type' => 'node',
|
||||
'entity_field' => 'type',
|
||||
'expose' => [
|
||||
'identifier' => $identifier,
|
||||
'label' => 'Content: Type',
|
||||
'operator_id' => 'type_op',
|
||||
'reduce' => FALSE,
|
||||
'description' => 'Exposed overridden description'
|
||||
],
|
||||
]
|
||||
]);
|
||||
$this->executeView($view);
|
||||
|
||||
$errors = $view->validate();
|
||||
$expected = [
|
||||
'default' => ['This identifier has illegal characters.'],
|
||||
'page_1' => ['This identifier has illegal characters.'],
|
||||
];
|
||||
$this->assertEqual($errors, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the reset button works on an exposed form.
|
||||
*/
|
||||
public function testResetButton() {
|
||||
// Test the button is hidden when there is no exposed input.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->assertNoField('edit-reset');
|
||||
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
|
||||
// Test that the type has been set.
|
||||
$this->assertFieldById('edit-type', 'article', 'Article type filter set.');
|
||||
|
||||
// Test the reset works.
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['op' => 'Reset']]);
|
||||
$this->assertResponse(200);
|
||||
// Test the type has been reset.
|
||||
$this->assertFieldById('edit-type', 'All', 'Article type filter has been reset.');
|
||||
|
||||
// Test the button is hidden after reset.
|
||||
$this->assertNoField('edit-reset');
|
||||
|
||||
// Test the reset works with type set.
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article', 'op' => 'Reset']]);
|
||||
$this->assertResponse(200);
|
||||
$this->assertFieldById('edit-type', 'All', 'Article type filter has been reset.');
|
||||
|
||||
// Test the button is hidden after reset.
|
||||
$this->assertNoField('edit-reset');
|
||||
|
||||
// Rename the label of the reset button.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$view->setDisplay();
|
||||
|
||||
$exposed_form = $view->display_handler->getOption('exposed_form');
|
||||
$exposed_form['options']['reset_button_label'] = $expected_label = $this->randomMachineName();
|
||||
$exposed_form['options']['reset_button'] = TRUE;
|
||||
$view->display_handler->setOption('exposed_form', $exposed_form);
|
||||
$view->save();
|
||||
|
||||
// Look whether the reset button label changed.
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->helperButtonHasLabel('edit-reset', $expected_label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests overriding the default render option with checkboxes.
|
||||
*/
|
||||
public function testExposedFormRenderCheckboxes() {
|
||||
// Make sure we have at least two options for node type.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->drupalCreateNode(['type' => 'page']);
|
||||
|
||||
// Use a test theme to convert multi-select elements into checkboxes.
|
||||
\Drupal::service('theme_handler')->install(['views_test_checkboxes_theme']);
|
||||
$this->config('system.theme')
|
||||
->set('default', 'views_test_checkboxes_theme')
|
||||
->save();
|
||||
|
||||
// Set the "type" filter to multi-select.
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$filter = $view->getHandler('page_1', 'filter', 'type');
|
||||
$filter['expose']['multiple'] = TRUE;
|
||||
$view->setHandler('page_1', 'filter', 'type', $filter);
|
||||
|
||||
// Only display 5 items per page so we can test that paging works.
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['pager']['options']['items_per_page'] = 5;
|
||||
|
||||
$view->save();
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
|
||||
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[article]"]');
|
||||
$this->assertEqual(count($actual), 1, 'Article option renders as a checkbox.');
|
||||
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[page]"]');
|
||||
$this->assertEqual(count($actual), 1, 'Page option renders as a checkbox');
|
||||
|
||||
// Ensure that all results are displayed.
|
||||
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
|
||||
$this->assertEqual(count($rows), 5, '5 rows are displayed by default on the first page when no options are checked.');
|
||||
|
||||
$this->clickLink('Page 2');
|
||||
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
|
||||
$this->assertEqual(count($rows), 1, '1 row is displayed by default on the second page when no options are checked.');
|
||||
$this->assertNoText('An illegal choice has been detected. Please contact the site administrator.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the exposed block functionality.
|
||||
*/
|
||||
public function testExposedBlock() {
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$view = Views::getView('test_exposed_block');
|
||||
$view->setDisplay('page_1');
|
||||
$block = $this->drupalPlaceBlock('views_exposed_filter_block:test_exposed_block-page_1');
|
||||
$this->drupalGet('test_exposed_block');
|
||||
|
||||
// Test there is an exposed form in a block.
|
||||
$xpath = $this->buildXPathQuery('//div[@id=:id]/form/@id', [':id' => Html::getUniqueId('block-' . $block->id())]);
|
||||
$result = $this->xpath($xpath);
|
||||
$this->assertEquals(1, count($result));
|
||||
|
||||
// Test there is not an exposed form in the view page content area.
|
||||
$xpath = $this->buildXPathQuery('//div[@class="view-content"]/form/@id', [':id' => Html::getUniqueId('block-' . $block->id())]);
|
||||
$this->assertNoFieldByXpath($xpath, $this->getExpectedExposedFormId($view), 'No exposed form found in views content region.');
|
||||
|
||||
// Test there is only one views exposed form on the page.
|
||||
$elements = $this->xpath('//form[@id=:id]', [':id' => $this->getExpectedExposedFormId($view)]);
|
||||
$this->assertEqual(count($elements), 1, 'One exposed form block found.');
|
||||
|
||||
// Test that the correct option is selected after form submission.
|
||||
$this->assertCacheContext('url');
|
||||
$this->assertOptionSelected('edit-type', 'All');
|
||||
foreach (['All', 'article', 'page'] as $argument) {
|
||||
$this->drupalGet('test_exposed_block', ['query' => ['type' => $argument]]);
|
||||
$this->assertCacheContext('url');
|
||||
$this->assertOptionSelected('edit-type', $argument);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the input required exposed form type.
|
||||
*/
|
||||
public function testInputRequired() {
|
||||
$view = View::load('test_exposed_form_buttons');
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['exposed_form']['type'] = 'input_required';
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->assertResponse(200);
|
||||
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
|
||||
|
||||
// Ensure that no results are displayed.
|
||||
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
|
||||
$this->assertEqual(count($rows), 0, 'No rows are displayed by default when no input is provided.');
|
||||
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
|
||||
|
||||
// Ensure that results are displayed.
|
||||
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
|
||||
$this->assertEqual(count($rows), 5, 'All rows are displayed by default when input is provided.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the "on demand text" for the input required exposed form type.
|
||||
*/
|
||||
public function testTextInputRequired() {
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['exposed_form']['type'] = 'input_required';
|
||||
// Set up the "on demand text".
|
||||
// @see https://www.drupal.org/node/535868
|
||||
$on_demand_text = 'Select any filter and click Apply to see results.';
|
||||
$display['display_options']['exposed_form']['options']['text_input_required'] = $on_demand_text;
|
||||
$display['display_options']['exposed_form']['options']['text_input_required_format'] = filter_default_format();
|
||||
$view->save();
|
||||
|
||||
// Ensure that the "on demand text" is displayed when no exposed filters are
|
||||
// applied.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->assertText('Select any filter and click Apply to see results.');
|
||||
|
||||
// Ensure that the "on demand text" is not displayed when an exposed filter
|
||||
// is applied.
|
||||
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
|
||||
$this->assertNoText($on_demand_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exposed forms with exposed sort and items per page.
|
||||
*/
|
||||
public function testExposedSortAndItemsPerPage() {
|
||||
for ($i = 0; $i < 50; $i++) {
|
||||
$entity = EntityTest::create([
|
||||
]);
|
||||
$entity->save();
|
||||
}
|
||||
$contexts = [
|
||||
'languages:language_interface',
|
||||
'entity_test_view_grants',
|
||||
'theme',
|
||||
'url.query_args',
|
||||
'languages:language_content'
|
||||
];
|
||||
|
||||
$this->drupalGet('test_exposed_form_sort_items_per_page');
|
||||
$this->assertCacheContexts($contexts);
|
||||
$this->assertIds(range(1, 10, 1));
|
||||
|
||||
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC']]);
|
||||
$this->assertCacheContexts($contexts);
|
||||
$this->assertIds(range(50, 41, 1));
|
||||
|
||||
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC', 'items_per_page' => 25]]);
|
||||
$this->assertCacheContexts($contexts);
|
||||
$this->assertIds(range(50, 26, 1));
|
||||
|
||||
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC', 'items_per_page' => 25, 'offset' => 10]]);
|
||||
$this->assertCacheContexts($contexts);
|
||||
$this->assertIds(range(40, 16, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified ids are the ones displayed in the view output.
|
||||
*
|
||||
* @param int[] $ids
|
||||
* The ids to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if ids match, FALSE otherwise.
|
||||
*/
|
||||
protected function assertIds(array $ids) {
|
||||
$elements = $this->cssSelect('div.view-test-exposed-form-sort-items-per-page div.views-row span.field-content');
|
||||
$actual_ids = [];
|
||||
foreach ($elements as $element) {
|
||||
$actual_ids[] = (int) $element->getText();
|
||||
}
|
||||
|
||||
return $this->assertIdentical($ids, $actual_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a views exposed form ID.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view to create an ID for.
|
||||
*
|
||||
* @return string
|
||||
* The form ID.
|
||||
*/
|
||||
protected function getExpectedExposedFormId(ViewExecutable $view) {
|
||||
return Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a view which is rendered after a form with a validation error.
|
||||
*/
|
||||
public function testFormErrorWithExposedForm() {
|
||||
$this->drupalGet('views_test_data_error_form_page');
|
||||
$this->assertResponse(200);
|
||||
$form = $this->cssSelect('form.views-exposed-form');
|
||||
$this->assertTrue($form, 'The exposed form element was found.');
|
||||
$this->assertRaw(t('Apply'), 'Ensure the exposed form is rendered before submitting the normal form.');
|
||||
$this->assertRaw('<div class="views-row">', 'Views result shown.');
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Submit'));
|
||||
$this->assertResponse(200);
|
||||
$form = $this->cssSelect('form.views-exposed-form');
|
||||
$this->assertTrue($form, 'The exposed form element was found.');
|
||||
$this->assertRaw(t('Apply'), 'Ensure the exposed form is rendered after submitting the normal form.');
|
||||
$this->assertRaw('<div class="views-row">', 'Views result shown.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views_test_data\Plugin\views\filter\FilterTest as FilterPlugin;
|
||||
|
||||
/**
|
||||
* Tests general filter plugin functionality.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\filter\FilterPluginBase
|
||||
*/
|
||||
class FilterTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_filter', 'test_filter_in_operator_ui'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views_ui', 'node'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['administer views']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views_test_data']['name']['filter']['id'] = 'test_filter';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test query of the row plugin.
|
||||
*/
|
||||
public function testFilterQuery() {
|
||||
// Check that we can find the test filter plugin.
|
||||
$plugin = $this->container->get('plugin.manager.views.filter')->createInstance('test_filter');
|
||||
$this->assertTrue($plugin instanceof FilterPlugin, 'Test filter plugin found.');
|
||||
|
||||
$view = Views::getView('test_filter');
|
||||
$view->initDisplay();
|
||||
|
||||
// Change the filtering.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'test_filter' => [
|
||||
'id' => 'test_filter',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'operator' => '=',
|
||||
'value' => 'John',
|
||||
'group' => 0,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Make sure the query have where data.
|
||||
$this->assertTrue(!empty($view->query->where));
|
||||
|
||||
// Check the data added.
|
||||
$where = $view->query->where;
|
||||
$this->assertIdentical($where[0]['conditions'][0]['field'], 'views_test_data.name', 'Where condition field matches');
|
||||
$this->assertIdentical($where[0]['conditions'][0]['value'], 'John', 'Where condition value matches');
|
||||
$this->assertIdentical($where[0]['conditions'][0]['operator'], '=', 'Where condition operator matches');
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Check that our operator and value match on the filter.
|
||||
$this->assertIdentical($view->filter['test_filter']->operator, '=');
|
||||
$this->assertIdentical($view->filter['test_filter']->value, 'John');
|
||||
|
||||
// Check that we have a single element, as a result of applying the '= John'
|
||||
// filter.
|
||||
$this->assertEqual(count($view->result), 1, format_string('Results were returned. @count results.', ['@count' => count($view->result)]));
|
||||
|
||||
$view->destroy();
|
||||
|
||||
$view->initDisplay();
|
||||
|
||||
// Change the filtering.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'test_filter' => [
|
||||
'id' => 'test_filter',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'operator' => '<>',
|
||||
'value' => 'John',
|
||||
'group' => 0,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
// Check that our operator and value match on the filter.
|
||||
$this->assertIdentical($view->filter['test_filter']->operator, '<>');
|
||||
$this->assertIdentical($view->filter['test_filter']->value, 'John');
|
||||
|
||||
// Check if we have the other elements in the dataset, as a result of
|
||||
// applying the '<> John' filter.
|
||||
$this->assertEqual(count($view->result), 4, format_string('Results were returned. @count results.', ['@count' => count($view->result)]));
|
||||
|
||||
$view->destroy();
|
||||
$view->initDisplay();
|
||||
|
||||
// Set the test_enable option to FALSE. The 'where' clause should not be
|
||||
// added to the query.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'test_filter' => [
|
||||
'id' => 'test_filter',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'operator' => '<>',
|
||||
'value' => 'John',
|
||||
'group' => 0,
|
||||
// Disable this option, so nothing should be added to the query.
|
||||
'test_enable' => FALSE,
|
||||
],
|
||||
]);
|
||||
|
||||
// Execute the view again.
|
||||
$this->executeView($view);
|
||||
|
||||
// Check if we have all 5 results.
|
||||
$this->assertEqual(count($view->result), 5, format_string('All @count results returned', ['@count' => count($view->displayHandlers)]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test no error message is displayed when all options are selected in an
|
||||
* exposed filter.
|
||||
*/
|
||||
public function testInOperatorSelectAllOptions() {
|
||||
$view = Views::getView('test_filter_in_operator_ui');
|
||||
$row['row[type]'] = 'fields';
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_in_operator_ui/default/row', $row, t('Apply'));
|
||||
$field['name[node_field_data.nid]'] = TRUE;
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_filter_in_operator_ui/default/field', $field, t('Add and configure fields'));
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/field/nid', [], t('Apply'));
|
||||
$edit['options[value][all]'] = TRUE;
|
||||
$edit['options[value][article]'] = TRUE;
|
||||
$edit['options[value][page]'] = TRUE;
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/filter/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_in_operator_ui/edit/default', [], t('Save'));
|
||||
$this->drupalPostForm(NULL, [], t('Update preview'));
|
||||
$this->assertNoText('An illegal choice has been detected.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the menu links created in views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class MenuLinkTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_menu_link'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views', 'views_ui', 'user', 'node', 'menu_ui', 'block'];
|
||||
|
||||
/**
|
||||
* A user with permission to administer views, menus and view content.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['administer views', 'administer menu']);
|
||||
$this->drupalPlaceBlock('system_menu_block:main');
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that menu links using menu_link_content as parent are visible.
|
||||
*/
|
||||
public function testHierarchicalMenuLinkVisibility() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$node = $this->drupalCreateNode(['type' => 'page']);
|
||||
|
||||
// Create a primary level menu link to the node.
|
||||
$link = MenuLinkContent::create([
|
||||
'title' => 'Primary level node',
|
||||
'menu_name' => 'main',
|
||||
'bundle' => 'menu_link_content',
|
||||
'parent' => '',
|
||||
'link' => [['uri' => 'entity:node/' . $node->id()]],
|
||||
]);
|
||||
$link->save();
|
||||
|
||||
$parent_menu_value = 'main:menu_link_content:' . $link->uuid();
|
||||
|
||||
// Alter the view's menu link in view page to use the menu link from the
|
||||
// node as parent.
|
||||
$this->drupalPostForm("admin/structure/views/nojs/display/test_menu_link/page_1/menu", [
|
||||
'menu[type]' => 'normal',
|
||||
'menu[title]' => 'Secondary level view page',
|
||||
'menu[parent]' => $parent_menu_value,
|
||||
], 'Apply');
|
||||
|
||||
// Save view which has pending changes.
|
||||
$this->drupalPostForm(NULL, [], 'Save');
|
||||
|
||||
// Test if the node as parent menu item is selected in our views settings.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_menu_link/page_1/menu');
|
||||
$this->assertOptionSelected('edit-menu-parent', $parent_menu_value);
|
||||
|
||||
$this->drupalGet('');
|
||||
|
||||
// Test if the primary menu item (node) is visible, and the secondary menu
|
||||
// item (view) is hidden.
|
||||
$this->assertText('Primary level node');
|
||||
$this->assertNoText('Secondary level view page');
|
||||
|
||||
// Go to the node page and ensure that both the first and second level items
|
||||
// are visible.
|
||||
$this->drupalGet($node->urlInfo());
|
||||
$this->assertText('Primary level node');
|
||||
$this->assertText('Secondary level view page');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the mini pager plugin.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\pager\Mini
|
||||
*/
|
||||
class MiniPagerTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_mini_pager'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* Nodes used by the test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
// Create a bunch of test nodes.
|
||||
for ($i = 0; $i < 20; $i++) {
|
||||
$this->nodes[] = $this->drupalCreateNode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the rendering of mini pagers.
|
||||
*/
|
||||
public function testMiniPagerRender() {
|
||||
$this->drupalGet('test_mini_pager');
|
||||
$this->assertText('›› test', 'The next link appears on the first page.');
|
||||
$this->assertText('Page 1', 'The current page info shows the first page.');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the first page.');
|
||||
$this->assertText($this->nodes[0]->label());
|
||||
$this->assertText($this->nodes[1]->label());
|
||||
$this->assertText($this->nodes[2]->label());
|
||||
|
||||
$this->drupalGet('test_mini_pager', ['query' => ['page' => 1]]);
|
||||
$this->assertText('‹‹ test', 'The previous link appears.');
|
||||
$this->assertText('Page 2', 'The current page info shows the second page.');
|
||||
$this->assertText('›› test', 'The next link appears.');
|
||||
$this->assertText($this->nodes[3]->label());
|
||||
$this->assertText($this->nodes[4]->label());
|
||||
$this->assertText($this->nodes[5]->label());
|
||||
|
||||
$this->drupalGet('test_mini_pager', ['query' => ['page' => 6]]);
|
||||
$this->assertNoText('›› test', 'The next link appears on the last page.');
|
||||
$this->assertText('Page 7', 'The current page info shows the last page.');
|
||||
$this->assertText('‹‹ test', 'The previous link does not appear on the last page.');
|
||||
$this->assertText($this->nodes[18]->label());
|
||||
$this->assertText($this->nodes[19]->label());
|
||||
|
||||
// Test @total value in result summary
|
||||
$view = Views::getView('test_mini_pager');
|
||||
$view->setDisplay('page_4');
|
||||
$this->executeView($view);
|
||||
$this->assertIdentical($view->get_total_rows, TRUE, 'The query was set to calculate the total number of rows.');
|
||||
$this->assertEqual(count($this->nodes), $view->total_rows, 'The total row count is equal to the number of nodes.');
|
||||
|
||||
$this->drupalGet('test_mini_pager_total', ['query' => ['page' => 1]]);
|
||||
$this->assertText('of ' . count($this->nodes), 'The first page shows the total row count.');
|
||||
$this->drupalGet('test_mini_pager_total', ['query' => ['page' => 6]]);
|
||||
$this->assertText('of ' . count($this->nodes), 'The last page shows the total row count.');
|
||||
|
||||
// Test a mini pager with just one item per page.
|
||||
$this->drupalGet('test_mini_pager_one');
|
||||
$this->assertText('››');
|
||||
$this->assertText('Page 1');
|
||||
$this->assertText($this->nodes[0]->label());
|
||||
|
||||
$this->drupalGet('test_mini_pager_one', ['query' => ['page' => 1]]);
|
||||
$this->assertText('‹‹');
|
||||
$this->assertText('Page 2');
|
||||
$this->assertText('››');
|
||||
$this->assertText($this->nodes[1]->label());
|
||||
|
||||
$this->drupalGet('test_mini_pager_one', ['query' => ['page' => 19]]);
|
||||
$this->assertNoText('››');
|
||||
$this->assertText('Page 20');
|
||||
$this->assertText('‹‹');
|
||||
$this->assertText($this->nodes[19]->label());
|
||||
|
||||
$this->drupalGet('test_mini_pager_all');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
|
||||
$this->assertNoText('Page 1', 'The current page info shows the only page.');
|
||||
$this->assertNoText('test ››', 'The next link does not appear on the page.');
|
||||
$result = $this->xpath('//div[contains(@class, "views-row")]');
|
||||
$this->assertEqual(count($result), count($this->nodes), 'All rows appear on the page.');
|
||||
|
||||
// Remove all items beside 1, so there should be no links shown.
|
||||
for ($i = 0; $i < 19; $i++) {
|
||||
$this->nodes[$i]->delete();
|
||||
}
|
||||
|
||||
$this->drupalGet('test_mini_pager');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
|
||||
$this->assertNoText('Page 1', 'The current page info shows the only page.');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
|
||||
$this->assertText($this->nodes[19]->label());
|
||||
|
||||
$view = Views::getView('test_mini_pager');
|
||||
$this->executeView($view);
|
||||
$this->assertIdentical($view->get_total_rows, NULL, 'The query was not forced to calculate the total number of results.');
|
||||
$this->assertIdentical($view->total_rows, 1, 'The pager calculated the total number of rows.');
|
||||
|
||||
// Remove the last node as well and ensure that no "Page 1" is shown.
|
||||
$this->nodes[19]->delete();
|
||||
$this->drupalGet('test_mini_pager');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
|
||||
$this->assertNoText('Page 1', 'The current page info shows the only page.');
|
||||
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Component\Gettext\PoHeader;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the creation of numeric fields.
|
||||
*
|
||||
* @group field
|
||||
*/
|
||||
class NumericFormatPluralTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views_ui', 'file', 'language', 'locale'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['numeric_test'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$web_user = $this->drupalCreateUser(['administer views', 'administer languages']);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test plural formatting setting on a numeric views handler.
|
||||
*/
|
||||
public function testNumericFormatPlural() {
|
||||
// Create a file.
|
||||
$file = $this->createFile();
|
||||
|
||||
// Assert that the starting configuration is correct.
|
||||
$config = $this->config('views.view.numeric_test');
|
||||
$field_config_prefix = 'display.default.display_options.fields.count.';
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1' . LOCALE_PLURAL_DELIMITER . '@count');
|
||||
|
||||
// Assert that the value is displayed.
|
||||
$this->drupalGet('numeric-test');
|
||||
$this->assertRaw('<span class="field-content">0</span>');
|
||||
|
||||
// Assert that the user interface has controls to change it.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/numeric_test/page_1/field/count');
|
||||
$this->assertFieldByName('options[format_plural_values][0]', '1');
|
||||
$this->assertFieldByName('options[format_plural_values][1]', '@count');
|
||||
|
||||
// Assert that changing the settings will change configuration properly.
|
||||
$edit = ['options[format_plural_values][0]' => '1 time', 'options[format_plural_values][1]' => '@count times'];
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
$config = $this->config('views.view.numeric_test');
|
||||
$field_config_prefix = 'display.default.display_options.fields.count.';
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1 time' . LOCALE_PLURAL_DELIMITER . '@count times');
|
||||
|
||||
// Assert that the value is displayed with some sample values.
|
||||
$numbers = [0, 1, 2, 3, 4, 42];
|
||||
foreach ($numbers as $i => $number) {
|
||||
\Drupal::service('file.usage')->add($file, 'views_ui', 'dummy', $i, $number);
|
||||
}
|
||||
$this->drupalGet('numeric-test');
|
||||
foreach ($numbers as $i => $number) {
|
||||
$this->assertRaw('<span class="field-content">' . $number . ($number == 1 ? ' time' : ' times') . '</span>');
|
||||
}
|
||||
|
||||
// Add Slovenian and set its plural formula to test multiple plural forms.
|
||||
$edit = ['predefined_langcode' => 'sl'];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
$formula = 'nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);';
|
||||
$header = new PoHeader();
|
||||
list($nplurals, $formula) = $header->parsePluralForms($formula);
|
||||
\Drupal::service('locale.plural.formula')->setPluralFormula('sl', $nplurals, $formula);
|
||||
|
||||
// Change the view to Slovenian.
|
||||
$config = $this->config('views.view.numeric_test');
|
||||
$config->set('langcode', 'sl')->save();
|
||||
|
||||
// Assert that the user interface has controls with more inputs now.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/numeric_test/page_1/field/count');
|
||||
$this->assertFieldByName('options[format_plural_values][0]', '1 time');
|
||||
$this->assertFieldByName('options[format_plural_values][1]', '@count times');
|
||||
$this->assertFieldByName('options[format_plural_values][2]', '');
|
||||
$this->assertFieldByName('options[format_plural_values][3]', '');
|
||||
|
||||
// Assert that changing the settings will change configuration properly.
|
||||
$edit = [
|
||||
'options[format_plural_values][0]' => '@count time0',
|
||||
'options[format_plural_values][1]' => '@count time1',
|
||||
'options[format_plural_values][2]' => '@count time2',
|
||||
'options[format_plural_values][3]' => '@count time3',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$config = $this->config('views.view.numeric_test');
|
||||
$field_config_prefix = 'display.default.display_options.fields.count.';
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
|
||||
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), implode(LOCALE_PLURAL_DELIMITER, array_values($edit)));
|
||||
|
||||
// The view should now use the new plural configuration.
|
||||
$this->drupalGet('sl/numeric-test');
|
||||
$this->assertRaw('<span class="field-content">0 time3</span>');
|
||||
$this->assertRaw('<span class="field-content">1 time0</span>');
|
||||
$this->assertRaw('<span class="field-content">2 time1</span>');
|
||||
$this->assertRaw('<span class="field-content">3 time2</span>');
|
||||
$this->assertRaw('<span class="field-content">4 time2</span>');
|
||||
$this->assertRaw('<span class="field-content">42 time3</span>');
|
||||
|
||||
// Add an English configuration translation with English plurals.
|
||||
$english = \Drupal::languageManager()->getLanguageConfigOverride('en', 'views.view.numeric_test');
|
||||
$english->set('display.default.display_options.fields.count.format_plural_string', '1 time' . LOCALE_PLURAL_DELIMITER . '@count times')->save();
|
||||
|
||||
// The view displayed in English should use the English translation.
|
||||
$this->drupalGet('numeric-test');
|
||||
$this->assertRaw('<span class="field-content">0 times</span>');
|
||||
$this->assertRaw('<span class="field-content">1 time</span>');
|
||||
$this->assertRaw('<span class="field-content">2 times</span>');
|
||||
$this->assertRaw('<span class="field-content">3 times</span>');
|
||||
$this->assertRaw('<span class="field-content">4 times</span>');
|
||||
$this->assertRaw('<span class="field-content">42 times</span>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and saves a test file.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* A file entity.
|
||||
*/
|
||||
protected function createFile() {
|
||||
// Create a new file entity.
|
||||
$file = File::create([
|
||||
'uid' => 1,
|
||||
'filename' => 'druplicon.txt',
|
||||
'uri' => 'public://druplicon.txt',
|
||||
'filemime' => 'text/plain',
|
||||
'created' => 1,
|
||||
'changed' => 1,
|
||||
'status' => FILE_STATUS_PERMANENT,
|
||||
]);
|
||||
file_put_contents($file->getFileUri(), 'hello world');
|
||||
|
||||
// Save it, inserting a new record.
|
||||
$file->save();
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
}
|
454
web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php
Normal file
454
web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php
Normal file
|
@ -0,0 +1,454 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the pluggable pager system.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class PagerTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_store_pager_settings', 'test_pager_none', 'test_pager_some', 'test_pager_full', 'test_view_pager_full_zero_items_per_page', 'test_view', 'content'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui'];
|
||||
|
||||
/**
|
||||
* String translation storage object.
|
||||
*
|
||||
* @var \Drupal\locale\StringStorageInterface
|
||||
*/
|
||||
protected $localeStorage;
|
||||
|
||||
/**
|
||||
* Pagers was sometimes not stored.
|
||||
*
|
||||
* @see https://www.drupal.org/node/652712
|
||||
*/
|
||||
public function testStorePagerSettings() {
|
||||
// Show the master display so the override selection is shown.
|
||||
\Drupal::configFactory()->getEditable('views.settings')->set('ui.show.master_display', TRUE)->save();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
// Test behavior described in
|
||||
// https://www.drupal.org/node/652712#comment-2354918.
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/test_view/edit');
|
||||
|
||||
$edit = [
|
||||
'pager[type]' => 'full',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager', $edit, t('Apply'));
|
||||
$edit = [
|
||||
'pager_options[items_per_page]' => 20,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager_options', $edit, t('Apply'));
|
||||
$this->assertText('20 items');
|
||||
|
||||
// Change type and check whether the type is new type is stored.
|
||||
$edit = [
|
||||
'pager[type]' => 'mini',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager', $edit, t('Apply'));
|
||||
$this->drupalGet('admin/structure/views/view/test_view/edit');
|
||||
$this->assertText('Mini', 'Changed pager plugin, should change some text');
|
||||
|
||||
// Test behavior described in
|
||||
// https://www.drupal.org/node/652712#comment-2354400.
|
||||
$view = Views::getView('test_store_pager_settings');
|
||||
// Make it editable in the admin interface.
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit');
|
||||
|
||||
$edit = [
|
||||
'pager[type]' => 'full',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager', $edit, t('Apply'));
|
||||
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit');
|
||||
$this->assertText('Full');
|
||||
|
||||
$edit = [
|
||||
'pager_options[items_per_page]' => 20,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager_options', $edit, t('Apply'));
|
||||
$this->assertText('20 items');
|
||||
|
||||
// add new display and test the settings again, by override it.
|
||||
$edit = [ ];
|
||||
// Add a display and override the pager settings.
|
||||
$this->drupalPostForm('admin/structure/views/view/test_store_pager_settings/edit', $edit, t('Add Page'));
|
||||
$edit = [
|
||||
'override[dropdown]' => 'page_1',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager', $edit, t('Apply'));
|
||||
|
||||
$edit = [
|
||||
'pager[type]' => 'mini',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager', $edit, t('Apply'));
|
||||
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit/page_1');
|
||||
$this->assertText('Mini', 'Changed pager plugin, should change some text');
|
||||
|
||||
$edit = [
|
||||
'pager_options[items_per_page]' => 10,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager_options', $edit, t('Apply'));
|
||||
$this->assertText('10 items', 'The default value has been changed.');
|
||||
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit/page_1');
|
||||
$this->assertText('20 items', 'The original value remains unchanged.');
|
||||
|
||||
// Test that the override element is only displayed on pager plugin selection form.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager');
|
||||
$this->assertFieldByName('override[dropdown]', 'page_1', 'The override element is displayed on plugin selection form.');
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager_options');
|
||||
$this->assertNoFieldByName('override[dropdown]', NULL, 'The override element is not displayed on plugin settings form.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the none-pager-query.
|
||||
*/
|
||||
public function testNoLimit() {
|
||||
// Create 11 nodes and make sure that everyone is returned.
|
||||
// We create 11 nodes, because the default pager plugin had 10 items per page.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
$view = Views::getView('test_pager_none');
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 11, 'Make sure that every item is returned in the result');
|
||||
|
||||
// Setup and test a offset.
|
||||
$view = Views::getView('test_pager_none');
|
||||
$view->setDisplay();
|
||||
$pager = [
|
||||
'type' => 'none',
|
||||
'options' => [
|
||||
'offset' => 3,
|
||||
],
|
||||
];
|
||||
$view->display_handler->setOption('pager', $pager);
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(count($view->result), 8, 'Make sure that every item beside the first three is returned in the result');
|
||||
|
||||
// Check some public functions.
|
||||
$this->assertFalse($view->pager->usePager());
|
||||
$this->assertFalse($view->pager->useCountQuery());
|
||||
$this->assertEqual($view->pager->getItemsPerPage(), 0);
|
||||
}
|
||||
|
||||
public function testViewTotalRowsWithoutPager() {
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 23; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
$view = Views::getView('test_pager_none');
|
||||
$view->get_total_rows = TRUE;
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual($view->total_rows, 23, "'total_rows' is calculated when pager type is 'none' and 'get_total_rows' is TRUE.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the some pager plugin.
|
||||
*/
|
||||
public function testLimit() {
|
||||
// Create 11 nodes and make sure that everyone is returned.
|
||||
// We create 11 nodes, because the default pager plugin had 10 items per page.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
$view = Views::getView('test_pager_some');
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 5, 'Make sure that only a certain count of items is returned');
|
||||
|
||||
// Setup and test a offset.
|
||||
$view = Views::getView('test_pager_some');
|
||||
$view->setDisplay();
|
||||
$pager = [
|
||||
'type' => 'none',
|
||||
'options' => [
|
||||
'offset' => 8,
|
||||
'items_per_page' => 5,
|
||||
],
|
||||
];
|
||||
$view->display_handler->setOption('pager', $pager);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 3, 'Make sure that only a certain count of items is returned');
|
||||
|
||||
// Check some public functions.
|
||||
$this->assertFalse($view->pager->usePager());
|
||||
$this->assertFalse($view->pager->useCountQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normal pager.
|
||||
*/
|
||||
public function testNormalPager() {
|
||||
// Create 11 nodes and make sure that everyone is returned.
|
||||
// We create 11 nodes, because the default pager plugin had 10 items per page.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
$view = Views::getView('test_pager_full');
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 5, 'Make sure that only a certain count of items is returned');
|
||||
|
||||
// Setup and test a offset.
|
||||
$view = Views::getView('test_pager_full');
|
||||
$view->setDisplay();
|
||||
$pager = [
|
||||
'type' => 'full',
|
||||
'options' => [
|
||||
'offset' => 8,
|
||||
'items_per_page' => 5,
|
||||
],
|
||||
];
|
||||
$view->display_handler->setOption('pager', $pager);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual(count($view->result), 3, 'Make sure that only a certain count of items is returned');
|
||||
|
||||
// Test items per page = 0
|
||||
$view = Views::getView('test_view_pager_full_zero_items_per_page');
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(count($view->result), 11, 'All items are return');
|
||||
|
||||
// TODO test number of pages.
|
||||
|
||||
// Test items per page = 0.
|
||||
// Setup and test a offset.
|
||||
$view = Views::getView('test_pager_full');
|
||||
$view->setDisplay();
|
||||
$pager = [
|
||||
'type' => 'full',
|
||||
'options' => [
|
||||
'offset' => 0,
|
||||
'items_per_page' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$view->display_handler->setOption('pager', $pager);
|
||||
$this->executeView($view);
|
||||
$this->assertEqual($view->pager->getItemsPerPage(), 0);
|
||||
$this->assertEqual(count($view->result), 11);
|
||||
|
||||
// Test pager cache contexts.
|
||||
$this->drupalGet('test_pager_full');
|
||||
$this->assertCacheContexts(['languages:language_interface', 'theme', 'timezone', 'url.query_args', 'user.node_grants:view']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering with NULL pager.
|
||||
*/
|
||||
public function testRenderNullPager() {
|
||||
// Create 11 nodes and make sure that everyone is returned.
|
||||
// We create 11 nodes, because the default pager plugin had 10 items per page.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
$view = Views::getView('test_pager_full');
|
||||
$this->executeView($view);
|
||||
// Force the value again here.
|
||||
$view->setAjaxEnabled(TRUE);
|
||||
$view->pager = NULL;
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->assertEqual(preg_match('/<ul class="pager">/', $output), 0, 'The pager is not rendered.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the api functions on the view object.
|
||||
*/
|
||||
public function testPagerApi() {
|
||||
$view = Views::getView('test_pager_full');
|
||||
$view->setDisplay();
|
||||
// On the first round don't initialize the pager.
|
||||
|
||||
$this->assertEqual($view->getItemsPerPage(), NULL, 'If the pager is not initialized and no manual override there is no items per page.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setItemsPerPage($rand_number);
|
||||
$this->assertEqual($view->getItemsPerPage(), $rand_number, 'Make sure getItemsPerPage uses the settings of setItemsPerPage.');
|
||||
|
||||
$this->assertEqual($view->getOffset(), NULL, 'If the pager is not initialized and no manual override there is no offset.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setOffset($rand_number);
|
||||
$this->assertEqual($view->getOffset(), $rand_number, 'Make sure getOffset uses the settings of setOffset.');
|
||||
|
||||
$this->assertEqual($view->getCurrentPage(), NULL, 'If the pager is not initialized and no manual override there is no current page.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setCurrentPage($rand_number);
|
||||
$this->assertEqual($view->getCurrentPage(), $rand_number, 'Make sure getCurrentPage uses the settings of set_current_page.');
|
||||
|
||||
$view->destroy();
|
||||
|
||||
// On this round enable the pager.
|
||||
$view->initDisplay();
|
||||
$view->initQuery();
|
||||
$view->initPager();
|
||||
|
||||
$this->assertEqual($view->getItemsPerPage(), 5, 'Per default the view has 5 items per page.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setItemsPerPage($rand_number);
|
||||
$rand_number = rand(6, 11);
|
||||
$view->pager->setItemsPerPage($rand_number);
|
||||
$this->assertEqual($view->getItemsPerPage(), $rand_number, 'Make sure getItemsPerPage uses the settings of setItemsPerPage.');
|
||||
|
||||
$this->assertEqual($view->getOffset(), 0, 'Per default a view has a 0 offset.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setOffset($rand_number);
|
||||
$rand_number = rand(6, 11);
|
||||
$view->pager->setOffset($rand_number);
|
||||
$this->assertEqual($view->getOffset(), $rand_number, 'Make sure getOffset uses the settings of setOffset.');
|
||||
|
||||
$this->assertEqual($view->getCurrentPage(), 0, 'Per default the current page is 0.');
|
||||
$rand_number = rand(1, 5);
|
||||
$view->setCurrentPage($rand_number);
|
||||
$rand_number = rand(6, 11);
|
||||
$view->pager->setCurrentPage($rand_number);
|
||||
$this->assertEqual($view->getCurrentPage(), $rand_number, 'Make sure getCurrentPage uses the settings of set_current_page.');
|
||||
|
||||
// Set an invalid page and make sure the method takes care about it.
|
||||
$view->setCurrentPage(-1);
|
||||
$this->assertEqual($view->getCurrentPage(), 0, 'Make sure setCurrentPage always sets a valid page number.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translating the pager using config_translation.
|
||||
*/
|
||||
public function testPagerConfigTranslation() {
|
||||
$view = Views::getView('content');
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['pager']['options']['items_per_page'] = 5;
|
||||
$view->save();
|
||||
|
||||
// Enable locale, config_translation and language module.
|
||||
$this->container->get('module_installer')->install(['locale', 'language', 'config_translation']);
|
||||
$this->resetAll();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access', 'translate configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$langcode = 'nl';
|
||||
|
||||
// Add a default locale storage for this test.
|
||||
$this->localeStorage = $this->container->get('locale.storage');
|
||||
|
||||
// Add Dutch language programmatically.
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
|
||||
$edit = [
|
||||
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][first]' => '« Eerste',
|
||||
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][previous]' => '‹ Vorige',
|
||||
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][next]' => 'Volgende ›',
|
||||
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][last]' => 'Laatste »',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/view/content/translate/nl/edit', $edit, t('Save translation'));
|
||||
|
||||
// We create 11 nodes, this will give us 3 pages.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
// Go to the second page so we see both previous and next buttons.
|
||||
$this->drupalGet('nl/admin/content', ['query' => ['page' => 1]]);
|
||||
// Translation mapping..
|
||||
$labels = [
|
||||
'« First' => '« Eerste',
|
||||
'‹ Previous' => '‹ Vorige',
|
||||
'Next ›' => 'Volgende ›',
|
||||
'Last »' => 'Laatste »',
|
||||
];
|
||||
foreach ($labels as $label => $translation) {
|
||||
// Check if we can find the translation.
|
||||
$this->assertRaw($translation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translating the pager using locale.
|
||||
*/
|
||||
public function testPagerLocale() {
|
||||
// Enable locale and language module.
|
||||
$this->container->get('module_installer')->install(['locale', 'language']);
|
||||
$this->resetAll();
|
||||
$langcode = 'nl';
|
||||
|
||||
// Add a default locale storage for this test.
|
||||
$this->localeStorage = $this->container->get('locale.storage');
|
||||
|
||||
// Add Dutch language programmatically.
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
|
||||
// Labels that need translations.
|
||||
$labels = [
|
||||
'« First' => '« Eerste',
|
||||
'‹ Previous' => '‹ Vorige',
|
||||
'Next ›' => 'Volgende ›',
|
||||
'Last »' => 'Laatste »',
|
||||
];
|
||||
foreach ($labels as $label => $translation) {
|
||||
// Create source string.
|
||||
$source = $this->localeStorage->createString(
|
||||
[
|
||||
'source' => $label
|
||||
]
|
||||
);
|
||||
$source->save();
|
||||
$this->createTranslation($source, $translation, $langcode);
|
||||
}
|
||||
|
||||
// We create 11 nodes, this will give us 3 pages.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
// Go to the second page so we see both previous and next buttons.
|
||||
$this->drupalGet('nl/test_pager_full', ['query' => ['page' => 1]]);
|
||||
foreach ($labels as $label => $translation) {
|
||||
// Check if we can find the translation.
|
||||
$this->assertRaw($translation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates single translation for source string.
|
||||
*/
|
||||
protected function createTranslation($source, $translation, $langcode) {
|
||||
$values = [
|
||||
'lid' => $source->lid,
|
||||
'language' => $langcode,
|
||||
'translation' => $translation,
|
||||
];
|
||||
return $this->localeStorage->createTranslation($values)->save();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the summary style plugin.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class StyleSummaryTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['entity_test', 'views_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_summary'];
|
||||
|
||||
/**
|
||||
* @var \Drupal\entity_test\Entity\EntityTest[]
|
||||
*/
|
||||
protected $entities = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create 5 entities per bundle, to allow a summary overview per bundle.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
for ($j = 0; $j < 5; $j++) {
|
||||
$this->entities[] = $entity = EntityTest::create([
|
||||
'name' => 'Entity ' . ($i * 5 + $j),
|
||||
'type' => 'type' . $i,
|
||||
]);
|
||||
$entity->save();
|
||||
}
|
||||
}
|
||||
|
||||
$views_user = $this->drupalCreateUser(['administer views']);
|
||||
$this->drupalLogin($views_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a summary view.
|
||||
*/
|
||||
public function testSummaryView() {
|
||||
$this->drupalGet('test-summary');
|
||||
|
||||
$summary_list = $this->cssSelect('ul.views-summary li');
|
||||
$this->assertEqual(4, count($summary_list));
|
||||
|
||||
foreach ($summary_list as $summary_list_item) {
|
||||
$this->assertEqual('(5)', trim(explode(' ', $summary_list_item->getText())[1]));
|
||||
}
|
||||
|
||||
$summary_links = $this->cssSelect('ul.views-summary a');
|
||||
$this->assertEqual(4, count($summary_links));
|
||||
foreach ($summary_links as $index => $summary_link) {
|
||||
$this->assertEqual('type' . $index, trim($summary_link->getText()));
|
||||
}
|
||||
|
||||
$this->clickLink('type1');
|
||||
$entries = $this->cssSelect('div.view-content div.views-row');
|
||||
$this->assertEqual(2, count($entries));
|
||||
|
||||
// Add a base path to the summary settings.
|
||||
$edit = [
|
||||
'options[summary][options][default_summary][base_path]' => 'test-summary',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_summary/page_1/argument/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
// Test that the links still work.
|
||||
$this->drupalGet('test-summary');
|
||||
$this->clickLink('type1');
|
||||
$entries = $this->cssSelect('div.view-content div.views-row');
|
||||
$this->assertEqual(2, count($entries));
|
||||
|
||||
// Change the summary display to an unformatted list displaying 3 items.
|
||||
$edit = [
|
||||
'options[summary][format]' => 'unformatted_summary',
|
||||
'options[summary][options][unformatted_summary][override]' => '1',
|
||||
'options[summary][options][unformatted_summary][items_per_page]' => '3',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_summary/page_1/argument/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_summary/page_1/argument/type');
|
||||
$this->drupalGet('test-summary');
|
||||
|
||||
$summary_list = $this->cssSelect('.views-summary-unformatted');
|
||||
$this->assertEqual(3, count($summary_list));
|
||||
|
||||
foreach ($summary_list as $summary_list_item) {
|
||||
$this->assertEqual('(5)', trim(explode(' ', $summary_list_item->getText())[1]));
|
||||
}
|
||||
|
||||
$summary_links = $this->cssSelect('.views-summary-unformatted a');
|
||||
$this->assertEqual(3, count($summary_links));
|
||||
foreach ($summary_links as $index => $summary_link) {
|
||||
$this->assertEqual('type' . $index, trim($summary_link->getText()));
|
||||
}
|
||||
|
||||
$this->clickLink('type1');
|
||||
$entries = $this->cssSelect('div.view-content div.views-row');
|
||||
$this->assertEqual(2, count($entries));
|
||||
|
||||
// Add a base path to the summary settings.
|
||||
$edit = [
|
||||
'options[summary][options][unformatted_summary][base_path]' => 'test-summary',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_summary/page_1/argument/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
|
||||
// Test that the links still work.
|
||||
$this->drupalGet('test-summary');
|
||||
$this->clickLink('type1');
|
||||
$entries = $this->cssSelect('div.view-content div.views-row');
|
||||
$this->assertEqual(2, count($entries));
|
||||
|
||||
// Set base_path to an unknown path and test that the links lead to the
|
||||
// front page.
|
||||
$edit = [
|
||||
'options[summary][options][unformatted_summary][base_path]' => 'unknown-path',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_summary/page_1/argument/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$this->drupalGet('test-summary');
|
||||
$this->assertLinkByHref('/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests the table style views plugin.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class StyleTableTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_table'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test table caption/summary/description.
|
||||
*/
|
||||
public function testAccessibilitySettings() {
|
||||
$this->drupalGet('test-table');
|
||||
|
||||
$result = $this->xpath('//caption/child::text()');
|
||||
$this->assertTrue(count($result), 'The caption appears on the table.');
|
||||
$this->assertEqual(trim($result[0]->getText()), 'caption-text');
|
||||
|
||||
$result = $this->xpath('//summary/child::text()');
|
||||
$this->assertTrue(count($result), 'The summary appears on the table.');
|
||||
$this->assertEqual(trim($result[0]->getText()), 'summary-text');
|
||||
|
||||
$result = $this->xpath('//caption/details/child::text()');
|
||||
$this->assertTrue(count($result), 'The table description appears on the table.');
|
||||
$this->assertEqual(trim($result[0]->getText()), 'description-text');
|
||||
|
||||
// Remove the caption and ensure the caption is not displayed anymore.
|
||||
$view = View::load('test_table');
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['style']['options']['caption'] = '';
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
$result = $this->xpath('//caption/child::text()');
|
||||
$this->assertFalse(trim($result[0]->getText()), 'Ensure that the caption disappears.');
|
||||
|
||||
// Remove the table summary.
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['style']['options']['summary'] = '';
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
$result = $this->xpath('//summary/child::text()');
|
||||
$this->assertFalse(count($result), 'Ensure that the summary disappears.');
|
||||
|
||||
// Remove the table description.
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['style']['options']['description'] = '';
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
$result = $this->xpath('//caption/details/child::text()');
|
||||
$this->assertFalse(count($result), 'Ensure that the description disappears.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test table fields in columns.
|
||||
*/
|
||||
public function testFieldInColumns() {
|
||||
$this->drupalGet('test-table');
|
||||
|
||||
// Ensure that both columns are in separate tds.
|
||||
// Check for class " views-field-job ", because just "views-field-job" won't
|
||||
// do: "views-field-job-1" would also contain "views-field-job".
|
||||
// @see Drupal\system\Tests\Form\ElementTest::testButtonClasses().
|
||||
$result = $this->xpath('//tbody/tr/td[contains(concat(" ", @class, " "), " views-field-job ")]');
|
||||
$this->assertTrue(count($result), 'Ensure there is a td with the class views-field-job');
|
||||
$result = $this->xpath('//tbody/tr/td[contains(concat(" ", @class, " "), " views-field-job-1 ")]');
|
||||
$this->assertTrue(count($result), 'Ensure there is a td with the class views-field-job-1');
|
||||
|
||||
// Combine the second job-column with the first one, with ', ' as separator.
|
||||
$view = View::load('test_table');
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['style']['options']['columns']['job_1'] = 'job';
|
||||
$display['display_options']['style']['options']['info']['job']['separator'] = ', ';
|
||||
$view->save();
|
||||
|
||||
// Ensure that both columns are properly combined.
|
||||
$this->drupalGet('test-table');
|
||||
|
||||
$result = $this->xpath('//tbody/tr/td[contains(concat(" ", @class, " "), " views-field-job views-field-job-1 ")]');
|
||||
$this->assertTrue(count($result), 'Ensure that the job column class names are joined into a single column');
|
||||
|
||||
$result = $this->xpath('//tbody/tr/td[contains(., "Drummer, Drummer")]');
|
||||
$this->assertTrue(count($result), 'Ensure the job column values are joined into a single column');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a number with the value of "0" is displayed in the table.
|
||||
*/
|
||||
public function testNumericFieldVisible() {
|
||||
// Adds a new datapoint in the views_test_data table to have a person with
|
||||
// an age of zero.
|
||||
$data_set = $this->dataSet();
|
||||
$query = db_insert('views_test_data')
|
||||
->fields(array_keys($data_set[0]));
|
||||
$query->values([
|
||||
'name' => 'James McCartney',
|
||||
'age' => 0,
|
||||
'job' => 'Baby',
|
||||
'created' => gmmktime(6, 30, 10, 1, 1, 2000),
|
||||
'status' => 1,
|
||||
]);
|
||||
$query->execute();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
|
||||
$result = $this->xpath('//tbody/tr/td[contains(., "Baby")]');
|
||||
$this->assertTrue(count($result), 'Ensure that the baby is found.');
|
||||
|
||||
$result = $this->xpath('//tbody/tr/td[text()=0]');
|
||||
$this->assertTrue(count($result), 'Ensure that the baby\'s age is shown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that empty columns are hidden when empty_column is set.
|
||||
*/
|
||||
public function testEmptyColumn() {
|
||||
// Empty the 'job' data.
|
||||
\Drupal::database()->update('views_test_data')
|
||||
->fields(['job' => ''])
|
||||
->execute();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
|
||||
// Test that only one of the job columns still shows.
|
||||
$result = $this->xpath('//thead/tr/th/a[text()="Job"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that empty column header is hidden.');
|
||||
|
||||
$result = $this->xpath('//tbody/tr/td[contains(concat(" ", @class, " "), " views-field-job-1 ")]');
|
||||
$this->assertEqual(count($result), 0, 'Ensure the empty table cells are hidden.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests grouping by a field.
|
||||
*/
|
||||
public function testGrouping() {
|
||||
/** @var \Drupal\views\ViewEntityInterface $view */
|
||||
$view = \Drupal::entityTypeManager()->getStorage('view')->load('test_table');
|
||||
// Get a reference to the display configuration so we can alter some
|
||||
// specific style options.
|
||||
$display = &$view->getDisplay('default');
|
||||
// Set job as the grouping field.
|
||||
$display['display_options']['style']['options']['grouping'][0] = [
|
||||
'field' => 'job',
|
||||
'rendered' => TRUE,
|
||||
'rendered_strip' => FALSE,
|
||||
];
|
||||
// Clear the caption text, the rendered job field will be used as a caption.
|
||||
$display['display_options']['style']['options']['caption'] = '';
|
||||
$display['display_options']['style']['options']['summary'] = '';
|
||||
$display['display_options']['style']['options']['description'] = '';
|
||||
$view->save();
|
||||
|
||||
// Add a record containing unsafe markup to be sure it's filtered out.
|
||||
$unsafe_markup = '<script>alert("Rapper");</script>';
|
||||
$unsafe_markup_data = [
|
||||
'name' => 'Marshall',
|
||||
'age' => 42,
|
||||
'job' => $unsafe_markup,
|
||||
'created' => gmmktime(0, 0, 0, 2, 15, 2001),
|
||||
'status' => 1,
|
||||
];
|
||||
$database = $this->container->get('database');
|
||||
$database->insert('views_test_data')
|
||||
->fields(array_keys($unsafe_markup_data))
|
||||
->values($unsafe_markup_data)
|
||||
->execute();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
$expected_captions = [
|
||||
'Job: Speaker',
|
||||
'Job: Songwriter',
|
||||
'Job: Drummer',
|
||||
'Job: Singer',
|
||||
'Job: ' . $unsafe_markup,
|
||||
];
|
||||
|
||||
// Ensure that we don't find the caption containing unsafe markup.
|
||||
$this->assertNoRaw($unsafe_markup, "Didn't find caption containing unsafe markup.");
|
||||
|
||||
// Ensure that all expected captions are found.
|
||||
foreach ($expected_captions as $raw_caption) {
|
||||
$this->assertEscaped($raw_caption);
|
||||
}
|
||||
|
||||
$display = &$view->getDisplay('default');
|
||||
// Remove the label from the grouping field.
|
||||
$display['display_options']['fields']['job']['label'] = '';
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-table');
|
||||
$expected_captions = [
|
||||
'Speaker',
|
||||
'Songwriter',
|
||||
'Drummer',
|
||||
'Singer',
|
||||
$unsafe_markup,
|
||||
];
|
||||
|
||||
// Ensure that we don't find the caption containing unsafe markup.
|
||||
$this->assertNoRaw($unsafe_markup, "Didn't find caption containing unsafe markup.");
|
||||
|
||||
// Ensure that all expected captions are found.
|
||||
foreach ($expected_captions as $raw_caption) {
|
||||
$this->assertEscaped($raw_caption);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
299
web/core/modules/views/tests/src/Functional/Plugin/StyleTest.php
Normal file
299
web/core/modules/views/tests/src/Functional/Plugin/StyleTest.php
Normal file
|
@ -0,0 +1,299 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views_test_data\Plugin\views\row\RowTest;
|
||||
use Drupal\views\Plugin\views\row\Fields;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views_test_data\Plugin\views\style\StyleTest as StyleTestPlugin;
|
||||
|
||||
/**
|
||||
* Tests general style functionality.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views_test_data\Plugin\views\style\StyleTest.
|
||||
*/
|
||||
class StyleTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Stores the SimpleXML representation of the output.
|
||||
*
|
||||
* @var \SimpleXMLElement
|
||||
*/
|
||||
protected $elements;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the general rendering of styles.
|
||||
*/
|
||||
public function testStyle() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// This run use the test row plugin and render with it.
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
$style = $view->display_handler->getOption('style');
|
||||
$style['type'] = 'test_style';
|
||||
$view->display_handler->setOption('style', $style);
|
||||
$row = $view->display_handler->getOption('row');
|
||||
$row['type'] = 'test_row';
|
||||
$view->display_handler->setOption('row', $row);
|
||||
$view->initDisplay();
|
||||
$view->initStyle();
|
||||
// Reinitialize the style as it supports row plugins now.
|
||||
$view->style_plugin->init($view, $view->display_handler);
|
||||
$this->assertTrue($view->rowPlugin instanceof RowTest, 'Make sure the right row plugin class is loaded.');
|
||||
|
||||
$random_text = $this->randomMachineName();
|
||||
$view->rowPlugin->setOutput($random_text);
|
||||
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertTrue(strpos($output, $random_text) !== FALSE, 'Make sure that the rendering of the row plugin appears in the output of the view.');
|
||||
|
||||
// Test without row plugin support.
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
$style = $view->display_handler->getOption('style');
|
||||
$style['type'] = 'test_style';
|
||||
$view->display_handler->setOption('style', $style);
|
||||
$view->initDisplay();
|
||||
$view->initStyle();
|
||||
$view->style_plugin->setUsesRowPlugin(FALSE);
|
||||
$this->assertTrue($view->style_plugin instanceof StyleTestPlugin, 'Make sure the right style plugin class is loaded.');
|
||||
$this->assertTrue($view->rowPlugin instanceof Fields, 'Make sure that rowPlugin is now a fields instance.');
|
||||
|
||||
$random_text = $this->randomMachineName();
|
||||
// Set some custom text to the output and make sure that this value is
|
||||
// rendered.
|
||||
$view->style_plugin->setOutput($random_text);
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->assertTrue(strpos($output, $random_text) !== FALSE, 'Make sure that the rendering of the style plugin appears in the output of the view.');
|
||||
}
|
||||
|
||||
public function testGrouping() {
|
||||
$this->_testGrouping(FALSE);
|
||||
$this->_testGrouping(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the grouping features of styles.
|
||||
*/
|
||||
public function _testGrouping($stripped = FALSE) {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
// Setup grouping by the job and the age field.
|
||||
$view->initStyle();
|
||||
$view->style_plugin->options['grouping'] = [
|
||||
['field' => 'job'],
|
||||
['field' => 'age'],
|
||||
];
|
||||
|
||||
// Reduce the amount of items to make the test a bit easier.
|
||||
// Set up the pager.
|
||||
$view->displayHandlers->get('default')->overrideOption('pager', [
|
||||
'type' => 'some',
|
||||
'options' => ['items_per_page' => 3],
|
||||
]);
|
||||
|
||||
// Add the job and age field.
|
||||
$fields = [
|
||||
'name' => [
|
||||
'id' => 'name',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'relationship' => 'none',
|
||||
'label' => 'Name',
|
||||
],
|
||||
'job' => [
|
||||
'id' => 'job',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'job',
|
||||
'relationship' => 'none',
|
||||
'label' => 'Job',
|
||||
],
|
||||
'age' => [
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
'label' => 'Age',
|
||||
],
|
||||
];
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', $fields);
|
||||
|
||||
// Now run the query and groupby the result.
|
||||
$this->executeView($view);
|
||||
|
||||
$expected = [];
|
||||
$expected['Job: Singer'] = [];
|
||||
$expected['Job: Singer']['group'] = 'Job: Singer';
|
||||
$expected['Job: Singer']['level'] = 0;
|
||||
$expected['Job: Singer']['rows']['Age: 25'] = [];
|
||||
$expected['Job: Singer']['rows']['Age: 25']['group'] = 'Age: 25';
|
||||
$expected['Job: Singer']['rows']['Age: 25']['level'] = 1;
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0] = new ResultRow(['index' => 0]);
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_name = 'John';
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_job = 'Singer';
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_age = '25';
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_id = '1';
|
||||
$expected['Job: Singer']['rows']['Age: 27'] = [];
|
||||
$expected['Job: Singer']['rows']['Age: 27']['group'] = 'Age: 27';
|
||||
$expected['Job: Singer']['rows']['Age: 27']['level'] = 1;
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1] = new ResultRow(['index' => 1]);
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_name = 'George';
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_job = 'Singer';
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_age = '27';
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_id = '2';
|
||||
$expected['Job: Drummer'] = [];
|
||||
$expected['Job: Drummer']['group'] = 'Job: Drummer';
|
||||
$expected['Job: Drummer']['level'] = 0;
|
||||
$expected['Job: Drummer']['rows']['Age: 28'] = [];
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['group'] = 'Age: 28';
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['level'] = 1;
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2] = new ResultRow(['index' => 2]);
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_name = 'Ringo';
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_job = 'Drummer';
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_age = '28';
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_id = '3';
|
||||
|
||||
|
||||
// Alter the results to support the stripped case.
|
||||
if ($stripped) {
|
||||
|
||||
// Add some html to the result and expected value.
|
||||
$rand1 = '<a data="' . $this->randomMachineName() . '" />';
|
||||
$view->result[0]->views_test_data_job .= $rand1;
|
||||
$expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_job = 'Singer' . $rand1;
|
||||
$expected['Job: Singer']['group'] = 'Job: Singer';
|
||||
$rand2 = '<a data="' . $this->randomMachineName() . '" />';
|
||||
$view->result[1]->views_test_data_job .= $rand2;
|
||||
$expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_job = 'Singer' . $rand2;
|
||||
$rand3 = '<a data="' . $this->randomMachineName() . '" />';
|
||||
$view->result[2]->views_test_data_job .= $rand3;
|
||||
$expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_job = 'Drummer' . $rand3;
|
||||
$expected['Job: Drummer']['group'] = 'Job: Drummer';
|
||||
|
||||
$view->style_plugin->options['grouping'][0] = ['field' => 'job', 'rendered' => TRUE, 'rendered_strip' => TRUE];
|
||||
$view->style_plugin->options['grouping'][1] = ['field' => 'age', 'rendered' => TRUE, 'rendered_strip' => TRUE];
|
||||
}
|
||||
|
||||
|
||||
// The newer api passes the value of the grouping as well.
|
||||
$sets_new_rendered = $view->style_plugin->renderGrouping($view->result, $view->style_plugin->options['grouping'], TRUE);
|
||||
|
||||
$this->assertEqual($sets_new_rendered, $expected, 'The style plugins should properly group the results with grouping by the rendered output.');
|
||||
|
||||
// Don't test stripped case, because the actual value is not stripped.
|
||||
if (!$stripped) {
|
||||
$sets_new_value = $view->style_plugin->renderGrouping($view->result, $view->style_plugin->options['grouping'], FALSE);
|
||||
|
||||
// Reorder the group structure to grouping by value.
|
||||
$new_expected = $expected;
|
||||
$new_expected['Singer'] = $expected['Job: Singer'];
|
||||
$new_expected['Singer']['rows']['25'] = $expected['Job: Singer']['rows']['Age: 25'];
|
||||
$new_expected['Singer']['rows']['27'] = $expected['Job: Singer']['rows']['Age: 27'];
|
||||
$new_expected['Drummer'] = $expected['Job: Drummer'];
|
||||
$new_expected['Drummer']['rows']['28'] = $expected['Job: Drummer']['rows']['Age: 28'];
|
||||
unset($new_expected['Job: Singer']);
|
||||
unset($new_expected['Singer']['rows']['Age: 25']);
|
||||
unset($new_expected['Singer']['rows']['Age: 27']);
|
||||
unset($new_expected['Job: Drummer']);
|
||||
unset($new_expected['Drummer']['rows']['Age: 28']);
|
||||
|
||||
$this->assertEqual($sets_new_value, $new_expected, 'The style plugins should proper group the results with grouping by the value.');
|
||||
}
|
||||
|
||||
// Test that grouping works on fields having no label.
|
||||
$fields['job']['label'] = '';
|
||||
$view->destroy();
|
||||
$view->setDisplay();
|
||||
$view->initStyle();
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', $fields);
|
||||
$view->style_plugin->options['grouping'] = [
|
||||
['field' => 'job'],
|
||||
['field' => 'age'],
|
||||
];
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
if ($stripped) {
|
||||
$view->result[0]->views_test_data_job .= $rand1;
|
||||
$view->result[1]->views_test_data_job .= $rand2;
|
||||
$view->result[2]->views_test_data_job .= $rand3;
|
||||
$view->style_plugin->options['grouping'][0] = ['field' => 'job', 'rendered' => TRUE, 'rendered_strip' => TRUE];
|
||||
$view->style_plugin->options['grouping'][1] = ['field' => 'age', 'rendered' => TRUE, 'rendered_strip' => TRUE];
|
||||
}
|
||||
|
||||
$sets_new_rendered = $view->style_plugin->renderGrouping($view->result, $view->style_plugin->options['grouping'], TRUE);
|
||||
|
||||
// Remove labels from expected results.
|
||||
foreach ($expected as $job => $data) {
|
||||
unset($expected[$job]);
|
||||
$job = str_replace('Job: ', '', $job);
|
||||
$data['group'] = $job;
|
||||
$expected[$job] = $data;
|
||||
}
|
||||
$this->assertEqual($expected, $sets_new_rendered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests custom css classes.
|
||||
*/
|
||||
public function testCustomRowClasses() {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
// Setup some random css class.
|
||||
$view->initStyle();
|
||||
$random_name = $this->randomMachineName();
|
||||
$view->style_plugin->options['row_class'] = $random_name . " test-token-{{ name }}";
|
||||
|
||||
$output = $view->preview();
|
||||
$this->storeViewPreview(\Drupal::service('renderer')->renderRoot($output));
|
||||
|
||||
$rows = $this->elements->body->div->div->div;
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
$attributes = $row->attributes();
|
||||
$class = (string) $attributes['class'][0];
|
||||
$this->assertTrue(strpos($class, $random_name) !== FALSE, 'Make sure that a custom css class is added to the output.');
|
||||
|
||||
// Check token replacement.
|
||||
$name = $view->field['name']->getValue($view->result[$count]);
|
||||
$this->assertTrue(strpos($class, "test-token-$name") !== FALSE, 'Make sure that a token in custom css class is replaced.');
|
||||
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a view output in the elements.
|
||||
*/
|
||||
protected function storeViewPreview($output) {
|
||||
$htmlDom = new \DOMDocument();
|
||||
@$htmlDom->loadHTML($output);
|
||||
if ($htmlDom) {
|
||||
// It's much easier to work with simplexml than DOM, luckily enough
|
||||
// we can just simply import our DOM tree.
|
||||
$this->elements = simplexml_import_dom($htmlDom);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests views bulk operation selection.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsBulkTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* An admin user
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $admin_user;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views'];
|
||||
|
||||
public function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->admin_user = $this->createUser(['bypass node access', 'administer nodes', 'access content overview']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests bulk selection.
|
||||
*/
|
||||
public function testBulkSelection() {
|
||||
|
||||
// Create first node, set updated time to the past.
|
||||
$node_1 = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'title' => 'The first node',
|
||||
'changed' => \Drupal::time()->getRequestTime() - 180
|
||||
]);
|
||||
|
||||
// Login as administrator and go to admin/content.
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->drupalGet('admin/content');
|
||||
$this->assertText($node_1->getTitle());
|
||||
|
||||
// Create second node now that the admin overview has been rendered.
|
||||
$node_2 = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'title' => 'The second node',
|
||||
'changed' => \Drupal::time()->getRequestTime() - 120
|
||||
]);
|
||||
|
||||
// Now click 'Apply to selected items' and assert the first node is selected
|
||||
// on the confirm form.
|
||||
$this->drupalPostForm(NULL, ['node_bulk_form[0]' => TRUE], 'Apply to selected items');
|
||||
$this->assertText($node_1->getTitle());
|
||||
$this->assertNoText($node_2->getTitle());
|
||||
|
||||
// Change the pager limit to 2.
|
||||
$this->config('views.view.content')->set('display.default.display_options.pager.options.items_per_page', 2)->save();
|
||||
|
||||
// Render the overview page again.
|
||||
$this->drupalGet('admin/content');
|
||||
|
||||
// Create third node now that the admin overview has been rendered.
|
||||
$node_3 = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'title' => 'The third node']
|
||||
);
|
||||
|
||||
// Now click 'Apply to selected items' and assert the second node is
|
||||
// selected on the confirm form.
|
||||
$this->drupalPostForm(NULL, ['node_bulk_form[1]' => TRUE], 'Apply to selected items');
|
||||
$this->assertText($node_1->getTitle());
|
||||
$this->assertNoText($node_3->getTitle());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests Views forms functionality.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsFormTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['action_bulk_test'];
|
||||
|
||||
/**
|
||||
* Tests the Views form wrapper.
|
||||
*/
|
||||
public function testFormWrapper() {
|
||||
$this->drupalGet('test_bulk_form');
|
||||
// Ensure we have the form tag on the page.
|
||||
$xpath = $this->cssSelect('.views-form form');
|
||||
$this->assertIdentical(count($xpath), 1, 'There is one views form on the page.');
|
||||
// Ensure we don't have nested form elements.
|
||||
$result = (bool) preg_match('#<form[^>]*?>(?!/form).*<form#s', $this->getRawContent());
|
||||
$this->assertFalse($result, 'The views form element is not nested.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Core\Database\DatabaseExceptionWrapper;
|
||||
|
||||
/**
|
||||
* Tests the views exception handling.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsSqlExceptionTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_filter'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views_test_data']['name']['filter']['id'] = 'test_exception_filter';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the SQL exception.
|
||||
*/
|
||||
public function testSqlException() {
|
||||
$view = Views::getView('test_filter');
|
||||
$view->initDisplay();
|
||||
|
||||
// Adding a filter that will result in an invalid query.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'test_filter' => [
|
||||
'id' => 'test_exception_filter',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'operator' => '=',
|
||||
'value' => 'John',
|
||||
'group' => 0,
|
||||
],
|
||||
]);
|
||||
|
||||
try {
|
||||
$this->executeView($view);
|
||||
$this->fail('Expected exception not thrown.');
|
||||
}
|
||||
catch (DatabaseExceptionWrapper $e) {
|
||||
$exception_assert_message = "Exception in {$view->storage->label()}[{$view->storage->id()}]";
|
||||
$this->assertEqual(strstr($e->getMessage(), ':', TRUE), $exception_assert_message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Tests render caching of blocks provided by views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class RenderCacheWebTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['node_id_argument'];
|
||||
|
||||
/**
|
||||
* The created nodes.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface[]
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$node_type = $this->drupalCreateContentType(['type' => 'test_type']);
|
||||
$node = Node::create([
|
||||
'title' => 'test title 1',
|
||||
'type' => $node_type->id(),
|
||||
]);
|
||||
$node->save();
|
||||
$this->nodes[] = $node;
|
||||
|
||||
$node = Node::create([
|
||||
'title' => 'test title 2',
|
||||
'type' => $node_type->id(),
|
||||
]);
|
||||
$node->save();
|
||||
$this->nodes[] = $node;
|
||||
|
||||
$this->placeBlock('views_block:node_id_argument-block_1', ['region' => 'header']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering caching of a views block with arguments.
|
||||
*/
|
||||
public function testEmptyView() {
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual([], $this->cssSelect('div.region-header div.views-field-title'));
|
||||
|
||||
$this->drupalGet($this->nodes[0]->toUrl());
|
||||
$result = $this->cssSelect('div.region-header div.views-field-title')[0]->getText();
|
||||
$this->assertEqual('test title 1', $result);
|
||||
|
||||
$this->drupalGet($this->nodes[1]->toUrl());
|
||||
$result = $this->cssSelect('div.region-header div.views-field-title')[0]->getText();
|
||||
$this->assertEqual('test title 2', $result);
|
||||
|
||||
$this->drupalGet($this->nodes[0]->toUrl());
|
||||
$result = $this->cssSelect('div.region-header div.views-field-title')[0]->getText();
|
||||
$this->assertEqual('test title 1', $result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Tests\Traits\Core\CronRunTrait;
|
||||
|
||||
/**
|
||||
* Tests search integration filters.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class SearchIntegrationTest extends ViewTestBase {
|
||||
|
||||
use CronRunTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'search'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_search'];
|
||||
|
||||
/**
|
||||
* Tests search integration.
|
||||
*/
|
||||
public function testSearchIntegration() {
|
||||
// Create a content type.
|
||||
$type = $this->drupalCreateContentType();
|
||||
|
||||
// Add three nodes, one containing the word "pizza", one containing
|
||||
// "sandwich", and one containing "cola is good with pizza". Make the
|
||||
// second node link to the first.
|
||||
$node['title'] = 'pizza';
|
||||
$node['body'] = [['value' => 'pizza']];
|
||||
$node['type'] = $type->id();
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
$this->drupalGet('node/1');
|
||||
$node_url = $this->getUrl();
|
||||
|
||||
$node['title'] = 'sandwich';
|
||||
$node['body'] = [['value' => 'sandwich with a <a href="' . $node_url . '">link to first node</a>']];
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
$node['title'] = 'cola';
|
||||
$node['body'] = [['value' => 'cola is good with pizza']];
|
||||
$node['type'] = $type->id();
|
||||
$this->drupalCreateNode($node);
|
||||
|
||||
// Run cron so that the search index tables are updated.
|
||||
$this->cronRun();
|
||||
|
||||
// Test the various views filters by visiting their pages.
|
||||
// These are in the test view 'test_search', and they just display the
|
||||
// titles of the nodes in the result, as links.
|
||||
|
||||
// Page with a keyword filter of 'pizza'.
|
||||
$this->drupalGet('test-filter');
|
||||
$this->assertLink('pizza');
|
||||
$this->assertNoLink('sandwich');
|
||||
$this->assertLink('cola');
|
||||
|
||||
// Page with a keyword argument, various argument values.
|
||||
// Verify that the correct nodes are shown, and only once.
|
||||
$this->drupalGet('test-arg/pizza');
|
||||
$this->assertOneLink('pizza');
|
||||
$this->assertNoLink('sandwich');
|
||||
$this->assertOneLink('cola');
|
||||
|
||||
$this->drupalGet('test-arg/sandwich');
|
||||
$this->assertNoLink('pizza');
|
||||
$this->assertOneLink('sandwich');
|
||||
$this->assertNoLink('cola');
|
||||
|
||||
$this->drupalGet('test-arg/pizza OR sandwich');
|
||||
$this->assertOneLink('pizza');
|
||||
$this->assertOneLink('sandwich');
|
||||
$this->assertOneLink('cola');
|
||||
|
||||
$this->drupalGet('test-arg/pizza sandwich OR cola');
|
||||
$this->assertNoLink('pizza');
|
||||
$this->assertNoLink('sandwich');
|
||||
$this->assertOneLink('cola');
|
||||
|
||||
$this->drupalGet('test-arg/cola pizza');
|
||||
$this->assertNoLink('pizza');
|
||||
$this->assertNoLink('sandwich');
|
||||
$this->assertOneLink('cola');
|
||||
|
||||
$this->drupalGet('test-arg/"cola is good"');
|
||||
$this->assertNoLink('pizza');
|
||||
$this->assertNoLink('sandwich');
|
||||
$this->assertOneLink('cola');
|
||||
|
||||
// Test sorting.
|
||||
$node = [
|
||||
'title' => "Drupal's search rocks.",
|
||||
'type' => $type->id(),
|
||||
];
|
||||
$this->drupalCreateNode($node);
|
||||
$node['title'] = "Drupal's search rocks <em>really</em> rocks!";
|
||||
$this->drupalCreateNode($node);
|
||||
$this->cronRun();
|
||||
$this->drupalGet('test-arg/rocks');
|
||||
$xpath = '//div[@class="views-row"]//a';
|
||||
/** @var \Behat\Mink\Element\NodeElement[] $results */
|
||||
$results = $this->xpath($xpath);
|
||||
$this->assertEqual($results[0]->getText(), "Drupal's search rocks <em>really</em> rocks!");
|
||||
$this->assertEqual($results[1]->getText(), "Drupal's search rocks.");
|
||||
$this->assertEscaped("Drupal's search rocks <em>really</em> rocks!");
|
||||
|
||||
// Test sorting with another set of titles.
|
||||
$node = [
|
||||
'title' => "Testing one two two two",
|
||||
'type' => $type->id(),
|
||||
];
|
||||
$this->drupalCreateNode($node);
|
||||
$node['title'] = "Testing one one one";
|
||||
$this->drupalCreateNode($node);
|
||||
$this->cronRun();
|
||||
$this->drupalGet('test-arg/one');
|
||||
$xpath = '//div[@class="views-row"]//a';
|
||||
/** @var \SimpleXMLElement[] $results */
|
||||
$results = $this->xpath($xpath);
|
||||
$this->assertEqual($results[0]->getText(), "Testing one one one");
|
||||
$this->assertEqual($results[1]->getText(), "Testing one two two two");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that exactly one link exists with the given text.
|
||||
*
|
||||
* @param string $label
|
||||
* Link label to assert.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertOneLink($label) {
|
||||
$links = $this->xpath('//a[normalize-space(text())=:label]', [':label' => $label]);
|
||||
$message = SafeMarkup::format('Link with label %label found once.', ['%label' => $label]);
|
||||
return $this->assert(isset($links[0]) && !isset($links[1]), $message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\Tests\Traits\Core\CronRunTrait;
|
||||
|
||||
/**
|
||||
* Tests search integration filters with multilingual nodes.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class SearchMultilingualTest extends ViewTestBase {
|
||||
|
||||
use CronRunTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'search', 'language', 'content_translation'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_search'];
|
||||
|
||||
/**
|
||||
* Tests search with multilingual nodes.
|
||||
*/
|
||||
public function testMultilingualSearchFilter() {
|
||||
// Create a user with admin for languages, content, and content types, plus
|
||||
// the ability to access content and searches.
|
||||
$user = $this->drupalCreateUser(['administer nodes', 'administer content types', 'administer languages', 'administer content translation', 'access content', 'search content']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Add Spanish language programmatically.
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
|
||||
// Create a content type and make it translatable.
|
||||
$type = $this->drupalCreateContentType();
|
||||
$edit = [
|
||||
'language_configuration[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $type->id(), $edit, t('Save content type'));
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][' . $type->id() . '][translatable]' => TRUE,
|
||||
'settings[node][' . $type->id() . '][fields][title]' => TRUE,
|
||||
'settings[node][' . $type->id() . '][fields][body]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
\Drupal::entityManager()->clearCachedDefinitions();
|
||||
|
||||
// Add a node in English, with title "sandwich".
|
||||
$values = [
|
||||
'title' => 'sandwich',
|
||||
'type' => $type->id(),
|
||||
];
|
||||
$node = $this->drupalCreateNode($values);
|
||||
|
||||
// "Translate" this node into Spanish, with title "pizza".
|
||||
$node->addTranslation('es', ['title' => 'pizza', 'status' => NodeInterface::PUBLISHED]);
|
||||
$node->save();
|
||||
|
||||
// Run cron so that the search index tables are updated.
|
||||
$this->cronRun();
|
||||
|
||||
// Test the keyword filter by visiting the page.
|
||||
// The views are in the test view 'test_search', and they just display the
|
||||
// titles of the nodes in the result, as links.
|
||||
|
||||
// Page with a keyword filter of 'pizza'. This should find the Spanish
|
||||
// translated node, which has 'pizza' in the title, but not the English
|
||||
// one, which does not have the word 'pizza' in it.
|
||||
$this->drupalGet('test-filter');
|
||||
$this->assertLink('pizza', 0, 'Found translation with matching title');
|
||||
$this->assertNoLink('sandwich', 'Did not find translation with non-matching title');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\taxonomy\Tests\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Tests glossary functionality of taxonomy views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class TaxonomyGlossaryTest extends ViewTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_taxonomy_glossary'];
|
||||
|
||||
/**
|
||||
* Taxonomy terms used by this test.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Term[]
|
||||
*/
|
||||
protected $taxonomyTerms;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
/** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary */
|
||||
$vocabulary = $this->createVocabulary();
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$this->taxonomyTerms[] = $this->createTerm($vocabulary);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a taxonomy glossary view.
|
||||
*/
|
||||
public function testTaxonomyGlossaryView() {
|
||||
// Go the taxonomy glossary page for the first term.
|
||||
$this->drupalGet('test_taxonomy_glossary/' . substr($this->taxonomyTerms[0]->getName(), 0, 1));
|
||||
$this->assertText($this->taxonomyTerms[0]->getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests general rendering of a view.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewRenderTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view_render'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests render functionality.
|
||||
*/
|
||||
public function testRender() {
|
||||
\Drupal::state()->set('views_render.test', 0);
|
||||
|
||||
// Make sure that the rendering just calls the preprocess function once.
|
||||
$view = Views::getView('test_view_render');
|
||||
$output = $view->preview();
|
||||
$this->container->get('renderer')->renderRoot($output);
|
||||
|
||||
$this->assertEqual(\Drupal::state()->get('views_render.test'), 1);
|
||||
}
|
||||
|
||||
}
|
158
web/core/modules/views/tests/src/Functional/ViewTestBase.php
Normal file
158
web/core/modules/views/tests/src/Functional/ViewTestBase.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\views\Tests\ViewResultAssertionTrait;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Defines a base class for Views testing in the full web test environment.
|
||||
*
|
||||
* Use this base test class if you need to emulate a full Drupal installation.
|
||||
* When possible, ViewsKernelTestBase should be used instead. Both base classes
|
||||
* include the same methods.
|
||||
*
|
||||
* @see \Drupal\Tests\views\Kernel\ViewsKernelTestBase
|
||||
* @see \Drupal\simpletest\WebTestBase
|
||||
*/
|
||||
abstract class ViewTestBase extends BrowserTestBase {
|
||||
|
||||
use ViewResultAssertionTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views', 'views_test_config'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
if ($import_test_views) {
|
||||
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the views_test_data.module.
|
||||
*
|
||||
* Because the schema of views_test_data.module is dependent on the test
|
||||
* using it, it cannot be enabled normally.
|
||||
*/
|
||||
protected function enableViewsTestModule() {
|
||||
// Define the schema and views data variable before enabling the test module.
|
||||
\Drupal::state()->set('views_test_data_schema', $this->schemaDefinition());
|
||||
\Drupal::state()->set('views_test_data_views_data', $this->viewsData());
|
||||
|
||||
\Drupal::service('module_installer')->install(['views_test_data']);
|
||||
$this->resetAll();
|
||||
$this->rebuildContainer();
|
||||
$this->container->get('module_handler')->reload();
|
||||
|
||||
// Load the test dataset.
|
||||
$data_set = $this->dataSet();
|
||||
$query = db_insert('views_test_data')
|
||||
->fields(array_keys($data_set[0]));
|
||||
foreach ($data_set as $record) {
|
||||
$query->values($record);
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders a nested array containing a result set based on a given column.
|
||||
*
|
||||
* @param array $result_set
|
||||
* An array of rows from a result set, with each row as an associative
|
||||
* array keyed by column name.
|
||||
* @param string $column
|
||||
* The column name by which to sort the result set.
|
||||
* @param bool $reverse
|
||||
* (optional) Boolean indicating whether to sort the result set in reverse
|
||||
* order. Defaults to FALSE.
|
||||
*
|
||||
* @return array
|
||||
* The sorted result set.
|
||||
*/
|
||||
protected function orderResultSet($result_set, $column, $reverse = FALSE) {
|
||||
$order = $reverse ? -1 : 1;
|
||||
usort($result_set, function ($a, $b) use ($column, $order) {
|
||||
if ($a[$column] == $b[$column]) {
|
||||
return 0;
|
||||
}
|
||||
return $order * (($a[$column] < $b[$column]) ? -1 : 1);
|
||||
});
|
||||
return $result_set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the existence of a button with a certain ID and label.
|
||||
*
|
||||
* @param string $id
|
||||
* The HTML ID of the button
|
||||
* @param string $expected_label
|
||||
* The expected label for the button.
|
||||
* @param string $message
|
||||
* (optional) A custom message to display with the assertion. If no custom
|
||||
* message is provided, the message will indicate the button label.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
*/
|
||||
protected function helperButtonHasLabel($id, $expected_label, $message = 'Label has the expected value: %label.') {
|
||||
$xpath = $this->assertSession()->buildXPathQuery('//button[@id=:value]|//input[@id=:value]', [':value' => $id]);
|
||||
$field = $this->getSession()->getPage()->find('xpath', $xpath);
|
||||
|
||||
if (empty($field)) {
|
||||
throw new ElementNotFoundException($this->getSession()->getDriver(), 'form field', 'id', $field);
|
||||
}
|
||||
|
||||
$this->assertEquals($expected_label, $field->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a view with debugging.
|
||||
*
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* The view object.
|
||||
* @param array $args
|
||||
* (optional) An array of the view arguments to use for the view.
|
||||
*/
|
||||
protected function executeView(ViewExecutable $view, $args = []) {
|
||||
// A view does not really work outside of a request scope, due to many
|
||||
// dependencies like the current user.
|
||||
$view->setDisplay();
|
||||
$view->preExecute($args);
|
||||
$view->execute();
|
||||
$verbose_message = '<pre>Executed view: ' . ((string) $view->build_info['query']) . '</pre>';
|
||||
if ($view->build_info['query'] instanceof SelectInterface) {
|
||||
$verbose_message .= '<pre>Arguments: ' . print_r($view->build_info['query']->getArguments(), TRUE) . '</pre>';
|
||||
}
|
||||
$this->verbose($verbose_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the schema definition.
|
||||
*/
|
||||
protected function schemaDefinition() {
|
||||
return ViewTestData::schemaDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the views data definition.
|
||||
*/
|
||||
protected function viewsData() {
|
||||
return ViewTestData::viewsData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a very simple test dataset.
|
||||
*/
|
||||
protected function dataSet() {
|
||||
return ViewTestData::dataSet();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
/**
|
||||
* Tests output of Views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsEscapingTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_page_display', 'test_field_header'];
|
||||
|
||||
/**
|
||||
* Used by WebTestBase::setup()
|
||||
*
|
||||
* We need theme_test for testing against test_basetheme and test_subtheme.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see \Drupal\simpletest\WebTestBase::setup()
|
||||
*/
|
||||
public static $modules = ['views', 'theme_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(TRUE);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for incorrectly escaped markup in the views-view-fields.html.twig.
|
||||
*/
|
||||
public function testViewsViewFieldsEscaping() {
|
||||
// Test with system theme using theme function.
|
||||
$this->drupalGet('test_page_display_200');
|
||||
|
||||
// Assert that there are no escaped '<'s characters.
|
||||
$this->assertNoEscaped('<');
|
||||
|
||||
// Install theme to test with template system.
|
||||
\Drupal::service('theme_handler')->install(['views_test_theme']);
|
||||
|
||||
// Make base theme default then test for hook invocations.
|
||||
$this->config('system.theme')
|
||||
->set('default', 'views_test_theme')
|
||||
->save();
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme');
|
||||
|
||||
$this->drupalGet('test_page_display_200');
|
||||
|
||||
// Assert that we are using the correct template.
|
||||
$this->assertText('force', 'The force is strong with this one');
|
||||
|
||||
// Assert that there are no escaped '<'s characters.
|
||||
$this->assertNoEscaped('<');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for incorrectly escaped markup in a header label on a display table.
|
||||
*/
|
||||
public function testViewsFieldHeaderEscaping() {
|
||||
// Test with a field header label having an html element wrapper.
|
||||
$this->drupalGet('test_field_header');
|
||||
|
||||
// Assert that there are no escaped '<'s characters.
|
||||
$this->assertNoEscaped('<');
|
||||
|
||||
// Test with a field header label having a XSS test as a wrapper.
|
||||
$this->drupalGet('test_field_header_xss');
|
||||
|
||||
// Assert that XSS test is escaped.
|
||||
$this->assertNoRaw('<script>alert("XSS")</script>', 'Harmful tags are escaped in header label.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
/**
|
||||
* Tests a page with multiple Views forms.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsFormMultipleTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_form_multiple'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views_test_data']['field_form_button_test']['field'] = [
|
||||
'title' => t('Button test'),
|
||||
'help' => t('Adds a test form button.'),
|
||||
'id' => 'field_form_button_test',
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the a page with multiple View forms in it.
|
||||
*/
|
||||
public function testViewsFormMultiple() {
|
||||
// Get the test page.
|
||||
$this->drupalGet('views_test_form_multiple');
|
||||
|
||||
$this->assertText('Test base form ID with Views forms and arguments.');
|
||||
|
||||
// Submit the forms, validate argument returned in message set by handler.
|
||||
// @note There is not a way to specify a specific index for a submit button. So
|
||||
// the row index returned is always the last occurrence.
|
||||
$this->getSession()->getPage()->pressButton('edit-field-form-button-test-4--2');
|
||||
$this->assertText('The test button at row 4 for test_form_multiple (default) View with args: arg2 was submitted.');
|
||||
$this->getSession()->getPage()->pressButton('edit-field-form-button-test-4');
|
||||
$this->assertText('The test button at row 4 for test_form_multiple (default) View with args: arg1 was submitted.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the template retrieval of views.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views_test_data\Plugin\views\style\StyleTemplateTest
|
||||
*/
|
||||
class ViewsTemplateTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view_display_template'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(FALSE);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests render functionality.
|
||||
*/
|
||||
public function testTemplate() {
|
||||
|
||||
// Make sure that the rendering just calls the preprocess function once.
|
||||
$view = Views::getView('test_view_display_template');
|
||||
$output = $view->preview();
|
||||
|
||||
// Check if we got the rendered output of our template file.
|
||||
$this->assertTrue(strpos(\Drupal::service('renderer')->renderRoot($output), 'This module defines its own display template.') !== FALSE, 'Display plugin DisplayTemplateTest defines its own template.');
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional;
|
||||
|
||||
/**
|
||||
* Tests the Views theme integration.
|
||||
*
|
||||
* We test against test_basetheme and test_subtheme provided by theme_test
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsThemeIntegrationTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_page_display'];
|
||||
|
||||
|
||||
/**
|
||||
* Used by WebTestBase::setup()
|
||||
*
|
||||
* We need theme_test for testing against test_basetheme and test_subtheme.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see \Drupal\simpletest\WebTestBase::setup()
|
||||
*/
|
||||
public static $modules = ['views', 'theme_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for exceptions and successful execution of hook_views_pre_render()
|
||||
* and hook_views_post_render() in theme and subtheme.
|
||||
*/
|
||||
public function testThemedViewPage() {
|
||||
|
||||
\Drupal::service('theme_handler')->install(['test_basetheme', 'test_subtheme']);
|
||||
|
||||
// Make base theme default then test for hook invocations.
|
||||
$this->config('system.theme')
|
||||
->set('default', 'test_basetheme')
|
||||
->save();
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'test_basetheme');
|
||||
|
||||
// Make sure a views rendered page is touched.
|
||||
$this->drupalGet('test_page_display_200');
|
||||
|
||||
$this->assertRaw("test_basetheme_views_pre_render", "Views title changed by test_basetheme.test_basetheme_views_pre_render");
|
||||
$this->assertRaw("test_basetheme_views_post_render", "Views title changed by test_basetheme.test_basetheme_views_post_render");
|
||||
|
||||
// Make sub theme default to test for hook invocation
|
||||
// from both sub and base theme.
|
||||
$this->config('system.theme')
|
||||
->set('default', 'test_subtheme')
|
||||
->save();
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'test_subtheme');
|
||||
|
||||
// Make sure a views rendered page is touched.
|
||||
$this->drupalGet('test_page_display_200');
|
||||
|
||||
$this->assertRaw("test_subtheme_views_pre_render", "Views title changed by test_subtheme.test_subtheme_views_pre_render");
|
||||
$this->assertRaw("test_subtheme_views_post_render", "Views title changed by test_subtheme.test_subtheme_views_post_render");
|
||||
|
||||
$this->assertRaw("test_basetheme_views_pre_render", "Views title changed by test_basetheme.test_basetheme_views_pre_render");
|
||||
$this->assertRaw("test_basetheme_views_post_render", "Views title changed by test_basetheme.test_basetheme_views_post_render");
|
||||
|
||||
$this->assertRaw('<em class="placeholder">' . count($this->dataSet()) . '</em> items found.', 'Views group title added by test_subtheme.test_subtheme_views_post_render');
|
||||
}
|
||||
|
||||
}
|
203
web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php
Normal file
203
web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests creating views with the wizard and viewing them on the listing page.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class BasicTest extends WizardTestBase {
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
public function testViewsWizardAndListing() {
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
|
||||
// Check if we can access the main views admin page.
|
||||
$this->drupalGet('admin/structure/views');
|
||||
$this->assertText(t('Add view'));
|
||||
|
||||
// Create a simple and not at all useful view.
|
||||
$view1 = [];
|
||||
$view1['label'] = $this->randomMachineName(16);
|
||||
$view1['id'] = strtolower($this->randomMachineName(16));
|
||||
$view1['description'] = $this->randomMachineName(16);
|
||||
$view1['page[create]'] = FALSE;
|
||||
$this->drupalPostForm('admin/structure/views/add', $view1, t('Save and edit'));
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet('admin/structure/views');
|
||||
$this->assertText($view1['label']);
|
||||
$this->assertText($view1['description']);
|
||||
$this->assertLinkByHref(\Drupal::url('entity.view.edit_form', ['view' => $view1['id']]));
|
||||
$this->assertLinkByHref(\Drupal::url('entity.view.delete_form', ['view' => $view1['id']]));
|
||||
$this->assertLinkByHref(\Drupal::url('entity.view.duplicate_form', ['view' => $view1['id']]));
|
||||
|
||||
// The view should not have a REST export display.
|
||||
$this->assertNoText('REST export', 'When no options are enabled in the wizard, the resulting view does not have a REST export display.');
|
||||
|
||||
// This view should not have a block.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertNoText($view1['label']);
|
||||
|
||||
// Create two nodes.
|
||||
$node1 = $this->drupalCreateNode(['type' => 'page']);
|
||||
$node2 = $this->drupalCreateNode(['type' => 'article']);
|
||||
|
||||
// Now create a page with simple node listing and an attached feed.
|
||||
$view2 = [];
|
||||
$view2['label'] = $this->randomMachineName(16);
|
||||
$view2['id'] = strtolower($this->randomMachineName(16));
|
||||
$view2['description'] = $this->randomMachineName(16);
|
||||
$view2['page[create]'] = 1;
|
||||
$view2['page[title]'] = $this->randomMachineName(16);
|
||||
$view2['page[path]'] = $this->randomMachineName(16);
|
||||
$view2['page[feed]'] = 1;
|
||||
$view2['page[feed_properties][path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view2, t('Save and edit'));
|
||||
$this->drupalGet($view2['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Since the view has a page, we expect to be automatically redirected to
|
||||
// it.
|
||||
$this->assertUrl($view2['page[path]']);
|
||||
$this->assertText($view2['page[title]']);
|
||||
$this->assertText($node1->label());
|
||||
$this->assertText($node2->label());
|
||||
|
||||
// Check if we have the feed.
|
||||
$this->assertLinkByHref(Url::fromRoute('view.' . $view2['id'] . '.feed_1')->toString());
|
||||
$elements = $this->cssSelect('link[href="' . Url::fromRoute('view.' . $view2['id'] . '.feed_1', [], ['absolute' => TRUE])->toString() . '"]');
|
||||
$this->assertEqual(count($elements), 1, 'Feed found.');
|
||||
$this->drupalGet($view2['page[feed_properties][path]']);
|
||||
// Because the response is XML we can't use the page which depends on an
|
||||
// HTML tag being present.
|
||||
$this->assertEquals('2.0', $this->getSession()->getDriver()->getAttribute('//rss', 'version'));
|
||||
// The feed should have the same title and nodes as the page.
|
||||
$this->assertText($view2['page[title]']);
|
||||
$this->assertRaw($node1->url('canonical', ['absolute' => TRUE]));
|
||||
$this->assertText($node1->label());
|
||||
$this->assertRaw($node2->url('canonical', ['absolute' => TRUE]));
|
||||
$this->assertText($node2->label());
|
||||
|
||||
// Go back to the views page and check if this view is there.
|
||||
$this->drupalGet('admin/structure/views');
|
||||
$this->assertText($view2['label']);
|
||||
$this->assertText($view2['description']);
|
||||
$this->assertLinkByHref(Url::fromRoute('view.' . $view2['id'] . '.page_1')->toString());
|
||||
|
||||
// The view should not have a REST export display.
|
||||
$this->assertNoText('REST export', 'If only the page option was enabled in the wizard, the resulting view does not have a REST export display.');
|
||||
|
||||
// This view should not have a block.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertNoText('View: ' . $view2['label']);
|
||||
|
||||
// Create a view with a page and a block, and filter the listing.
|
||||
$view3 = [];
|
||||
$view3['label'] = $this->randomMachineName(16);
|
||||
$view3['id'] = strtolower($this->randomMachineName(16));
|
||||
$view3['description'] = $this->randomMachineName(16);
|
||||
$view3['show[wizard_key]'] = 'node';
|
||||
$view3['show[type]'] = 'page';
|
||||
$view3['page[create]'] = 1;
|
||||
$view3['page[title]'] = $this->randomMachineName(16);
|
||||
$view3['page[path]'] = $this->randomMachineName(16);
|
||||
$view3['block[create]'] = 1;
|
||||
$view3['block[title]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view3, t('Save and edit'));
|
||||
$this->drupalGet($view3['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Make sure the view only displays the node we expect.
|
||||
$this->assertUrl($view3['page[path]']);
|
||||
$this->assertText($view3['page[title]']);
|
||||
$this->assertText($node1->label());
|
||||
$this->assertNoText($node2->label());
|
||||
|
||||
// Go back to the views page and check if this view is there.
|
||||
$this->drupalGet('admin/structure/views');
|
||||
$this->assertText($view3['label']);
|
||||
$this->assertText($view3['description']);
|
||||
$this->assertLinkByHref(Url::fromRoute('view.' . $view3['id'] . '.page_1')->toString());
|
||||
|
||||
// The view should not have a REST export display.
|
||||
$this->assertNoText('REST export', 'If only the page and block options were enabled in the wizard, the resulting view does not have a REST export display.');
|
||||
|
||||
// Confirm that the block is available in the block administration UI.
|
||||
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
|
||||
$this->clickLink('Place block');
|
||||
$this->assertText($view3['label']);
|
||||
|
||||
// Place the block.
|
||||
$this->drupalPlaceBlock("views_block:{$view3['id']}-block_1");
|
||||
|
||||
// Visit a random page (not the one that displays the view itself) and look
|
||||
// for the expected node title in the block.
|
||||
$this->drupalGet('user');
|
||||
$this->assertText($node1->label());
|
||||
$this->assertNoText($node2->label());
|
||||
|
||||
// Make sure the listing page doesn't show disabled default views.
|
||||
$this->assertNoText('tracker', 'Default tracker view does not show on the listing page.');
|
||||
|
||||
// Create a view with only a REST export.
|
||||
$view4 = [];
|
||||
$view4['label'] = $this->randomMachineName(16);
|
||||
$view4['id'] = strtolower($this->randomMachineName(16));
|
||||
$view4['description'] = $this->randomMachineName(16);
|
||||
$view4['show[wizard_key]'] = 'node';
|
||||
$view4['show[type]'] = 'page';
|
||||
$view4['rest_export[create]'] = 1;
|
||||
$view4['rest_export[path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view4, t('Save and edit'));
|
||||
$this->assertRaw(t('The view %view has been saved.', ['%view' => $view4['label']]));
|
||||
|
||||
// Check that the REST export path works.
|
||||
$this->drupalGet($view4['rest_export[path]']);
|
||||
$this->assertResponse(200);
|
||||
$data = Json::decode($this->getSession()->getPage()->getContent());
|
||||
$this->assertEqual(count($data), 1, 'Only the node of type page is exported.');
|
||||
$node = reset($data);
|
||||
$this->assertEqual($node['nid'][0]['value'], $node1->id(), 'The node of type page is exported.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests default plugin values are populated from the wizard form.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\display\DisplayPluginBase::mergeDefaults()
|
||||
*/
|
||||
public function testWizardDefaultValues() {
|
||||
$random_id = strtolower($this->randomMachineName(16));
|
||||
// Create a basic view.
|
||||
$view = [];
|
||||
$view['label'] = $this->randomMachineName(16);
|
||||
$view['id'] = $random_id;
|
||||
$view['description'] = $this->randomMachineName(16);
|
||||
$view['page[create]'] = FALSE;
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
|
||||
|
||||
// Make sure the plugin types that should not have empty options don't have.
|
||||
// Test against all values is unit tested.
|
||||
// @see \Drupal\Tests\views\Kernel\Plugin\DisplayKernelTest
|
||||
$view = Views::getView($random_id);
|
||||
$displays = $view->storage->get('display');
|
||||
|
||||
foreach ($displays as $display) {
|
||||
foreach (['query', 'exposed_form', 'pager', 'style', 'row'] as $type) {
|
||||
$this->assertFalse(empty($display['display_options'][$type]['options']), SafeMarkup::format('Default options found for @plugin.', ['@plugin' => $type]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
/**
|
||||
* Tests the ability of the views wizard to specify the number of items per
|
||||
* page.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ItemsPerPageTest extends WizardTestBase {
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the number of items per page.
|
||||
*/
|
||||
public function testItemsPerPage() {
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
|
||||
// Create articles, each with a different creation time so that we can do a
|
||||
// meaningful sort.
|
||||
$node1 = $this->drupalCreateNode(['type' => 'article', 'created' => REQUEST_TIME]);
|
||||
$node2 = $this->drupalCreateNode(['type' => 'article', 'created' => REQUEST_TIME + 1]);
|
||||
$node3 = $this->drupalCreateNode(['type' => 'article', 'created' => REQUEST_TIME + 2]);
|
||||
$node4 = $this->drupalCreateNode(['type' => 'article', 'created' => REQUEST_TIME + 3]);
|
||||
$node5 = $this->drupalCreateNode(['type' => 'article', 'created' => REQUEST_TIME + 4]);
|
||||
|
||||
// Create a page. This should never appear in the view created below.
|
||||
$page_node = $this->drupalCreateNode(['type' => 'page', 'created' => REQUEST_TIME + 2]);
|
||||
|
||||
// Create a view that sorts newest first, and shows 4 items in the page and
|
||||
// 3 in the block.
|
||||
$view = [];
|
||||
$view['label'] = $this->randomMachineName(16);
|
||||
$view['id'] = strtolower($this->randomMachineName(16));
|
||||
$view['description'] = $this->randomMachineName(16);
|
||||
$view['show[wizard_key]'] = 'node';
|
||||
$view['show[type]'] = 'article';
|
||||
$view['show[sort]'] = 'node_field_data-created:DESC';
|
||||
$view['page[create]'] = 1;
|
||||
$view['page[title]'] = $this->randomMachineName(16);
|
||||
$view['page[path]'] = $this->randomMachineName(16);
|
||||
$view['page[items_per_page]'] = 4;
|
||||
$view['block[create]'] = 1;
|
||||
$view['block[title]'] = $this->randomMachineName(16);
|
||||
$view['block[items_per_page]'] = 3;
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
|
||||
$this->drupalGet($view['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Make sure the page display shows the nodes we expect, and that they
|
||||
// appear in the expected order.
|
||||
$this->assertUrl($view['page[path]']);
|
||||
$this->assertText($view['page[title]']);
|
||||
$content = $this->getRawContent();
|
||||
$this->assertText($node5->label());
|
||||
$this->assertText($node4->label());
|
||||
$this->assertText($node3->label());
|
||||
$this->assertText($node2->label());
|
||||
$this->assertNoText($node1->label());
|
||||
$this->assertNoText($page_node->label());
|
||||
$pos5 = strpos($content, $node5->label());
|
||||
$pos4 = strpos($content, $node4->label());
|
||||
$pos3 = strpos($content, $node3->label());
|
||||
$pos2 = strpos($content, $node2->label());
|
||||
$this->assertTrue($pos5 < $pos4 && $pos4 < $pos3 && $pos3 < $pos2, 'The nodes appear in the expected order in the page display.');
|
||||
|
||||
// Confirm that the block is listed in the block administration UI.
|
||||
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
|
||||
$this->clickLink('Place block');
|
||||
$this->assertText($view['label']);
|
||||
|
||||
// Place the block, visit a page that displays the block, and check that the
|
||||
// nodes we expect appear in the correct order.
|
||||
$this->drupalPlaceBlock("views_block:{$view['id']}-block_1");
|
||||
|
||||
$this->drupalGet('user');
|
||||
$content = $this->getRawContent();
|
||||
$this->assertText($node5->label());
|
||||
$this->assertText($node4->label());
|
||||
$this->assertText($node3->label());
|
||||
$this->assertNoText($node2->label());
|
||||
$this->assertNoText($node1->label());
|
||||
$this->assertNoText($page_node->label());
|
||||
$pos5 = strpos($content, $node5->label());
|
||||
$pos4 = strpos($content, $node4->label());
|
||||
$pos3 = strpos($content, $node3->label());
|
||||
$this->assertTrue($pos5 < $pos4 && $pos4 < $pos3, 'The nodes appear in the expected order in the block display.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Tests the ability of the views wizard to put views in a menu.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class MenuTest extends WizardTestBase {
|
||||
|
||||
/**
|
||||
* Tests the menu functionality.
|
||||
*/
|
||||
public function testMenus() {
|
||||
$this->drupalPlaceBlock('system_menu_block:main');
|
||||
|
||||
// Create a view with a page display and a menu link in the Main Menu.
|
||||
$view = [];
|
||||
$view['label'] = $this->randomMachineName(16);
|
||||
$view['id'] = strtolower($this->randomMachineName(16));
|
||||
$view['description'] = $this->randomMachineName(16);
|
||||
$view['page[create]'] = 1;
|
||||
$view['page[title]'] = $this->randomMachineName(16);
|
||||
$view['page[path]'] = $this->randomMachineName(16);
|
||||
$view['page[link]'] = 1;
|
||||
$view['page[link_properties][menu_name]'] = 'main';
|
||||
$view['page[link_properties][title]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
|
||||
|
||||
// Make sure there is a link to the view from the front page (where we
|
||||
// expect the main menu to display).
|
||||
$this->drupalGet('');
|
||||
$this->assertResponse(200);
|
||||
$this->assertLink($view['page[link_properties][title]']);
|
||||
$this->assertLinkByHref(Url::fromUri('base:' . $view['page[path]'])->toString());
|
||||
|
||||
// Make sure the link is associated with the main menu.
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||
$link = $menu_link_manager->createInstance('views_view:views.' . $view['id'] . '.page_1');
|
||||
$url = $link->getUrlObject();
|
||||
$this->assertEqual($url->getRouteName(), 'view.' . $view['id'] . '.page_1', SafeMarkup::format('Found a link to %path in the main menu', ['%path' => $view['page[path]']]));
|
||||
$metadata = $link->getMetaData();
|
||||
$this->assertEqual(['view_id' => $view['id'], 'display_id' => 'page_1'], $metadata);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
/**
|
||||
* Tests node wizard and generic entity integration.
|
||||
*
|
||||
* @group Views
|
||||
* @group node
|
||||
*/
|
||||
class NodeWizardTest extends WizardTestBase {
|
||||
|
||||
/**
|
||||
* Tests creating a view with node titles.
|
||||
*/
|
||||
public function testViewAddWithNodeTitles() {
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
|
||||
$view = [];
|
||||
$view['label'] = $this->randomMachineName(16);
|
||||
$view['id'] = strtolower($this->randomMachineName(16));
|
||||
$view['description'] = $this->randomMachineName(16);
|
||||
$view['page[create]'] = FALSE;
|
||||
$view['show[wizard_key]'] = 'node';
|
||||
$view['page[style][row_plugin]'] = 'titles';
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
|
||||
|
||||
$view_storage_controller = \Drupal::entityManager()->getStorage('view');
|
||||
/** @var \Drupal\views\Entity\View $view */
|
||||
$view = $view_storage_controller->load($view['id']);
|
||||
|
||||
$display_options = $view->getDisplay('default')['display_options'];
|
||||
// Ensure that the 'entity_table' and 'entity_field' properties are set
|
||||
// property.
|
||||
$this->assertEqual('node', $display_options['fields']['title']['entity_type']);
|
||||
$this->assertEqual('title', $display_options['fields']['title']['entity_field']);
|
||||
|
||||
$this->assertEqual('node', $display_options['filters']['status']['entity_type']);
|
||||
$this->assertEqual('status', $display_options['filters']['status']['entity_field']);
|
||||
|
||||
$this->assertEqual('node', $display_options['sorts']['created']['entity_type']);
|
||||
$this->assertEqual('created', $display_options['sorts']['created']['entity_field']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
/**
|
||||
* Tests the ability of the views wizard to create views without a pager.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class PagerTest extends WizardTestBase {
|
||||
|
||||
/**
|
||||
* Tests the pager option.
|
||||
*/
|
||||
public function testPager() {
|
||||
// Create nodes, each with a different creation time so that we have
|
||||
// conditions that are meaningful for the use of a pager.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
for ($i = 0; $i < 12; $i++) {
|
||||
$this->drupalCreateNode(['created' => REQUEST_TIME - $i]);
|
||||
}
|
||||
|
||||
// Make a View that uses a pager.
|
||||
$path_with_pager = 'test-view-with-pager';
|
||||
$this->createViewAtPath($path_with_pager, TRUE);
|
||||
$this->drupalGet($path_with_pager);
|
||||
|
||||
// This technique for finding the existence of a pager
|
||||
// matches that used in Drupal\views_ui\Tests\PreviewTest.php.
|
||||
$elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
|
||||
$this->assertTrue(!empty($elements), 'Full pager found.');
|
||||
|
||||
// Make a View that does not have a pager.
|
||||
$path_with_no_pager = 'test-view-without-pager';
|
||||
$this->createViewAtPath($path_with_no_pager, FALSE);
|
||||
$this->drupalGet($path_with_no_pager);
|
||||
$elements = $this->xpath('//ul[contains(@class, :class)]/li', [':class' => 'pager__items']);
|
||||
$this->assertTrue(empty($elements), 'Full pager not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple View of nodes at a given path.
|
||||
*
|
||||
* @param string $path
|
||||
* The path at which the View should be created.
|
||||
* @param bool $pager
|
||||
* A boolean for whether the View created should use a pager.
|
||||
*/
|
||||
protected function createViewAtPath($path, $pager = TRUE) {
|
||||
$view = [];
|
||||
$view['label'] = $this->randomMachineName(16);
|
||||
$view['id'] = strtolower($this->randomMachineName(16));
|
||||
$view['show[sort]'] = 'node_field_data-created:ASC';
|
||||
$view['page[create]'] = 1;
|
||||
$view['page[title]'] = $this->randomMachineName(16);
|
||||
$view['page[path]'] = $path;
|
||||
$view['page[pager]'] = $pager;
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
/**
|
||||
* Tests the ability of the views wizard to create views with sorts.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class SortingTest extends WizardTestBase {
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the sorting functionality.
|
||||
*/
|
||||
public function testSorting() {
|
||||
// Create nodes, each with a different creation time so that we can do a
|
||||
// meaningful sort.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$node1 = $this->drupalCreateNode(['created' => REQUEST_TIME]);
|
||||
$node2 = $this->drupalCreateNode(['created' => REQUEST_TIME + 1]);
|
||||
$node3 = $this->drupalCreateNode(['created' => REQUEST_TIME + 2]);
|
||||
|
||||
// Create a view that sorts oldest first.
|
||||
$view1 = [];
|
||||
$view1['label'] = $this->randomMachineName(16);
|
||||
$view1['id'] = strtolower($this->randomMachineName(16));
|
||||
$view1['description'] = $this->randomMachineName(16);
|
||||
$view1['show[sort]'] = 'node_field_data-created:ASC';
|
||||
$view1['page[create]'] = 1;
|
||||
$view1['page[title]'] = $this->randomMachineName(16);
|
||||
$view1['page[path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view1, t('Save and edit'));
|
||||
$this->drupalGet($view1['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Make sure the view shows the nodes in the expected order.
|
||||
$this->assertUrl($view1['page[path]']);
|
||||
$this->assertText($view1['page[title]']);
|
||||
$content = $this->getRawContent();
|
||||
$this->assertText($node1->label());
|
||||
$this->assertText($node2->label());
|
||||
$this->assertText($node3->label());
|
||||
$pos1 = strpos($content, $node1->label());
|
||||
$pos2 = strpos($content, $node2->label());
|
||||
$pos3 = strpos($content, $node3->label());
|
||||
$this->assertTrue($pos1 < $pos2 && $pos2 < $pos3, 'The nodes appear in the expected order in a view that sorts by oldest first.');
|
||||
|
||||
// Create a view that sorts newest first.
|
||||
$view2 = [];
|
||||
$view2['label'] = $this->randomMachineName(16);
|
||||
$view2['id'] = strtolower($this->randomMachineName(16));
|
||||
$view2['description'] = $this->randomMachineName(16);
|
||||
$view2['show[sort]'] = 'node_field_data-created:DESC';
|
||||
$view2['page[create]'] = 1;
|
||||
$view2['page[title]'] = $this->randomMachineName(16);
|
||||
$view2['page[path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm('admin/structure/views/add', $view2, t('Save and edit'));
|
||||
$this->drupalGet($view2['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Make sure the view shows the nodes in the expected order.
|
||||
$this->assertUrl($view2['page[path]']);
|
||||
$this->assertText($view2['page[title]']);
|
||||
$content = $this->getRawContent();
|
||||
$this->assertText($node3->label());
|
||||
$this->assertText($node2->label());
|
||||
$this->assertText($node1->label());
|
||||
$pos3 = strpos($content, $node3->label());
|
||||
$pos2 = strpos($content, $node2->label());
|
||||
$pos1 = strpos($content, $node1->label());
|
||||
$this->assertTrue($pos3 < $pos2 && $pos2 < $pos1, 'The nodes appear in the expected order in a view that sorts by newest first.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the ability of the views wizard to create views filtered by taxonomy.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class TaggedWithTest extends WizardTestBase {
|
||||
|
||||
use EntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* Node type with an autocomplete tagging field.
|
||||
*
|
||||
* @var \Drupal\node\NodeTypeInterface
|
||||
*/
|
||||
protected $nodeTypeWithTags;
|
||||
|
||||
/**
|
||||
* Node type without an autocomplete tagging field.
|
||||
*
|
||||
* @var \Drupal\node\NodeTypeInterface
|
||||
*/
|
||||
protected $nodeTypeWithoutTags;
|
||||
|
||||
/**
|
||||
* The vocabulary used for the test tag field.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $tagVocabulary;
|
||||
|
||||
/**
|
||||
* Holds the field storage for test tag field.
|
||||
*
|
||||
* @var \Drupal\field\FieldStorageConfigInterface
|
||||
*/
|
||||
protected $tagFieldStorage;
|
||||
|
||||
/**
|
||||
* Name of the test tag field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tagFieldName;
|
||||
|
||||
/**
|
||||
* Field definition for the test tag field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tagField;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create two content types. One will have an autocomplete tagging field,
|
||||
// and one won't.
|
||||
$this->nodeTypeWithTags = $this->drupalCreateContentType();
|
||||
$this->nodeTypeWithoutTags = $this->drupalCreateContentType();
|
||||
|
||||
// Create the vocabulary for the tag field.
|
||||
$this->tagVocabulary = Vocabulary::create([
|
||||
'name' => 'Views testing tags',
|
||||
'vid' => 'views_testing_tags',
|
||||
]);
|
||||
$this->tagVocabulary->save();
|
||||
|
||||
// Create the tag field itself.
|
||||
$this->tagFieldName = 'field_views_testing_tags';
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->tagVocabulary->id() => $this->tagVocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', $this->nodeTypeWithTags->id(), $this->tagFieldName, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
entity_get_form_display('node', $this->nodeTypeWithTags->id(), 'default')
|
||||
->setComponent($this->tagFieldName, [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
])
|
||||
->save();
|
||||
|
||||
entity_get_display('node', $this->nodeTypeWithTags->id(), 'default')
|
||||
->setComponent($this->tagFieldName, [
|
||||
'type' => 'entity_reference_label',
|
||||
'weight' => 10,
|
||||
])
|
||||
->save();
|
||||
entity_get_display('node', $this->nodeTypeWithTags->id(), 'teaser')
|
||||
->setComponent('field_views_testing_tags', [
|
||||
'type' => 'entity_reference_label',
|
||||
'weight' => 10,
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the "tagged with" functionality.
|
||||
*/
|
||||
public function testTaggedWith() {
|
||||
// In this test we will only create nodes that have an instance of the tag
|
||||
// field.
|
||||
$node_add_path = 'node/add/' . $this->nodeTypeWithTags->id();
|
||||
|
||||
// Create three nodes, with different tags.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $node_tag1_title = $this->randomMachineName();
|
||||
$edit[$this->tagFieldName . '[target_id]'] = 'tag1';
|
||||
$this->drupalPostForm($node_add_path, $edit, t('Save'));
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $node_tag1_tag2_title = $this->randomMachineName();
|
||||
$edit[$this->tagFieldName . '[target_id]'] = 'tag1, tag2';
|
||||
$this->drupalPostForm($node_add_path, $edit, t('Save'));
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $node_no_tags_title = $this->randomMachineName();
|
||||
$this->drupalPostForm($node_add_path, $edit, t('Save'));
|
||||
|
||||
// Create a view that filters by taxonomy term "tag1". It should show only
|
||||
// the two nodes from above that are tagged with "tag1".
|
||||
$view1 = [];
|
||||
// First select the node type and update the form so the correct tag field
|
||||
// is used.
|
||||
$view1['show[type]'] = $this->nodeTypeWithTags->id();
|
||||
$this->drupalPostForm('admin/structure/views/add', $view1, t('Update "of type" choice'));
|
||||
// Now resubmit the entire form to the same URL.
|
||||
$view1['label'] = $this->randomMachineName(16);
|
||||
$view1['id'] = strtolower($this->randomMachineName(16));
|
||||
$view1['description'] = $this->randomMachineName(16);
|
||||
$view1['show[tagged_with]'] = 'tag1';
|
||||
$view1['page[create]'] = 1;
|
||||
$view1['page[title]'] = $this->randomMachineName(16);
|
||||
$view1['page[path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm(NULL, $view1, t('Save and edit'));
|
||||
// Visit the page and check that the nodes we expect are present and the
|
||||
// ones we don't expect are absent.
|
||||
$this->drupalGet($view1['page[path]']);
|
||||
$this->assertResponse(200);
|
||||
$this->assertText($node_tag1_title);
|
||||
$this->assertText($node_tag1_tag2_title);
|
||||
$this->assertNoText($node_no_tags_title);
|
||||
|
||||
// Create a view that filters by taxonomy term "tag2". It should show only
|
||||
// the one node from above that is tagged with "tag2".
|
||||
$view2 = [];
|
||||
$view2['show[type]'] = $this->nodeTypeWithTags->id();
|
||||
$this->drupalPostForm('admin/structure/views/add', $view2, t('Update "of type" choice'));
|
||||
$this->assertResponse(200);
|
||||
$view2['label'] = $this->randomMachineName(16);
|
||||
$view2['id'] = strtolower($this->randomMachineName(16));
|
||||
$view2['description'] = $this->randomMachineName(16);
|
||||
$view2['show[tagged_with]'] = 'tag2';
|
||||
$view2['page[create]'] = 1;
|
||||
$view2['page[title]'] = $this->randomMachineName(16);
|
||||
$view2['page[path]'] = $this->randomMachineName(16);
|
||||
$this->drupalPostForm(NULL, $view2, t('Save and edit'));
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet($view2['page[path]']);
|
||||
$this->assertNoText($node_tag1_title);
|
||||
$this->assertText($node_tag1_tag2_title);
|
||||
$this->assertNoText($node_no_tags_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the "tagged with" form element only shows for node types that support it.
|
||||
*/
|
||||
public function testTaggedWithByNodeType() {
|
||||
// The tagging field is associated with one of our node types only. So the
|
||||
// "tagged with" form element on the view wizard should appear on the form
|
||||
// by default (when the wizard is configured to display all content) and
|
||||
// also when the node type that has the tagging field is selected, but not
|
||||
// when the node type that doesn't have the tagging field is selected.
|
||||
$tags_xpath = '//input[@name="show[tagged_with]"]';
|
||||
$this->drupalGet('admin/structure/views/add');
|
||||
$this->assertFieldByXpath($tags_xpath);
|
||||
$view['show[type]'] = $this->nodeTypeWithTags->id();
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice'));
|
||||
$this->assertFieldByXpath($tags_xpath);
|
||||
$view['show[type]'] = $this->nodeTypeWithoutTags->id();
|
||||
$this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)'));
|
||||
$this->assertNoFieldByXpath($tags_xpath);
|
||||
|
||||
// If we add an instance of the tagging field to the second node type, the
|
||||
// "tagged with" form element should not appear for it too.
|
||||
FieldConfig::create([
|
||||
'field_name' => $this->tagFieldName,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => $this->nodeTypeWithoutTags->id(),
|
||||
'settings' => [
|
||||
'handler' => 'default',
|
||||
'handler_settings' => [
|
||||
'target_bundles' => [
|
||||
$this->tagVocabulary->id() => $this->tagVocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
entity_get_form_display('node', $this->nodeTypeWithoutTags->id(), 'default')
|
||||
->setComponent($this->tagFieldName, [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
])
|
||||
->save();
|
||||
|
||||
$view['show[type]'] = $this->nodeTypeWithTags->id();
|
||||
$this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice'));
|
||||
$this->assertFieldByXpath($tags_xpath);
|
||||
$view['show[type]'] = $this->nodeTypeWithoutTags->id();
|
||||
$this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)'));
|
||||
$this->assertFieldByXpath($tags_xpath);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Functional\Wizard;
|
||||
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Views UI wizard tests.
|
||||
*/
|
||||
abstract class WizardTestBase extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'views_ui', 'block', 'rest'];
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Create and log in a user with administer views permission.
|
||||
$views_admin = $this->drupalCreateUser(['administer views', 'administer blocks', 'bypass node access', 'access user profiles', 'view all revisions']);
|
||||
$this->drupalLogin($views_admin);
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Handler;
|
||||
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the generic entity area handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\area\Entity
|
||||
*/
|
||||
class AreaEmptyTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('node');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views']['test_example'] = [
|
||||
'title' => 'Test Example area',
|
||||
'help' => 'A area handler which just exists for tests.',
|
||||
'area' => [
|
||||
'id' => 'test_example'
|
||||
]
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_example_area'];
|
||||
|
||||
/**
|
||||
* Tests that the header and footer areas are not rendered if empty.
|
||||
*/
|
||||
public function testRenderEmptyHeaderFooter() {
|
||||
$view = Views::getView('test_example_area');
|
||||
$view->initHandlers();
|
||||
|
||||
// Set example empty text.
|
||||
$empty_text = $this->randomMachineName();
|
||||
$empty_header = $this->randomMachineName();
|
||||
$empty_footer = $this->randomMachineName();
|
||||
|
||||
// Set empty text.
|
||||
$view->empty['test_example']->options['string'] = '<p>' . $empty_text . '</p>';
|
||||
// Set example header text.
|
||||
$view->header['test_example']->options['string'] = '<p>' . $empty_header . '</p>';
|
||||
// Set example footer text.
|
||||
$view->footer['test_example']->options['string'] = '<p>' . $empty_footer . '</p>';
|
||||
|
||||
// Verify that the empty header and footer sections have not been rendered.
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$this->assertText($empty_text);
|
||||
$this->assertNoText($empty_header);
|
||||
$this->assertNoText($empty_footer);
|
||||
|
||||
// Enable displaying the header and footer when the View is empty.
|
||||
$view->header['test_example']->options['empty'] = TRUE;
|
||||
$view->footer['test_example']->options['empty'] = TRUE;
|
||||
|
||||
// Verify that the header and footer sections have been rendered.
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$this->assertText($empty_header);
|
||||
$this->assertText($empty_footer);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Handler;
|
||||
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the result area handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\area\Result
|
||||
*/
|
||||
class AreaResultTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_area_result'];
|
||||
|
||||
/**
|
||||
* Tests the results area handler.
|
||||
*/
|
||||
public function testResult() {
|
||||
$view = Views::getView('test_area_result');
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$this->assertText('start: 1 | end: 5 | total: 5 | label: test_area_result | per page: 0 | current page: 1 | current record count: 5 | page count: 1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the results area handler.
|
||||
*/
|
||||
public function testResultEmpty() {
|
||||
$view = Views::getView('test_area_result');
|
||||
|
||||
// Test that the area is displayed if we have checked the empty checkbox.
|
||||
$view->setDisplay('default');
|
||||
|
||||
// Add a filter that will make the result set empty.
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'name' => [
|
||||
'id' => 'name',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'name',
|
||||
'relationship' => 'none',
|
||||
'operator' => '=',
|
||||
'value' => 'non-existing-name',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$this->assertText('start: 0 | end: 0 | total: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
|
||||
|
||||
// Test that the area is not displayed if we have not checked the empty
|
||||
// checkbox.
|
||||
$view->setDisplay('page_1');
|
||||
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
$output = \Drupal::service('renderer')->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$this->assertNoText('start: 0 | end: 0 | total: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Handler;
|
||||
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the core Drupal\views\Plugin\views\field\Numeric handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\field\Numeric
|
||||
*/
|
||||
class FieldNumericTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Tests the Numeric handler with different settings.
|
||||
*
|
||||
* @dataProvider providerTestFieldNumeric
|
||||
*/
|
||||
public function testFieldNumeric($field_settings, $values, $expected_values) {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
if (!empty($field_settings)) {
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', ['age' => $field_settings]);
|
||||
}
|
||||
$this->executeView($view);
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$view->result[0]->views_test_data_age = $value;
|
||||
$this->assertSame($expected_values[$key], $view->field['age']->advancedRender($view->result[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testFieldNumeric.
|
||||
*
|
||||
* @return array
|
||||
* The data set containing field settings, values to set and expected
|
||||
* values.
|
||||
*/
|
||||
public function providerTestFieldNumeric() {
|
||||
return [
|
||||
'no-formating' => [
|
||||
[],
|
||||
[0, 0.1234, -0.1234, 1000.1234, -1000.1234],
|
||||
['0', '0.1234', '-0.1234', '1,000.1234', '-1,000.1234'],
|
||||
],
|
||||
'precision_2-hide_empty-hide_zero' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 2,
|
||||
'set_precision' => TRUE,
|
||||
'empty_zero' => TRUE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
],
|
||||
[0, 0.1234, -0.1234, 1000.1234, -1000.1234, 0.0001, -0.0001, NULL, ''],
|
||||
['', '0.12', '-0.12', '1,000.12', '-1,000.12', '', '', '', ''],
|
||||
],
|
||||
'decimal-separator' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'decimal' => ',',
|
||||
'separator' => '.',
|
||||
'empty_zero' => TRUE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
],
|
||||
[0.1234, -0.1234, 1000.1234, -1000.1234],
|
||||
['0,1234', '-0,1234', '1.000,1234', '-1.000,1234'],
|
||||
],
|
||||
'precision_2-no_separator' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 2,
|
||||
'set_precision' => TRUE,
|
||||
'decimal' => ',',
|
||||
'separator' => '',
|
||||
'empty_zero' => TRUE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
],
|
||||
[1234, 1234.01, -1234, -1234.01],
|
||||
['1234,00', '1234,01', '-1234,00', '-1234,01'],
|
||||
],
|
||||
'precision_0-no_separator' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 0,
|
||||
'set_precision' => TRUE,
|
||||
'separator' => '',
|
||||
'empty_zero' => TRUE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
],
|
||||
[1234, 1234.01, -1234, -1234.01],
|
||||
['1234', '1234', '-1234', '-1234'],
|
||||
],
|
||||
'precision_0-hide_empty-zero_empty' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 0,
|
||||
'set_precision' => TRUE,
|
||||
'empty_zero' => TRUE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
'prefix' => 'test: ',
|
||||
],
|
||||
[0, 0.1234, -0.1234, 1000.1234, -1000.1234],
|
||||
['', '', '', 'test: 1,000', 'test: -1,000'],
|
||||
],
|
||||
'precision_0-hide_empty-not_zero_empty' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 0,
|
||||
'set_precision' => TRUE,
|
||||
'empty_zero' => FALSE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
'prefix' => '',
|
||||
],
|
||||
[0, 0.1234, -0.1234],
|
||||
['0', '0', '0'],
|
||||
],
|
||||
'precision_2-hide_empty-not_zero_empty' => [
|
||||
[
|
||||
'hide_empty' => TRUE,
|
||||
'precision' => 2,
|
||||
'set_precision' => TRUE,
|
||||
'empty_zero' => FALSE,
|
||||
'id' => 'age',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'age',
|
||||
'relationship' => 'none',
|
||||
'prefix' => '',
|
||||
],
|
||||
[0, 0.001234, -0.001234, NULL],
|
||||
['0.00', '0.00', '0.00', ''],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Plugin;
|
||||
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views_test_data\Plugin\views\display_extender\DisplayExtenderTest as DisplayExtenderTestData;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the display extender plugins.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views_test_data\Plugin\views\display_extender\DisplayExtenderTest
|
||||
*/
|
||||
class DisplayExtenderTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Test display extenders.
|
||||
*/
|
||||
public function testDisplayExtenders() {
|
||||
$this->config('views.settings')->set('display_extenders', ['display_extender_test'])->save();
|
||||
$this->assertEqual(count(Views::getEnabledDisplayExtenders()), 1, 'Make sure that there is only one enabled display extender.');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->initDisplay();
|
||||
|
||||
$this->assertEqual(count($view->display_handler->getExtenders()), 1, 'Make sure that only one extender is initialized.');
|
||||
|
||||
$display_extender = $view->display_handler->getExtenders()['display_extender_test'];
|
||||
$this->assertTrue($display_extender instanceof DisplayExtenderTestData, 'Make sure the right class got initialized.');
|
||||
|
||||
$view->preExecute();
|
||||
$this->assertTrue($display_extender->testState['preExecute'], 'Make sure the display extender was able to react on preExecute.');
|
||||
$view->execute();
|
||||
$this->assertTrue($display_extender->testState['query'], 'Make sure the display extender was able to react on query.');
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Drupal\Tests\views\Kernel\Plugin;
|
|||
|
||||
use Drupal\Core\Menu\MenuTreeParameters;
|
||||
use Drupal\Core\Session\AnonymousUserSession;
|
||||
use Drupal\views\Entity\View;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -22,7 +23,7 @@ class DisplayPageTest extends ViewsKernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_page_display', 'test_page_display_route', 'test_page_display_menu'];
|
||||
public static $testViews = ['test_page_display', 'test_page_display_route', 'test_page_display_menu', 'test_display_more'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -149,4 +150,71 @@ class DisplayPageTest extends ViewsKernelTestBase {
|
|||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the readmore functionality.
|
||||
*/
|
||||
public function testReadMore() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
$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('//div[@class=:class]/a', [':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('//div[@class=:class]/a', [':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('//div[@class=:class]/a', [':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', [
|
||||
'type' => 'some',
|
||||
'options' => [
|
||||
'items_per_page' => 1,
|
||||
'offset' => 0,
|
||||
],
|
||||
]);
|
||||
$this->executeView($view);
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
$this->setRawContent($output);
|
||||
$result = $this->xpath('//div[@class=:class]/a', [':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.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Plugin;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the exposed form markup.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views_test_data\Plugin\views\display_extender\DisplayExtenderTest
|
||||
*/
|
||||
class ExposedFormRenderTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_exposed_form_buttons'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('node');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the exposed form markup.
|
||||
*/
|
||||
public function testExposedFormRender() {
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$this->executeView($view);
|
||||
$exposed_form = $view->display_handler->getPlugin('exposed_form');
|
||||
$output = $exposed_form->renderExposedForm();
|
||||
$this->setRawContent(\Drupal::service('renderer')->renderRoot($output));
|
||||
|
||||
$this->assertFieldByXpath('//form/@id', Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display), 'Expected form ID found.');
|
||||
|
||||
$view->setDisplay('page_1');
|
||||
$expected_action = $view->display_handler->getUrlInfo()->toString();
|
||||
$this->assertFieldByXPath('//form/@action', $expected_action, 'The expected value for the action attribute was found.');
|
||||
// Make sure the description is shown.
|
||||
$result = $this->xpath('//form//div[contains(@id, :id) and normalize-space(text())=:description]', [':id' => 'edit-type--description', ':description' => t('Exposed description')]);
|
||||
$this->assertEqual(count($result), 1, 'Filter description was found.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Plugin;
|
||||
|
||||
use Drupal\simpletest\UserCreationTrait;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the base relationship handler.
|
||||
*
|
||||
* @group views
|
||||
* @see \Drupal\views\Plugin\views\relationship\RelationshipPluginBase
|
||||
*/
|
||||
class RelationshipJoinInTest extends RelationshipJoinTestBase {
|
||||
|
||||
use UserCreationTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Maps between the key in the expected result and the query result.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $columnMap = [
|
||||
'views_test_data_name' => 'name',
|
||||
'users_field_data_views_test_data_uid' => 'uid',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests the query result of a view with a relationship with an IN condition.
|
||||
*/
|
||||
public function testRelationshipInQuery() {
|
||||
// Update the first two Beatles to be authored by Kristiaan.
|
||||
$account_k = $this->createUser([], 'Kristiaan');
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id IN (1,2)", [':uid' => $account_k->id()]);
|
||||
|
||||
// Update the other two Beatles to be authored by Django.
|
||||
$account_d = $this->createUser([], 'Django');
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id IN (3,4)", [':uid' => $account_d->id()]);
|
||||
|
||||
// Update Meredith to be authored by Silvie.
|
||||
$account_s = $this->createUser([], 'Silvie');
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 5", [':uid' => $account_s->id()]);
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
|
||||
$view->displayHandlers->get('default')->overrideOption('relationships', [
|
||||
'uid' => [
|
||||
'id' => 'uid',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'uid',
|
||||
'required' => TRUE,
|
||||
],
|
||||
]);
|
||||
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'uid' => [
|
||||
'id' => 'uid',
|
||||
'table' => 'users_field_data',
|
||||
'field' => 'uid',
|
||||
'relationship' => 'uid',
|
||||
],
|
||||
]);
|
||||
|
||||
$fields = $view->displayHandlers->get('default')->getOption('fields');
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', $fields + [
|
||||
'uid' => [
|
||||
'id' => 'uid',
|
||||
'table' => 'users_field_data',
|
||||
'field' => 'uid',
|
||||
'relationship' => 'uid',
|
||||
],
|
||||
]);
|
||||
|
||||
// Check for all beatles created by Kristiaan.
|
||||
$view->initHandlers();
|
||||
$view->filter['uid']->value = [$account_k->id()];
|
||||
$this->executeView($view);
|
||||
|
||||
$expected_result = [
|
||||
['name' => 'John', 'uid' => $account_k->id()],
|
||||
['name' => 'George', 'uid' => $account_k->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
|
||||
$view->destroy();
|
||||
|
||||
// Check for all beatles created by Django. This should not return anything
|
||||
// as the 'extra' option on the join prohibits relating to any authors but
|
||||
// Kristiaan or Silvie.
|
||||
$view->initHandlers();
|
||||
$view->filter['uid']->value = [$account_d->id()];
|
||||
$this->executeView($view);
|
||||
|
||||
$expected_result = [];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
|
||||
$view->destroy();
|
||||
|
||||
// Check for all people created by anyone.
|
||||
$view->initHandlers();
|
||||
$this->executeView($view);
|
||||
$expected_result = [
|
||||
['name' => 'John', 'uid' => $account_k->id()],
|
||||
['name' => 'George', 'uid' => $account_k->id()],
|
||||
['name' => 'Meredith', 'uid' => $account_s->id()],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an IN condition for the user name.
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
// Only relate if the author's name is Kristiaan or Silvie.
|
||||
$data['views_test_data']['uid']['relationship']['extra'][] = [
|
||||
'field' => 'name',
|
||||
'value' => ['Kristiaan', 'Silvie'],
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue