Newer
Older
namespace Drupal\views\Tests\Plugin;
use Drupal\Component\Utility\Html;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
Alex Pott
committed
use Drupal\views\Entity\View;
* Tests exposed forms functionality.
*
* @group views
class ExposedFormTest extends ViewTestBase {
Damian Lee
committed
use AssertPageCacheContextsAndTagsTrait;
catch
committed
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_exposed_form_buttons', 'test_exposed_block', 'test_exposed_form_sort_items_per_page'];
catch
committed
Tim Plunkett
committed
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui', 'block', 'entity_test'];
Tim Plunkett
committed
protected function setUp() {
parent::setUp();
$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');
Alex Pott
committed
$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'));
catch
committed
/**
* 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', [
catch
committed
'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'
],
]
]);
catch
committed
$view->save();
$this->drupalGet('test_exposed_form_buttons', ['query' => [$identifier => 'article']]);
catch
committed
$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', [
catch
committed
'type' => [
Alex Pott
committed
'exposed' => TRUE,
catch
committed
'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'
],
]
]);
catch
committed
$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() {
Alex Pott
committed
// Test the button is hidden when there is no exposed input.
$this->drupalGet('test_exposed_form_buttons');
Alex Pott
committed
$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.');
Alex Pott
committed
// Test the button is hidden after reset.
$this->assertNoField('edit-reset');
Angie Byron
committed
// Test the reset works with type set.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article', 'op' => 'Reset']]);
Angie Byron
committed
$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');
$view = Views::getView('test_exposed_form_buttons');
Damian Lee
committed
$view->setDisplay();
Daniel Wehner
committed
$exposed_form = $view->display_handler->getOption('exposed_form');
Alex Pott
committed
$exposed_form['options']['reset_button_label'] = $expected_label = $this->randomMachineName();
$exposed_form['options']['reset_button'] = TRUE;
Daniel Wehner
committed
$view->display_handler->setOption('exposed_form', $exposed_form);
Alex Pott
committed
// Look whether the reset button label changed.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
Tim Plunkett
committed
$this->assertResponse(200);
$this->helperButtonHasLabel('edit-reset', $expected_label);
}
/**
* Tests the exposed form markup.
*/
public function testExposedFormRender() {
catch
committed
$view = Views::getView('test_exposed_form_buttons');
$this->executeView($view);
$exposed_form = $view->display_handler->getPlugin('exposed_form');
Alex Pott
committed
$output = $exposed_form->renderExposedForm();
$this->setRawContent(\Drupal::service('renderer')->renderRoot($output));
$this->assertFieldByXpath('//form/@id', $this->getExpectedExposedFormId($view), '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.');
Alex Pott
committed
// 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')]);
Alex Pott
committed
$this->assertEqual(count($result), 1, 'Filter description was found.');
}
/**
* 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']);
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
$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())]);
$this->assertFieldByXpath($xpath, $this->getExpectedExposedFormId($view), 'Expected form found in views block.');
// 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');
Alex Pott
committed
$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);
}
}
catch
committed
/**
* Test the input required exposed form type.
*/
public function testInputRequired() {
Alex Pott
committed
$view = View::load('test_exposed_form_buttons');
catch
committed
$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'));
catch
committed
// 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']]);
catch
committed
// 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.');
}
Alex Pott
committed
/**
* 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']]);
Alex Pott
committed
$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',
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
'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;
}
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.');
}