Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Form controller for search_embedded_form form.
*
* @internal
*/
class SearchEmbeddedForm extends FormBase {
@ -48,7 +50,7 @@ class SearchEmbeddedForm extends FormBase {
$state = \Drupal::state();
$submit_count = (int) $state->get('search_embedded_form.submit_count');
$state->set('search_embedded_form.submit_count', $submit_count + 1);
drupal_set_message($this->t('Test form was submitted'));
$this->messenger()->addStatus($this->t('Test form was submitted'));
}
}

View file

@ -5,5 +5,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- test_page_test
- drupal:test_page_test

View file

@ -2,7 +2,7 @@
namespace Drupal\search_extra_type\Plugin\Search;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\UrlGeneratorTrait;
use Drupal\Core\Url;
@ -59,7 +59,7 @@ class SearchExtraTypeSearch extends ConfigurableSearchPluginBase {
'link' => Url::fromRoute('test_page_test.test_page')->toString(),
'type' => 'Dummy result type',
'title' => 'Dummy title',
'snippet' => SafeMarkup::format("Dummy search snippet to display. Keywords: @keywords\n\nConditions: @search_parameters", ['@keywords' => $this->keywords, '@search_parameters' => print_r($this->searchParameters, TRUE)]),
'snippet' => new FormattableMarkup("Dummy search snippet to display. Keywords: @keywords\n\nConditions: @search_parameters", ['@keywords' => $this->keywords, '@search_parameters' => print_r($this->searchParameters, TRUE)]),
],
];
}
@ -81,7 +81,7 @@ class SearchExtraTypeSearch extends ConfigurableSearchPluginBase {
$pager = [
'#type' => 'pager',
];
$output['suffix']['#markup'] = '</ol>' . drupal_render($pager);
$output['suffix']['#markup'] = '</ol>' . \Drupal::service('renderer')->render($pager);
return $output;
}

View file

@ -19,13 +19,13 @@ function search_langcode_test_search_preprocess($text, $langcode = NULL) {
// Prints the langcode for testPreprocessLangcode() and adds some
// extra text.
else {
drupal_set_message('Langcode Preprocess Test: ' . $langcode);
\Drupal::messenger()->addStatus('Langcode Preprocess Test: ' . $langcode);
$text .= 'Additional text';
}
}
// Prints the langcode for testPreprocessLangcode().
elseif (isset($langcode)) {
drupal_set_message('Langcode Preprocess Test: ' . $langcode);
\Drupal::messenger()->addStatus('Langcode Preprocess Test: ' . $langcode);
// Preprocessing for the excerpt test.
if ($langcode == 'ex') {

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\search\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase;
/**
* @group hal
*/
class SearchPageHalJsonAnonTest extends SearchPageResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\search\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase;
/**
* @group hal
*/
class SearchPageHalJsonBasicAuthTest extends SearchPageResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\search\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase;
/**
* @group hal
*/
class SearchPageHalJsonCookieTest extends SearchPageResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class SearchPageJsonAnonTest extends SearchPageResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class SearchPageJsonBasicAuthTest extends SearchPageResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class SearchPageJsonCookieTest extends SearchPageResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,111 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\search\Entity\SearchPage;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
abstract class SearchPageResourceTestBase extends EntityResourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'search'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'search_page';
/**
* @var \Drupal\search\SearchPageInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['access content']);
break;
case 'POST':
case 'PATCH':
case 'DELETE':
$this->grantPermissionsToTestedRole(['administer search']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$search_page = SearchPage::create([
'id' => 'hinode_search',
'plugin' => 'node_search',
'label' => 'Search of magnetic activity of the Sun',
'path' => 'sun',
]);
$search_page->save();
return $search_page;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'configuration' => [
'rankings' => [],
],
'dependencies' => [
'module' => ['node'],
],
'id' => 'hinode_search',
'label' => 'Search of magnetic activity of the Sun',
'langcode' => 'en',
'path' => 'sun',
'plugin' => 'node_search',
'status' => TRUE,
'uuid' => $this->entity->uuid(),
'weight' => 0,
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
// @todo Update in https://www.drupal.org/node/2300677.
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'GET':
return "The 'access content' permission is required.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessCacheability() {
// @see \Drupal\search\SearchPageAccessControlHandler::checkAccess()
return parent::getExpectedUnauthorizedAccessCacheability()
->addCacheTags(['config:search.page.hinode_search']);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class SearchPageXmlAnonTest extends SearchPageResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class SearchPageXmlBasicAuthTest extends SearchPageResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\search\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class SearchPageXmlCookieTest extends SearchPageResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,122 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Indexes content and tests the advanced search form.
*
* @group search
*/
class SearchAdvancedSearchFormTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search', 'dblog'];
/**
* A node to use for testing.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
// Create and log in user.
$test_user = $this->drupalCreateUser(['access content', 'search content', 'use advanced search', 'administer nodes']);
$this->drupalLogin($test_user);
// Create initial node.
$this->node = $this->drupalCreateNode();
// First update the index. This does the initial processing.
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
// Then, run the shutdown function. Testing is a unique case where indexing
// and searching has to happen in the same request, so running the shutdown
// function manually is needed to finish the indexing process.
search_update_totals();
}
/**
* Tests advanced search by node type.
*/
public function testNodeType() {
// Verify some properties of the node that was created.
$this->assertTrue($this->node->getType() == 'page', 'Node type is Basic page.');
$dummy_title = 'Lorem ipsum';
$this->assertNotEqual($dummy_title, $this->node->label(), "Dummy title doesn't equal node title.");
// Search for the dummy title with a GET query.
$this->drupalGet('search/node', ['query' => ['keys' => $dummy_title]]);
$this->assertNoText($this->node->label(), 'Basic page node is not found with dummy title.');
// Search for the title of the node with a GET query.
$this->drupalGet('search/node', ['query' => ['keys' => $this->node->label()]]);
$this->assertText($this->node->label(), 'Basic page node is found with GET query.');
// Search for the title of the node with a POST query.
$edit = ['or' => $this->node->label()];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
$this->assertText($this->node->label(), 'Basic page node is found with POST query.');
// Search by node type.
$this->drupalPostForm('search/node', array_merge($edit, ['type[page]' => 'page']), 'edit-submit--2');
$this->assertText($this->node->label(), 'Basic page node is found with POST query and type:page.');
$this->drupalPostForm('search/node', array_merge($edit, ['type[article]' => 'article']), 'edit-submit--2');
$this->assertText('search yielded no results', 'Article node is not found with POST query and type:article.');
}
/**
* Tests that after submitting the advanced search form, the form is refilled.
*/
public function testFormRefill() {
$edit = [
'keys' => 'cat',
'or' => 'dog gerbil',
'phrase' => 'pets are nice',
'negative' => 'fish snake',
'type[page]' => 'page',
];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Test that the encoded query appears in the page title. Only test the
// part not including the quote, because assertText() cannot seem to find
// the quote marks successfully.
$this->assertText('Search for cat dog OR gerbil -fish -snake');
// Verify that all of the form fields are filled out.
foreach ($edit as $key => $value) {
if ($key != 'type[page]') {
$elements = $this->xpath('//input[@name=:name]', [':name' => $key]);
$this->assertTrue(isset($elements[0]) && $elements[0]->getValue() == $value, "Field $key is set to $value");
}
else {
$elements = $this->xpath('//input[@name=:name]', [':name' => $key]);
$this->assertTrue(isset($elements[0]) && !empty($elements[0]->getAttribute('checked')), "Field $key is checked");
}
}
// Now test by submitting the or/not part of the query in the main
// search box, and verify that the advanced form is not filled out.
// (It shouldn't be filled out unless you submit values in those fields.)
$edit2 = ['keys' => 'cat dog OR gerbil -fish -snake'];
$this->drupalPostForm('search/node', $edit2, 'edit-submit--2');
$this->assertText('Search for cat dog OR gerbil -fish -snake');
foreach ($edit as $key => $value) {
if ($key != 'type[page]') {
$elements = $this->xpath('//input[@name=:name]', [':name' => $key]);
$this->assertFalse(isset($elements[0]) && $elements[0]->getValue() == $value, "Field $key is not set to $value");
}
}
}
}

View file

@ -0,0 +1,109 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests if the search form block is available.
*
* @group search
*/
class SearchBlockTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['block', 'node', 'search', 'dblog'];
protected function setUp() {
parent::setUp();
// Create and log in user.
$admin_user = $this->drupalCreateUser(['administer blocks', 'search content']);
$this->drupalLogin($admin_user);
}
/**
* Test that the search form block can be placed and works.
*/
public function testSearchFormBlock() {
// Test availability of the search block in the admin "Place blocks" list.
$this->drupalGet('admin/structure/block');
$this->getSession()->getPage()->findLink('Place block')->click();
$this->assertLinkByHref('/admin/structure/block/add/search_form_block/classy', 0,
'Did not find the search block in block candidate list.');
$block = $this->drupalPlaceBlock('search_form_block');
$this->drupalGet('');
$this->assertText($block->label(), 'Block title was found.');
// Check that name attribute is not empty.
$pattern = "//input[@type='submit' and @name='']";
$elements = $this->xpath($pattern);
$this->assertTrue(empty($elements), 'The search input field does not have empty name attribute.');
// Test a normal search via the block form, from the front page.
$terms = ['keys' => 'test'];
$this->drupalPostForm('', $terms, t('Search'));
$this->assertResponse(200);
$this->assertText('Your search yielded no results');
// Test a search from the block on a 404 page.
$this->drupalGet('foo');
$this->assertResponse(404);
$this->drupalPostForm(NULL, $terms, t('Search'));
$this->assertResponse(200);
$this->assertText('Your search yielded no results');
$visibility = $block->getVisibility();
$visibility['request_path']['pages'] = 'search';
$block->setVisibilityConfig('request_path', $visibility['request_path']);
$this->drupalPostForm('', $terms, t('Search'));
$this->assertResponse(200);
$this->assertText('Your search yielded no results');
// Confirm that the form submits to the default search page.
/** @var $search_page_repository \Drupal\search\SearchPageRepositoryInterface */
$search_page_repository = \Drupal::service('search.search_page_repository');
$entity_id = $search_page_repository->getDefaultSearchPage();
$this->assertEqual(
$this->getUrl(),
\Drupal::url('search.view_' . $entity_id, [], ['query' => ['keys' => $terms['keys']], 'absolute' => TRUE]),
'Submitted to correct URL.'
);
// Test an empty search via the block form, from the front page.
$terms = ['keys' => ''];
$this->drupalPostForm('', $terms, t('Search'));
$this->assertResponse(200);
$this->assertText('Please enter some keywords');
// Confirm that the user is redirected to the search page, when form is
// submitted empty.
$this->assertEqual(
$this->getUrl(),
\Drupal::url('search.view_' . $entity_id, [], ['query' => ['keys' => ''], 'absolute' => TRUE]),
'Redirected to correct URL.'
);
// Test that after entering a too-short keyword in the form, you can then
// search again with a longer keyword. First test using the block form.
$this->drupalPostForm('node', ['keys' => $this->randomMachineName(1)], t('Search'));
$this->assertText('You must include at least one keyword to match in the content', 'Keyword message is displayed when searching for short word');
$this->assertNoText(t('Please enter some keywords'), 'With short word entered, no keywords message is not displayed');
$this->drupalPostForm(NULL, ['keys' => $this->randomMachineName()], t('Search'), [], 'search-block-form');
$this->assertNoText('You must include at least one keyword to match in the content', 'Keyword message is not displayed when searching for long word after short word search');
// Same test again, using the search page form for the second search this
// time.
$this->drupalPostForm('node', ['keys' => $this->randomMachineName(1)], t('Search'));
$this->drupalPostForm(NULL, ['keys' => $this->randomMachineName()], t('Search'), [], 'search-form');
$this->assertNoText('You must include at least one keyword to match in the content', 'Keyword message is not displayed when searching for long word after short word search');
}
}

View file

@ -4,6 +4,7 @@ namespace Drupal\Tests\search\Functional;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that comment count display toggles properly on comment status of node.
@ -17,16 +18,14 @@ use Drupal\comment\Tests\CommentTestTrait;
*
* @group search
*/
class SearchCommentCountToggleTest extends SearchTestBase {
class SearchCommentCountToggleTest extends BrowserTestBase {
use CommentTestTrait;
/**
* Modules to enable.
*
* @var array
* {@inheritdoc}
*/
public static $modules = ['node', 'comment'];
protected static $modules = ['node', 'comment', 'search', 'dblog'];
/**
* A user with permission to search and post comments.
@ -45,6 +44,8 @@ class SearchCommentCountToggleTest extends SearchTestBase {
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
// Create searching user.
$this->searchingUser = $this->drupalCreateUser(['search content', 'access content', 'access comments', 'post comments', 'skip comment approval']);

View file

@ -0,0 +1,362 @@
<?php
namespace Drupal\Tests\search\Functional;
use Behat\Mink\Exception\ResponseTextException;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
use Drupal\user\RoleInterface;
use Drupal\filter\Entity\FilterFormat;
/**
* Tests integration searching comments.
*
* @group search
*/
class SearchCommentTest extends BrowserTestBase {
use CommentTestTrait;
use CronRunTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['filter', 'node', 'comment', 'search'];
/**
* Test subject for comments.
*
* @var string
*/
protected $commentSubject;
/**
* ID for the administrator role.
*
* @var string
*/
protected $adminRole;
/**
* A user with various administrative permissions.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* Test node for searching.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
$full_html_format = FilterFormat::create([
'format' => 'full_html',
'name' => 'Full HTML',
'weight' => 1,
'filters' => [],
]);
$full_html_format->save();
// Create and log in an administrative user having access to the Full HTML
// text format.
$permissions = [
'administer filters',
$full_html_format->getPermissionName(),
'administer permissions',
'create page content',
'post comments',
'skip comment approval',
'access comments',
];
$this->adminUser = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->adminUser);
// Add a comment field.
$this->addDefaultCommentField('node', 'article');
}
/**
* Verify that comments are rendered using proper format in search results.
*/
public function testSearchResultsComment() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Create basic_html format that escapes all HTML.
$basic_html_format = FilterFormat::create([
'format' => 'basic_html',
'name' => 'Basic HTML',
'weight' => 1,
'filters' => [
'filter_html_escape' => ['status' => 1],
],
'roles' => [RoleInterface::AUTHENTICATED_ID],
]);
$basic_html_format->save();
$comment_body = 'Test comment body';
// Make preview optional.
$field = FieldConfig::loadByName('node', 'article', 'comment');
$field->setSetting('preview', DRUPAL_OPTIONAL);
$field->save();
// Allow anonymous users to search content.
$edit = [
RoleInterface::ANONYMOUS_ID . '[search content]' => 1,
RoleInterface::ANONYMOUS_ID . '[access comments]' => 1,
RoleInterface::ANONYMOUS_ID . '[post comments]' => 1,
];
$this->drupalPostForm('admin/people/permissions', $edit, t('Save permissions'));
// Create a node.
$node = $this->drupalCreateNode(['type' => 'article']);
// Post a comment using 'Full HTML' text format.
$edit_comment = [];
$edit_comment['subject[0][value]'] = 'Test comment subject';
$edit_comment['comment_body[0][value]'] = '<h1>' . $comment_body . '</h1>';
$full_html_format_id = 'full_html';
$edit_comment['comment_body[0][format]'] = $full_html_format_id;
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit_comment, t('Save'));
// Post a comment with an evil script tag in the comment subject and a
// script tag nearby a keyword in the comment body. Use the 'FULL HTML' text
// format so the script tag stored.
$edit_comment2 = [];
$edit_comment2['subject[0][value]'] = "<script>alert('subjectkeyword');</script>";
$edit_comment2['comment_body[0][value]'] = "nearbykeyword<script>alert('somethinggeneric');</script>";
$edit_comment2['comment_body[0][format]'] = $full_html_format_id;
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit_comment2, t('Save'));
// Post a comment with a keyword inside an evil script tag in the comment
// body. Use the 'FULL HTML' text format so the script tag is stored.
$edit_comment3 = [];
$edit_comment3['subject[0][value]'] = 'asubject';
$edit_comment3['comment_body[0][value]'] = "<script>alert('insidekeyword');</script>";
$edit_comment3['comment_body[0][format]'] = $full_html_format_id;
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit_comment3, t('Save'));
// Invoke search index update.
$this->drupalLogout();
$this->cronRun();
// Search for the comment subject.
$edit = [
'keys' => "'" . $edit_comment['subject[0][value]'] . "'",
];
$this->drupalPostForm('search/node', $edit, t('Search'));
$node_storage->resetCache([$node->id()]);
$node2 = $node_storage->load($node->id());
$this->assertText($node2->label(), 'Node found in search results.');
$this->assertText($edit_comment['subject[0][value]'], 'Comment subject found in search results.');
// Search for the comment body.
$edit = [
'keys' => "'" . $comment_body . "'",
];
$this->drupalPostForm(NULL, $edit, t('Search'));
$this->assertText($node2->label(), 'Node found in search results.');
// Verify that comment is rendered using proper format.
$this->assertText($comment_body, 'Comment body text found in search results.');
$this->assertNoRaw(t('n/a'), 'HTML in comment body is not hidden.');
$this->assertNoEscaped($edit_comment['comment_body[0][value]'], 'HTML in comment body is not escaped.');
// Search for the evil script comment subject.
$edit = [
'keys' => 'subjectkeyword',
];
$this->drupalPostForm('search/node', $edit, t('Search'));
// Verify the evil comment subject is escaped in search results.
$this->assertRaw('&lt;script&gt;alert(&#039;<strong>subjectkeyword</strong>&#039;);');
$this->assertNoRaw('<script>');
// Search for the keyword near the evil script tag in the comment body.
$edit = [
'keys' => 'nearbykeyword',
];
$this->drupalPostForm('search/node', $edit, t('Search'));
// Verify that nearby script tag in the evil comment body is stripped from
// search results.
$this->assertRaw('<strong>nearbykeyword</strong>');
$this->assertNoRaw('<script>');
// Search for contents inside the evil script tag in the comment body.
$edit = [
'keys' => 'insidekeyword',
];
$this->drupalPostForm('search/node', $edit, t('Search'));
// @todo Verify the actual search results.
// https://www.drupal.org/node/2551135
// Verify there is no script tag in search results.
$this->assertNoRaw('<script>');
// Hide comments.
$this->drupalLogin($this->adminUser);
$node->set('comment', CommentItemInterface::HIDDEN);
$node->save();
// Invoke search index update.
$this->drupalLogout();
$this->cronRun();
// Search for $title.
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText(t('Your search yielded no results.'));
}
/**
* Verify access rules for comment indexing with different permissions.
*/
public function testSearchResultsCommentAccess() {
$comment_body = 'Test comment body';
$this->commentSubject = 'Test comment subject';
$roles = $this->adminUser->getRoles(TRUE);
$this->adminRole = $roles[0];
// Create a node.
// Make preview optional.
$field = FieldConfig::loadByName('node', 'article', 'comment');
$field->setSetting('preview', DRUPAL_OPTIONAL);
$field->save();
$this->node = $this->drupalCreateNode(['type' => 'article']);
// Post a comment using 'Full HTML' text format.
$edit_comment = [];
$edit_comment['subject[0][value]'] = $this->commentSubject;
$edit_comment['comment_body[0][value]'] = '<h1>' . $comment_body . '</h1>';
$this->drupalPostForm('comment/reply/node/' . $this->node->id() . '/comment', $edit_comment, t('Save'));
$this->drupalLogout();
$this->setRolePermissions(RoleInterface::ANONYMOUS_ID);
$this->assertCommentAccess(FALSE, 'Anon user has search permission but no access comments permission, comments should not be indexed');
$this->setRolePermissions(RoleInterface::ANONYMOUS_ID, TRUE);
$this->assertCommentAccess(TRUE, 'Anon user has search permission and access comments permission, comments should be indexed');
$this->drupalLogin($this->adminUser);
$this->drupalGet('admin/people/permissions');
// Disable search access for authenticated user to test admin user.
$this->setRolePermissions(RoleInterface::AUTHENTICATED_ID, FALSE, FALSE);
$this->setRolePermissions($this->adminRole);
$this->assertCommentAccess(FALSE, 'Admin user has search permission but no access comments permission, comments should not be indexed');
$this->drupalGet('node/' . $this->node->id());
$this->setRolePermissions($this->adminRole, TRUE);
$this->assertCommentAccess(TRUE, 'Admin user has search permission and access comments permission, comments should be indexed');
$this->setRolePermissions(RoleInterface::AUTHENTICATED_ID);
$this->assertCommentAccess(FALSE, 'Authenticated user has search permission but no access comments permission, comments should not be indexed');
$this->setRolePermissions(RoleInterface::AUTHENTICATED_ID, TRUE);
$this->assertCommentAccess(TRUE, 'Authenticated user has search permission and access comments permission, comments should be indexed');
// Verify that access comments permission is inherited from the
// authenticated role.
$this->setRolePermissions(RoleInterface::AUTHENTICATED_ID, TRUE, FALSE);
$this->setRolePermissions($this->adminRole);
$this->assertCommentAccess(TRUE, 'Admin user has search permission and no access comments permission, but comments should be indexed because admin user inherits authenticated user\'s permission to access comments');
// Verify that search content permission is inherited from the authenticated
// role.
$this->setRolePermissions(RoleInterface::AUTHENTICATED_ID, TRUE, TRUE);
$this->setRolePermissions($this->adminRole, TRUE, FALSE);
$this->assertCommentAccess(TRUE, 'Admin user has access comments permission and no search permission, but comments should be indexed because admin user inherits authenticated user\'s permission to search');
}
/**
* Set permissions for role.
*/
public function setRolePermissions($rid, $access_comments = FALSE, $search_content = TRUE) {
$permissions = [
'access comments' => $access_comments,
'search content' => $search_content,
];
user_role_change_permissions($rid, $permissions);
}
/**
* Update search index and search for comment.
*/
public function assertCommentAccess($assume_access, $message) {
// Invoke search index update.
search_mark_for_reindex('node_search', $this->node->id());
$this->cronRun();
// Search for the comment subject.
$edit = [
'keys' => "'" . $this->commentSubject . "'",
];
$this->drupalPostForm('search/node', $edit, t('Search'));
try {
if ($assume_access) {
$this->assertSession()->pageTextContains($this->node->label());
$this->assertSession()->pageTextContains($this->commentSubject);
}
else {
$this->assertSession()->pageTextContains(t('Your search yielded no results.'));
}
}
catch (ResponseTextException $exception) {
$this->fail($message);
}
}
/**
* Verify that 'add new comment' does not appear in search results or index.
*/
public function testAddNewComment() {
// Create a node with a short body.
$settings = [
'type' => 'article',
'title' => 'short title',
'body' => [['value' => 'short body text']],
];
$user = $this->drupalCreateUser([
'search content',
'create article content',
'access content',
'post comments',
'access comments',
]);
$this->drupalLogin($user);
$node = $this->drupalCreateNode($settings);
// Verify that if you view the node on its own page, 'add new comment'
// is there.
$this->drupalGet('node/' . $node->id());
$this->assertText(t('Add new comment'));
// Run cron to index this page.
$this->drupalLogout();
$this->cronRun();
// Search for 'comment'. Should be no results.
$this->drupalLogin($user);
$this->drupalPostForm('search/node', ['keys' => 'comment'], t('Search'));
$this->assertText(t('Your search yielded no results'));
// Search for the node title. Should be found, and 'Add new comment' should
// not be part of the search snippet.
$this->drupalPostForm('search/node', ['keys' => 'short'], t('Search'));
$this->assertText($node->label(), 'Search for keyword worked');
$this->assertNoText(t('Add new comment'));
}
}

View file

@ -0,0 +1,405 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Core\Url;
use Drupal\search\Entity\SearchPage;
use Drupal\Tests\BrowserTestBase;
/**
* Verify the search config settings form.
*
* @group search
*/
class SearchConfigSettingsFormTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['block', 'dblog', 'node', 'search', 'search_extra_type', 'test_page_test'];
/**
* User who can search and administer search.
*
* @var \Drupal\user\UserInterface
*/
protected $searchUser;
/**
* Node indexed for searching.
*
* @var \Drupal\node\NodeInterface
*/
protected $searchNode;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Log in as a user that can create and search content.
$this->searchUser = $this->drupalCreateUser(['search content', 'administer search', 'administer nodes', 'bypass node access', 'access user profiles', 'administer users', 'administer blocks', 'access site reports']);
$this->drupalLogin($this->searchUser);
// Add a single piece of content and index it.
$node = $this->drupalCreateNode();
$this->searchNode = $node;
// Link the node to itself to test that it's only indexed once. The content
// also needs the word "pizza" so we can use it as the search keyword.
$body_key = 'body[0][value]';
$edit[$body_key] = \Drupal::l($node->label(), $node->urlInfo()) . ' pizza sandwich';
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
// Enable the search block.
$this->drupalPlaceBlock('search_form_block');
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
}
/**
* Verifies the search settings form.
*/
public function testSearchSettingsPage() {
// Test that the settings form displays the correct count of items left to index.
$this->drupalGet('admin/config/search/pages');
$this->assertText(t('There are @count items left to index.', ['@count' => 0]));
// Test the re-index button.
$this->drupalPostForm('admin/config/search/pages', [], t('Re-index site'));
$this->assertText(t('Are you sure you want to re-index the site'));
$this->drupalPostForm('admin/config/search/pages/reindex', [], t('Re-index site'));
$this->assertText(t('All search indexes will be rebuilt'));
$this->drupalGet('admin/config/search/pages');
$this->assertText(t('There is 1 item left to index.'));
// Test that the form saves with the default values.
$this->drupalPostForm('admin/config/search/pages', [], t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Form saves with the default values.');
// Test that the form does not save with an invalid word length.
$edit = [
'minimum_word_size' => $this->randomMachineName(3),
];
$this->drupalPostForm('admin/config/search/pages', $edit, t('Save configuration'));
$this->assertNoText(t('The configuration options have been saved.'), 'Form does not save with an invalid word length.');
// Test logging setting. It should be off by default.
$text = $this->randomMachineName(5);
$this->drupalPostForm('search/node', ['keys' => $text], t('Search'));
$this->drupalGet('admin/reports/dblog');
$this->assertNoLink('Searched Content for ' . $text . '.', 'Search was not logged');
// Turn on logging.
$edit = ['logging' => TRUE];
$this->drupalPostForm('admin/config/search/pages', $edit, t('Save configuration'));
$text = $this->randomMachineName(5);
$this->drupalPostForm('search/node', ['keys' => $text], t('Search'));
$this->drupalGet('admin/reports/dblog');
$this->assertLink('Searched Content for ' . $text . '.', 0, 'Search was logged');
}
/**
* Verifies plugin-supplied settings form.
*/
public function testSearchModuleSettingsPage() {
$this->drupalGet('admin/config/search/pages');
$this->clickLink(t('Edit'), 1);
// Ensure that the default setting was picked up from the default config
$this->assertTrue($this->xpath('//select[@id="edit-extra-type-settings-boost"]//option[@value="bi" and @selected="selected"]'), 'Module specific settings are picked up from the default config');
// Change extra type setting and also modify a common search setting.
$edit = [
'extra_type_settings[boost]' => 'ii',
];
$this->drupalPostForm(NULL, $edit, t('Save search page'));
// Ensure that the modifications took effect.
$this->assertRaw(t('The %label search page has been updated.', ['%label' => 'Dummy search type']));
$this->drupalGet('admin/config/search/pages/manage/dummy_search_type');
$this->assertTrue($this->xpath('//select[@id="edit-extra-type-settings-boost"]//option[@value="ii" and @selected="selected"]'), 'Module specific settings can be changed');
}
/**
* Verifies that you can disable individual search plugins.
*/
public function testSearchModuleDisabling() {
// Array of search plugins to test: 'keys' are the keywords to search for,
// and 'text' is the text to assert is on the results page.
$plugin_info = [
'node_search' => [
'keys' => 'pizza',
'text' => $this->searchNode->label(),
],
'user_search' => [
'keys' => $this->searchUser->getUsername(),
'text' => $this->searchUser->getEmail(),
],
'dummy_search_type' => [
'keys' => 'foo',
'text' => 'Dummy search snippet to display',
],
];
$plugins = array_keys($plugin_info);
/** @var $entities \Drupal\search\SearchPageInterface[] */
$entities = SearchPage::loadMultiple();
// Disable all of the search pages.
foreach ($entities as $entity) {
$entity->disable()->save();
}
// Test each plugin if it's enabled as the only search plugin.
foreach ($entities as $entity_id => $entity) {
$this->setDefaultThroughUi($entity_id);
// Run a search from the correct search URL.
$info = $plugin_info[$entity_id];
$this->drupalGet('search/' . $entity->getPath(), ['query' => ['keys' => $info['keys']]]);
$this->assertResponse(200);
$this->assertNoText('no results', $entity->label() . ' search found results');
$this->assertText($info['text'], 'Correct search text found');
// Verify that other plugin search tab labels are not visible.
foreach ($plugins as $other) {
if ($other != $entity_id) {
$label = $entities[$other]->label();
$this->assertNoText($label, $label . ' search tab is not shown');
}
}
// Run a search from the search block on the node page. Verify you get
// to this plugin's search results page.
$terms = ['keys' => $info['keys']];
$this->drupalPostForm('node', $terms, t('Search'));
$current = $this->getURL();
$expected = \Drupal::url('search.view_' . $entity->id(), [], ['query' => ['keys' => $info['keys']], 'absolute' => TRUE]);
$this->assertEqual($current, $expected, 'Block redirected to right search page');
// Try an invalid search path, which should 404.
$this->drupalGet('search/not_a_plugin_path');
$this->assertResponse(404);
$entity->disable()->save();
}
// Set the node search as default.
$this->setDefaultThroughUi('node_search');
// Test with all search plugins enabled. When you go to the search
// page or run search, all plugins should be shown.
foreach ($entities as $entity) {
$entity->enable()->save();
}
\Drupal::service('router.builder')->rebuild();
$paths = [
['path' => 'search/node', 'options' => ['query' => ['keys' => 'pizza']]],
['path' => 'search/node', 'options' => []],
];
foreach ($paths as $item) {
$this->drupalGet($item['path'], $item['options']);
foreach ($plugins as $entity_id) {
$label = $entities[$entity_id]->label();
$this->assertText($label, format_string('%label search tab is shown', ['%label' => $label]));
}
}
}
/**
* Tests the ordering of search pages on a clean install.
*/
public function testDefaultSearchPageOrdering() {
$this->drupalGet('search');
$elements = $this->xpath('//*[contains(@class, :class)]//a', [':class' => 'tabs primary']);
$this->assertIdentical($elements[0]->getAttribute('href'), \Drupal::url('search.view_node_search'));
$this->assertIdentical($elements[1]->getAttribute('href'), \Drupal::url('search.view_dummy_search_type'));
$this->assertIdentical($elements[2]->getAttribute('href'), \Drupal::url('search.view_user_search'));
}
/**
* Tests multiple search pages of the same type.
*/
public function testMultipleSearchPages() {
$this->assertDefaultSearch('node_search', 'The default page is set to the installer default.');
$search_storage = \Drupal::entityManager()->getStorage('search_page');
$entities = $search_storage->loadMultiple();
$search_storage->delete($entities);
$this->assertDefaultSearch(FALSE);
// Ensure that no search pages are configured.
$this->drupalGet('admin/config/search/pages');
$this->assertText(t('No search pages have been configured.'));
// Add a search page.
$edit = [];
$edit['search_type'] = 'search_extra_type_search';
$this->drupalPostForm(NULL, $edit, t('Add search page'));
$this->assertTitle('Add new search page | Drupal');
$first = [];
$first['label'] = $this->randomString();
$first_id = $first['id'] = strtolower($this->randomMachineName(8));
$first['path'] = strtolower($this->randomMachineName(8));
$this->drupalPostForm(NULL, $first, t('Save'));
$this->assertDefaultSearch($first_id, 'The default page matches the only search page.');
$this->assertRaw(t('The %label search page has been added.', ['%label' => $first['label']]));
// Attempt to add a search page with an existing path.
$edit = [];
$edit['search_type'] = 'search_extra_type_search';
$this->drupalPostForm(NULL, $edit, t('Add search page'));
$edit = [];
$edit['label'] = $this->randomString();
$edit['id'] = strtolower($this->randomMachineName(8));
$edit['path'] = $first['path'];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertText(t('The search page path must be unique.'));
// Add a second search page.
$second = [];
$second['label'] = $this->randomString();
$second_id = $second['id'] = strtolower($this->randomMachineName(8));
$second['path'] = strtolower($this->randomMachineName(8));
$this->drupalPostForm(NULL, $second, t('Save'));
$this->assertDefaultSearch($first_id, 'The default page matches the only search page.');
// Ensure both search pages have their tabs displayed.
$this->drupalGet('search');
$elements = $this->xpath('//*[contains(@class, :class)]//a', [':class' => 'tabs primary']);
$this->assertIdentical($elements[0]->getAttribute('href'), Url::fromRoute('search.view_' . $first_id)->toString());
$this->assertIdentical($elements[1]->getAttribute('href'), Url::fromRoute('search.view_' . $second_id)->toString());
// Switch the weight of the search pages and check the order of the tabs.
$edit = [
'entities[' . $first_id . '][weight]' => 10,
'entities[' . $second_id . '][weight]' => -10,
];
$this->drupalPostForm('admin/config/search/pages', $edit, t('Save configuration'));
$this->drupalGet('search');
$elements = $this->xpath('//*[contains(@class, :class)]//a', [':class' => 'tabs primary']);
$this->assertIdentical($elements[0]->getAttribute('href'), Url::fromRoute('search.view_' . $second_id)->toString());
$this->assertIdentical($elements[1]->getAttribute('href'), Url::fromRoute('search.view_' . $first_id)->toString());
// Check the initial state of the search pages.
$this->drupalGet('admin/config/search/pages');
$this->verifySearchPageOperations($first_id, TRUE, FALSE, FALSE, FALSE);
$this->verifySearchPageOperations($second_id, TRUE, TRUE, TRUE, FALSE);
// Change the default search page.
$this->clickLink(t('Set as default'));
$this->assertRaw(t('The default search page is now %label. Be sure to check the ordering of your search pages.', ['%label' => $second['label']]));
$this->verifySearchPageOperations($first_id, TRUE, TRUE, TRUE, FALSE);
$this->verifySearchPageOperations($second_id, TRUE, FALSE, FALSE, FALSE);
// Disable the first search page.
$this->clickLink(t('Disable'));
$this->assertResponse(200);
$this->assertNoLink(t('Disable'));
$this->verifySearchPageOperations($first_id, TRUE, TRUE, FALSE, TRUE);
$this->verifySearchPageOperations($second_id, TRUE, FALSE, FALSE, FALSE);
// Enable the first search page.
$this->clickLink(t('Enable'));
$this->assertResponse(200);
$this->verifySearchPageOperations($first_id, TRUE, TRUE, TRUE, FALSE);
$this->verifySearchPageOperations($second_id, TRUE, FALSE, FALSE, FALSE);
// Test deleting.
$this->clickLink(t('Delete'));
$this->assertRaw(t('Are you sure you want to delete the search page %label?', ['%label' => $first['label']]));
$this->drupalPostForm(NULL, [], t('Delete'));
$this->assertRaw(t('The search page %label has been deleted.', ['%label' => $first['label']]));
$this->verifySearchPageOperations($first_id, FALSE, FALSE, FALSE, FALSE);
}
/**
* Tests that the enable/disable/default routes are protected from CSRF.
*/
public function testRouteProtection() {
// Ensure that the enable and disable routes are protected.
$this->drupalGet('admin/config/search/pages/manage/node_search/enable');
$this->assertResponse(403);
$this->drupalGet('admin/config/search/pages/manage/node_search/disable');
$this->assertResponse(403);
$this->drupalGet('admin/config/search/pages/manage/node_search/set-default');
$this->assertResponse(403);
}
/**
* Checks that the search page operations match expectations.
*
* @param string $id
* The search page ID to check.
* @param bool $edit
* Whether the edit link is expected.
* @param bool $delete
* Whether the delete link is expected.
* @param bool $disable
* Whether the disable link is expected.
* @param bool $enable
* Whether the enable link is expected.
*/
protected function verifySearchPageOperations($id, $edit, $delete, $disable, $enable) {
if ($edit) {
$this->assertLinkByHref("admin/config/search/pages/manage/$id");
}
else {
$this->assertNoLinkByHref("admin/config/search/pages/manage/$id");
}
if ($delete) {
$this->assertLinkByHref("admin/config/search/pages/manage/$id/delete");
}
else {
$this->assertNoLinkByHref("admin/config/search/pages/manage/$id/delete");
}
if ($disable) {
$this->assertLinkByHref("admin/config/search/pages/manage/$id/disable");
}
else {
$this->assertNoLinkByHref("admin/config/search/pages/manage/$id/disable");
}
if ($enable) {
$this->assertLinkByHref("admin/config/search/pages/manage/$id/enable");
}
else {
$this->assertNoLinkByHref("admin/config/search/pages/manage/$id/enable");
}
}
/**
* Checks that the default search page matches expectations.
*
* @param string $expected
* The expected search page.
* @param string $message
* (optional) A message to display with the assertion.
* @param string $group
* (optional) The group this message is in.
*/
protected function assertDefaultSearch($expected, $message = '', $group = 'Other') {
/** @var $search_page_repository \Drupal\search\SearchPageRepositoryInterface */
$search_page_repository = \Drupal::service('search.search_page_repository');
$this->assertIdentical($search_page_repository->getDefaultSearchPage(), $expected, $message, $group);
}
/**
* Sets a search page as the default in the UI.
*
* @param string $entity_id
* The search page entity ID to enable.
*/
protected function setDefaultThroughUi($entity_id) {
$this->drupalGet('admin/config/search/pages');
preg_match('|href="([^"]+' . $entity_id . '/set-default[^"]+)"|', $this->getSession()->getPage()->getContent(), $matches);
$this->drupalGet($this->getAbsoluteUrl($matches[1]));
}
}

View file

@ -3,24 +3,25 @@
namespace Drupal\Tests\search\Functional;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
/**
* Tests searching with date filters that exclude some translations.
*
* @group search
*/
class SearchDateIntervalTest extends SearchTestBase {
class SearchDateIntervalTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var string[]
* {@inheritdoc}
*/
public static $modules = ['language', 'search_date_query_alter'];
protected static $modules = ['language', 'search_date_query_alter', 'node', 'search'];
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create and log in user.
$test_user = $this->drupalCreateUser(['access content', 'search content', 'use advanced search', 'administer nodes', 'administer languages', 'access administration pages', 'administer site configuration']);
$this->drupalLogin($test_user);

View file

@ -0,0 +1,87 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Verifies that a form embedded in search results works.
*
* @group search
*/
class SearchEmbedFormTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search', 'search_embedded_form'];
/**
* Node used for testing.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
/**
* Count of how many times the form has been submitted.
*
* @var int
*/
protected $submitCount = 0;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create a user and a node, and update the search index.
$test_user = $this->drupalCreateUser(['access content', 'search content', 'administer nodes']);
$this->drupalLogin($test_user);
$this->node = $this->drupalCreateNode();
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
// Set up a dummy initial count of times the form has been submitted.
$this->submitCount = \Drupal::state()->get('search_embedded_form.submit_count');
$this->refreshVariables();
}
/**
* Tests that the embedded form appears and can be submitted.
*/
public function testEmbeddedForm() {
// First verify we can submit the form from the module's page.
$this->drupalPostForm('search_embedded_form',
['name' => 'John'],
t('Send away'));
$this->assertText(t('Test form was submitted'), 'Form message appears');
$count = \Drupal::state()->get('search_embedded_form.submit_count');
$this->assertEqual($this->submitCount + 1, $count, 'Form submission count is correct');
$this->submitCount = $count;
// Now verify that we can see and submit the form from the search results.
$this->drupalGet('search/node', ['query' => ['keys' => $this->node->label()]]);
$this->assertText(t('Your name'), 'Form is visible');
$this->drupalPostForm(NULL,
['name' => 'John'],
t('Send away'));
$this->assertText(t('Test form was submitted'), 'Form message appears');
$count = \Drupal::state()->get('search_embedded_form.submit_count');
$this->assertEqual($this->submitCount + 1, $count, 'Form submission count is correct');
$this->submitCount = $count;
// Now verify that if we submit the search form, it doesn't count as
// our form being submitted.
$this->drupalPostForm('search',
['keys' => 'foo'],
t('Search'));
$this->assertNoText(t('Test form was submitted'), 'Form message does not appear');
$count = \Drupal::state()->get('search_embedded_form.submit_count');
$this->assertEqual($this->submitCount, $count, 'Form submission count is correct');
$this->submitCount = $count;
}
}

View file

@ -2,16 +2,26 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that searching for a phrase gets the correct page count.
*
* @group search
*/
class SearchExactTest extends SearchTestBase {
class SearchExactTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search'];
/**
* Tests that the correct number of pager links are found for both keywords and phrases.
*/
public function testExactQuery() {
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Log in with sufficient privileges.
$user = $this->drupalCreateUser(['create page content', 'search content']);
$this->drupalLogin($user);

View file

@ -3,6 +3,7 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Component\Utility\Html;
use Drupal\Tests\BrowserTestBase;
/**
* Verify the search without keywords set and extra conditions.
@ -13,14 +14,12 @@ use Drupal\Component\Utility\Html;
*
* @group search
*/
class SearchKeywordsConditionsTest extends SearchTestBase {
class SearchKeywordsConditionsTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
* {@inheritdoc}
*/
public static $modules = ['comment', 'search_extra_type', 'test_page_test'];
protected static $modules = ['comment', 'search', 'search_extra_type', 'test_page_test'];
/**
* A user with permission to search and post comments.

View file

@ -0,0 +1,138 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
/**
* Tests advanced search with different languages added.
*
* @group search
*/
class SearchLanguageTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['language', 'node', 'search'];
/**
* Array of nodes available to search.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $searchableNodes;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create and log in user.
$test_user = $this->drupalCreateUser(['access content', 'search content', 'use advanced search', 'administer nodes', 'administer languages', 'access administration pages', 'administer site configuration']);
$this->drupalLogin($test_user);
// Add a new language.
ConfigurableLanguage::createFromLangcode('es')->save();
// Make the body field translatable. The title is already translatable by
// definition. The parent class has already created the article and page
// content types.
$field_storage = FieldStorageConfig::loadByName('node', 'body');
$field_storage->setTranslatable(TRUE);
$field_storage->save();
// Create a few page nodes with multilingual body values.
$default_format = filter_default_format();
$nodes = [
[
'title' => 'First node en',
'type' => 'page',
'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
'langcode' => 'en',
],
[
'title' => 'Second node this is the Spanish title',
'type' => 'page',
'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
'langcode' => 'es',
],
[
'title' => 'Third node en',
'type' => 'page',
'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
'langcode' => 'en',
],
];
$this->searchableNodes = [];
foreach ($nodes as $setting) {
$this->searchableNodes[] = $this->drupalCreateNode($setting);
}
// Add English translation to the second node.
$translation = $this->searchableNodes[1]->addTranslation('en', ['title' => 'Second node en']);
$translation->body->value = $this->randomMachineName(32);
$this->searchableNodes[1]->save();
// Add Spanish translation to the third node.
$translation = $this->searchableNodes[2]->addTranslation('es', ['title' => 'Third node es']);
$translation->body->value = $this->randomMachineName(32);
$this->searchableNodes[2]->save();
// Update the index and then run the shutdown method.
$plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
$plugin->updateIndex();
search_update_totals();
}
public function testLanguages() {
// Add predefined language.
$edit = ['predefined_langcode' => 'fr'];
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
$this->assertText('French', 'Language added successfully.');
// Now we should have languages displayed.
$this->drupalGet('search/node');
$this->assertText(t('Languages'), 'Languages displayed to choose from.');
$this->assertText(t('English'), 'English is a possible choice.');
$this->assertText(t('French'), 'French is a possible choice.');
// Ensure selecting no language does not make the query different.
$this->drupalPostForm('search/node', [], 'edit-submit--2');
$this->assertUrl(\Drupal::url('search.view_node_search', [], ['query' => ['keys' => ''], 'absolute' => TRUE]), [], 'Correct page redirection, no language filtering.');
// Pick French and ensure it is selected.
$edit = ['language[fr]' => TRUE];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Get the redirected URL.
$url = $this->getUrl();
$parts = parse_url($url);
$query_string = isset($parts['query']) ? rawurldecode($parts['query']) : '';
$this->assertTrue(strpos($query_string, '=language:fr') !== FALSE, 'Language filter language:fr add to the query string.');
// Search for keyword node and language filter as Spanish.
$edit = ['keys' => 'node', 'language[es]' => TRUE];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Check for Spanish results.
$this->assertLink('Second node this is the Spanish title', 0, 'Second node Spanish title found in search results');
$this->assertLink('Third node es', 0, 'Third node Spanish found in search results');
// Ensure that results don't contain other language nodes.
$this->assertNoLink('First node en', 'Search results do not contain first English node');
$this->assertNoLink('Second node en', 'Search results do not contain second English node');
$this->assertNoLink('Third node en', 'Search results do not contain third English node');
// Change the default language and delete English.
$path = 'admin/config/regional/language';
$this->drupalGet($path);
$this->assertFieldChecked('edit-site-default-language-en', 'Default language updated.');
$edit = [
'site_default_language' => 'fr',
];
$this->drupalPostForm($path, $edit, t('Save configuration'));
$this->assertNoFieldChecked('edit-site-default-language-en', 'Default language updated.');
$this->drupalPostForm('admin/config/regional/language/delete/en', [], t('Delete'));
}
}

View file

@ -4,13 +4,14 @@ namespace Drupal\Tests\search\Functional;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
/**
* Tests entities with multilingual fields.
*
* @group search
*/
class SearchMultilingualEntityTest extends SearchTestBase {
class SearchMultilingualEntityTest extends BrowserTestBase {
/**
* List of searchable nodes.
@ -26,11 +27,16 @@ class SearchMultilingualEntityTest extends SearchTestBase {
*/
protected $plugin;
public static $modules = ['language', 'locale', 'comment'];
/**
* {@inheritdoc}
*/
protected static $modules = ['language', 'locale', 'comment', 'node', 'search'];
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create a user who can administer search, do searches, see the status
// report, and administer cron. Log in.
$user = $this->drupalCreateUser(['administer search', 'search content', 'use advanced search', 'access content', 'access site reports', 'administer site configuration']);
@ -78,16 +84,11 @@ class SearchMultilingualEntityTest extends SearchTestBase {
// After the third node, we don't care what the settings are. But we
// need to have at least 5 to make sure the throttling is working
// correctly. So, let's make 8 total.
[
],
[
],
[
],
[
],
[
],
[],
[],
[],
[],
[],
];
$this->searchableNodes = [];
foreach ($nodes as $setting) {

View file

@ -2,12 +2,19 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests search functionality with diacritics.
*
* @group search
*/
class SearchNodeDiacriticsTest extends SearchTestBase {
class SearchNodeDiacriticsTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search'];
/**
* A user with permission to use advanced search.
@ -18,6 +25,9 @@ class SearchNodeDiacriticsTest extends SearchTestBase {
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
node_access_rebuild();
// Create a test user and log in.

View file

@ -2,12 +2,19 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests search functionality with punctuation and HTML entities.
*
* @group search
*/
class SearchNodePunctuationTest extends SearchTestBase {
class SearchNodePunctuationTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search'];
/**
* A user with permission to use advanced search.
@ -18,8 +25,10 @@ class SearchNodePunctuationTest extends SearchTestBase {
protected function setUp() {
parent::setUp();
node_access_rebuild();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
node_access_rebuild();
// Create a test user and log in.
$this->testUser = $this->drupalCreateUser(['access content', 'search content', 'use advanced search', 'access user profiles']);
$this->drupalLogin($this->testUser);

View file

@ -0,0 +1,110 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests search index is updated properly when nodes are removed or updated.
*
* @group search
*/
class SearchNodeUpdateAndDeletionTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search'];
/**
* A user with permission to access and search content.
*
* @var \Drupal\user\UserInterface
*/
public $testUser;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create a test user and log in.
$this->testUser = $this->drupalCreateUser(['access content', 'search content']);
$this->drupalLogin($this->testUser);
}
/**
* Tests that the search index info is properly updated when a node changes.
*/
public function testSearchIndexUpdateOnNodeChange() {
// Create a node.
$node = $this->drupalCreateNode([
'title' => 'Someone who says Ni!',
'body' => [['value' => "We are the knights who say Ni!"]],
'type' => 'page',
]);
$node_search_plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
// Update the search index.
$node_search_plugin->updateIndex();
search_update_totals();
// Search the node to verify it appears in search results
$edit = ['keys' => 'knights'];
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText($node->label());
// Update the node
$node->body->value = "We want a shrubbery!";
$node->save();
// Run indexer again
$node_search_plugin->updateIndex();
search_update_totals();
// Search again to verify the new text appears in test results.
$edit = ['keys' => 'shrubbery'];
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText($node->label());
}
/**
* Tests that the search index info is updated when a node is deleted.
*/
public function testSearchIndexUpdateOnNodeDeletion() {
// Create a node.
$node = $this->drupalCreateNode([
'title' => 'No dragons here',
'body' => [['value' => 'Again: No dragons here']],
'type' => 'page',
]);
$node_search_plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
// Update the search index.
$node_search_plugin->updateIndex();
search_update_totals();
// Search the node to verify it appears in search results
$edit = ['keys' => 'dragons'];
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText($node->label());
// Get the node info from the search index tables.
$search_index_dataset = db_query("SELECT sid FROM {search_index} WHERE type = 'node_search' AND word = :word", [':word' => 'dragons'])
->fetchField();
$this->assertNotEqual($search_index_dataset, FALSE, t('Node info found on the search_index'));
// Delete the node.
$node->delete();
// Check if the node info is gone from the search table.
$search_index_dataset = db_query("SELECT sid FROM {search_index} WHERE type = 'node_search' AND word = :word", [':word' => 'dragons'])
->fetchField();
$this->assertFalse($search_index_dataset, t('Node info successfully removed from search_index'));
// Search again to verify the node doesn't appear anymore.
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertNoText($node->label());
}
}

View file

@ -0,0 +1,111 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
/**
* Tests that numbers can be searched with more complex matching.
*
* @group search
*/
class SearchNumberMatchingTest extends BrowserTestBase {
use CronRunTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['dblog', 'node', 'search'];
/**
* A user with permission to administer nodes.
*
* @var \Drupal\user\UserInterface
*/
protected $testUser;
/**
* An array of strings containing numbers to use for testing.
*
* Define a group of numbers that should all match each other --
* numbers with internal punctuation should match each other, as well
* as numbers with and without leading zeros and leading/trailing
* . and -.
*
* @var string[]
*/
protected $numbers = [
'123456789',
'12/34/56789',
'12.3456789',
'12-34-56789',
'123,456,789',
'-123456789',
'0123456789',
];
/**
* An array of nodes created for testing purposes.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->testUser = $this->drupalCreateUser(['search content', 'access content', 'administer nodes', 'access site reports']);
$this->drupalLogin($this->testUser);
foreach ($this->numbers as $num) {
$info = [
'body' => [['value' => $num]],
'type' => 'page',
'language' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$this->nodes[] = $this->drupalCreateNode($info);
}
// Run cron to ensure the content is indexed.
$this->cronRun();
$this->drupalGet('admin/reports/dblog');
$this->assertText(t('Cron run completed'), 'Log shows cron run completed');
}
/**
* Tests that all the numbers can be searched.
*/
public function testNumberSearching() {
for ($i = 0; $i < count($this->numbers); $i++) {
$node = $this->nodes[$i];
// Verify that the node title does not appear on the search page
// with a dummy search.
$this->drupalPostForm('search/node',
['keys' => 'foo'],
t('Search'));
$this->assertNoText($node->label(), format_string('%number: node title not shown in dummy search', ['%number' => $i]));
// Now verify that we can find node i by searching for any of the
// numbers.
for ($j = 0; $j < count($this->numbers); $j++) {
$number = $this->numbers[$j];
// If the number is negative, remove the - sign, because - indicates
// "not keyword" when searching.
$number = ltrim($number, '-');
$this->drupalPostForm('search/node',
['keys' => $number],
t('Search'));
$this->assertText($node->label(), format_string('%i: node title shown (search found the node) in search for number %number', ['%i' => $i, '%number' => $number]));
}
}
}
}

View file

@ -0,0 +1,116 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
/**
* Tests that numbers can be searched.
*
* @group search
*/
class SearchNumbersTest extends BrowserTestBase {
use CronRunTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['dblog', 'node', 'search'];
/**
* A user with permission to administer nodes.
*
* @var \Drupal\user\UserInterface
*/
protected $testUser;
/**
* An array containing a series of "numbers" for testing purposes.
*
* Create content with various numbers in it.
* Note: 50 characters is the current limit of the search index's word
* field.
*
* @var string[]
*/
protected $numbers = [
'ISBN' => '978-0446365383',
'UPC' => '036000 291452',
'EAN bar code' => '5901234123457',
'negative' => '-123456.7890',
'quoted negative' => '"-123456.7890"',
'leading zero' => '0777777777',
'tiny' => '111',
'small' => '22222222222222',
'medium' => '333333333333333333333333333',
'large' => '444444444444444444444444444444444444444',
'gigantic' => '5555555555555555555555555555555555555555555555555',
'over fifty characters' => '666666666666666666666666666666666666666666666666666666666666',
'date' => '01/02/2009',
'commas' => '987,654,321',
];
/**
* An array of nodes created for testing purposes.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->testUser = $this->drupalCreateUser(['search content', 'access content', 'administer nodes', 'access site reports']);
$this->drupalLogin($this->testUser);
foreach ($this->numbers as $doc => $num) {
$info = [
'body' => [['value' => $num]],
'type' => 'page',
'language' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
'title' => $doc . ' number',
];
$this->nodes[$doc] = $this->drupalCreateNode($info);
}
// Run cron to ensure the content is indexed.
$this->cronRun();
$this->drupalGet('admin/reports/dblog');
$this->assertText(t('Cron run completed'), 'Log shows cron run completed');
}
/**
* Tests that all the numbers can be searched.
*/
public function testNumberSearching() {
$types = array_keys($this->numbers);
foreach ($types as $type) {
$number = $this->numbers[$type];
// If the number is negative, remove the - sign, because - indicates
// "not keyword" when searching.
$number = ltrim($number, '-');
$node = $this->nodes[$type];
// Verify that the node title does not appear on the search page
// with a dummy search.
$this->drupalPostForm('search/node',
['keys' => 'foo'],
t('Search'));
$this->assertNoText($node->label(), $type . ': node title not shown in dummy search');
// Verify that the node title does appear as a link on the search page
// when searching for the number.
$this->drupalPostForm('search/node',
['keys' => $number],
t('Search'));
$this->assertText($node->label(), format_string('%type: node title shown (search found the node) in search for number %number.', ['%type' => $type, '%number' => $number]));
}
}
}

View file

@ -0,0 +1,226 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Core\Cache\Cache;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests the search_page entity cache tags on the search results pages.
*
* @group search
*/
class SearchPageCacheTagsTest extends BrowserTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search'];
/**
* {@inheritdoc}
*/
protected $dumpHeaders = TRUE;
/**
* A user with permission to search content.
*
* @var \Drupal\user\UserInterface
*/
protected $searchingUser;
/**
* A node that is indexed by the search module.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create user.
$this->searchingUser = $this->drupalCreateUser(['search content', 'access user profiles']);
// Create a node and update the search index.
$this->node = $this->drupalCreateNode(['title' => 'bike shed shop']);
$this->node->setOwner($this->searchingUser);
$this->node->save();
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
}
/**
* Tests the presence of the expected cache tag in various situations.
*/
public function testSearchText() {
$this->drupalLogin($this->searchingUser);
// Initial page for searching nodes.
$this->drupalGet('search/node');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index:node_search');
$this->assertCacheTag('node_list');
// Node search results.
$edit = [];
$edit['keys'] = 'bike shed';
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('bike shed shop');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
$this->assertCacheTag('node:1');
$this->assertCacheTag('user:2');
$this->assertCacheTag('rendered');
$this->assertCacheTag('http_response');
$this->assertCacheTag('node_list');
// Updating a node should invalidate the search plugin's index cache tag.
$this->node->title = 'bike shop';
$this->node->save();
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('bike shop');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
$this->assertCacheTag('node:1');
$this->assertCacheTag('user:2');
$this->assertCacheTag('rendered');
$this->assertCacheTag('http_response');
$this->assertCacheTag('node_list');
// Deleting a node should invalidate the search plugin's index cache tag.
$this->node->delete();
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('Your search yielded no results.');
$this->assertCacheTag('config:search.page.node_search');
$this->assertCacheTag('search_index');
$this->assertCacheTag('search_index:node_search');
$this->assertCacheTag('node_list');
// Initial page for searching users.
$this->drupalGet('search/user');
$this->assertCacheTag('config:search.page.user_search');
$this->assertCacheTag('user_list');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'search_index');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'search_index:user_search');
// User search results.
$edit['keys'] = $this->searchingUser->getUsername();
$this->drupalPostForm('search/user', $edit, t('Search'));
$this->assertCacheTag('config:search.page.user_search');
$this->assertCacheTag('user_list');
$this->assertCacheTag('user:2');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'search_index');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'search_index:user_search');
}
/**
* Tests the presence of expected cache tags with referenced entities.
*/
public function testSearchTagsBubbling() {
// Install field UI and entity reference modules.
$this->container->get('module_installer')->install(['field_ui', 'entity_reference']);
$this->resetAll();
// Creates a new content type that will have an entity reference.
$type_name = 'entity_reference_test';
$type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]);
$bundle_path = 'admin/structure/types/manage/' . $type->id();
// Create test user.
$admin_user = $this->drupalCreateUser([
'access content',
'create ' . $type_name . ' content',
'administer node fields',
'administer node display',
]);
$this->drupalLogin($admin_user);
// First step: 'Add new field' on the 'Manage fields' page.
$this->drupalGet($bundle_path . '/fields/add-field');
$this->drupalPostForm(NULL, [
'label' => 'Test label',
'field_name' => 'test__ref',
'new_storage_type' => 'entity_reference',
], t('Save and continue'));
// Second step: 'Field settings' form.
$this->drupalPostForm(NULL, [], t('Save field settings'));
// Create a new node of our newly created node type and fill in the entity
// reference field.
$edit = [
'title[0][value]' => 'Llama shop',
'field_test__ref[0][target_id]' => $this->node->getTitle(),
];
$this->drupalPostForm('node/add/' . $type->id(), $edit, t('Save'));
// Test that the value of the entity reference field is shown.
$this->drupalGet('node/2');
$this->assertText('bike shed shop');
// Refresh the search index.
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
// Log in with searching user again.
$this->drupalLogin($this->searchingUser);
// Default search cache tags.
$default_search_tags = [
'config:search.page.node_search',
'search_index',
'search_index:node_search',
'http_response',
'rendered',
'node_list',
];
// Node search results for shop, should return node:1 (bike shed shop) and
// node:2 (Llama shop). The related authors cache tags should be visible as
// well.
$edit = [];
$edit['keys'] = 'shop';
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('bike shed shop');
$this->assertText('Llama shop');
$expected_cache_tags = Cache::mergeTags($default_search_tags, [
'node:1',
'user:2',
'node:2',
'user:3',
'node_view',
'config:filter.format.plain_text',
]);
$this->assertCacheTags($expected_cache_tags);
// Only get the new node in the search results, should result in node:1,
// node:2 and user:3 as cache tags even though only node:1 is shown. This is
// because node:2 is reference in node:1 as an entity reference.
$edit = [];
$edit['keys'] = 'Llama';
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('Llama shop');
$expected_cache_tags = Cache::mergeTags($default_search_tags, [
'node:1',
'node:2',
'user:3',
'node_view',
]);
$this->assertCacheTags($expected_cache_tags);
}
}

View file

@ -2,6 +2,8 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests if the result page can be overridden.
*
@ -10,14 +12,12 @@ namespace Drupal\Tests\search\Functional;
*
* @group search
*/
class SearchPageOverrideTest extends SearchTestBase {
class SearchPageOverrideTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
* {@inheritdoc}
*/
public static $modules = ['search_extra_type'];
protected static $modules = ['search', 'search_extra_type'];
/**
* A user with permission to administer search.

View file

@ -0,0 +1,165 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the search help text and search page text.
*
* @group search
*/
class SearchPageTextTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['block', 'node', 'search'];
/**
* A user with permission to use advanced search.
*
* @var \Drupal\user\UserInterface
*/
protected $searchingUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create user.
$this->searchingUser = $this->drupalCreateUser(['search content', 'access user profiles', 'use advanced search']);
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
}
/**
* Tests for XSS in search module local task.
*
* This is a regression test for https://www.drupal.org/node/2338081
*/
public function testSearchLabelXSS() {
$this->drupalLogin($this->drupalCreateUser(['administer search']));
$keys['label'] = '<script>alert("Dont Panic");</script>';
$this->drupalPostForm('admin/config/search/pages/manage/node_search', $keys, t('Save search page'));
$this->drupalLogin($this->searchingUser);
$this->drupalGet('search/node');
$this->assertEscaped($keys['label']);
}
/**
* Tests the failed search text, and various other text on the search page.
*/
public function testSearchText() {
$this->drupalLogin($this->searchingUser);
$this->drupalGet('search/node');
$this->assertText(t('Enter your keywords'));
$this->assertText(t('Search'));
$this->assertTitle(t('Search') . ' | Drupal', 'Search page title is correct');
$edit = [];
$search_terms = 'bike shed ' . $this->randomMachineName();
$edit['keys'] = $search_terms;
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertText('search yielded no results');
$this->assertText(t('Search'));
$title_source = 'Search for @keywords | Drupal';
$this->assertTitle(t($title_source, ['@keywords' => Unicode::truncate($search_terms, 60, TRUE, TRUE)]), 'Search page title is correct');
$this->assertNoText('Node', 'Erroneous tab and breadcrumb text is not present');
$this->assertNoText(t('Node'), 'Erroneous translated tab and breadcrumb text is not present');
$this->assertText(t('Content'), 'Tab and breadcrumb text is present');
$this->clickLink('Search help');
$this->assertText('Search help', 'Correct title is on search help page');
$this->assertText('Use upper-case OR to get more results', 'Correct text is on content search help page');
// Search for a longer text, and see that it is in the title, truncated.
$edit = [];
$search_terms = 'Every word is like an unnecessary stain on silence and nothingness.';
$edit['keys'] = $search_terms;
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertTitle(t($title_source, ['@keywords' => 'Every word is like an unnecessary stain on silence and…']), 'Search page title is correct');
// Search for a string with a lot of special characters.
$search_terms = 'Hear nothing > "see nothing" `feel' . " '1982.";
$edit['keys'] = $search_terms;
$this->drupalPostForm('search/node', $edit, t('Search'));
$actual_title = $this->xpath('//title')[0]->getText();
$this->assertEqual($actual_title, Html::decodeEntities(t($title_source, ['@keywords' => Unicode::truncate($search_terms, 60, TRUE, TRUE)])), 'Search page title is correct');
$edit['keys'] = $this->searchingUser->getUsername();
$this->drupalPostForm('search/user', $edit, t('Search'));
$this->assertText(t('Search'));
$this->assertTitle(t($title_source, ['@keywords' => Unicode::truncate($this->searchingUser->getUsername(), 60, TRUE, TRUE)]));
$this->clickLink('Search help');
$this->assertText('Search help', 'Correct title is on search help page');
$this->assertText('user names and partial user names', 'Correct text is on user search help page');
// Test that search keywords containing slashes are correctly loaded
// from the GET params and displayed in the search form.
$arg = $this->randomMachineName() . '/' . $this->randomMachineName();
$this->drupalGet('search/node', ['query' => ['keys' => $arg]]);
$input = $this->xpath("//input[@id='edit-keys' and @value='{$arg}']");
$this->assertFalse(empty($input), 'Search keys with a / are correctly set as the default value in the search box.');
// Test a search input exceeding the limit of AND/OR combinations to test
// the Denial-of-Service protection.
$limit = $this->config('search.settings')->get('and_or_limit');
$keys = [];
for ($i = 0; $i < $limit + 1; $i++) {
// Use a key of 4 characters to ensure we never generate 'AND' or 'OR'.
$keys[] = $this->randomMachineName(4);
if ($i % 2 == 0) {
$keys[] = 'OR';
}
}
$edit['keys'] = implode(' ', $keys);
$this->drupalPostForm('search/node', $edit, t('Search'));
$this->assertRaw(t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', ['@count' => $limit]));
// Test that a search on Node or User with no keywords entered generates
// the "Please enter some keywords" message.
$this->drupalPostForm('search/node', [], t('Search'));
$this->assertText(t('Please enter some keywords'), 'With no keywords entered, message is displayed on node page');
$this->drupalPostForm('search/user', [], t('Search'));
$this->assertText(t('Please enter some keywords'), 'With no keywords entered, message is displayed on user page');
// Make sure the "Please enter some keywords" message is NOT displayed if
// you use "or" words or phrases in Advanced Search.
$this->drupalPostForm('search/node', ['or' => $this->randomMachineName() . ' ' . $this->randomMachineName()], 'edit-submit--2');
$this->assertNoText(t('Please enter some keywords'), 'With advanced OR keywords entered, no keywords message is not displayed on node page');
$this->drupalPostForm('search/node', ['phrase' => '"' . $this->randomMachineName() . '" "' . $this->randomMachineName() . '"'], 'edit-submit--2');
$this->assertNoText(t('Please enter some keywords'), 'With advanced phrase entered, no keywords message is not displayed on node page');
// Verify that if you search for a too-short keyword, you get the right
// message, and that if after that you search for a longer keyword, you
// do not still see the message.
$this->drupalPostForm('search/node', ['keys' => $this->randomMachineName(1)], t('Search'));
$this->assertText('You must include at least one keyword', 'Keyword message is displayed when searching for short word');
$this->assertNoText(t('Please enter some keywords'), 'With short word entered, no keywords message is not displayed');
$this->drupalPostForm(NULL, ['keys' => $this->randomMachineName()], t('Search'));
$this->assertNoText('You must include at least one keyword', 'Keyword message is not displayed when searching for long word after short word search');
// Test that if you search for a URL with .. in it, you still end up at
// the search page. See issue https://www.drupal.org/node/890058.
$this->drupalPostForm('search/node', ['keys' => '../../admin'], t('Search'));
$this->assertResponse(200, 'Searching for ../../admin with non-admin user does not lead to a 403 error');
$this->assertText('no results', 'Searching for ../../admin with non-admin user gives you a no search results page');
// Test that if you search for a URL starting with "./", you still end up
// at the search page. See issue https://www.drupal.org/node/1421560.
$this->drupalPostForm('search/node', ['keys' => '.something'], t('Search'));
$this->assertResponse(200, 'Searching for .something does not lead to a 403 error');
$this->assertText('no results', 'Searching for .something gives you a no search results page');
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that the search preprocessing uses the correct language code.
*
* @group search
*/
class SearchPreprocessLangcodeTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search', 'search_langcode_test'];
/**
* Test node for searching.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$web_user = $this->drupalCreateUser([
'create page content',
'edit own page content',
'search content',
'use advanced search',
]);
$this->drupalLogin($web_user);
}
/**
* Tests that hook_search_preprocess() returns the correct langcode.
*/
public function testPreprocessLangcode() {
// Create a node.
$this->node = $this->drupalCreateNode(['body' => [[]], 'langcode' => 'en']);
// First update the index. This does the initial processing.
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
// Then, run the shutdown function. Testing is a unique case where indexing
// and searching has to happen in the same request, so running the shutdown
// function manually is needed to finish the indexing process.
search_update_totals();
// Search for the additional text that is added by the preprocess
// function. If you search for text that is in the node, preprocess is
// not invoked on the node during the search excerpt generation.
$edit = ['or' => 'Additional text'];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Checks if the langcode message has been set by hook_search_preprocess().
$this->assertText('Langcode Preprocess Test: en');
}
/**
* Tests stemming for hook_search_preprocess().
*/
public function testPreprocessStemming() {
// Create a node.
$this->node = $this->drupalCreateNode([
'title' => 'we are testing',
'body' => [[]],
'langcode' => 'en',
]);
// First update the index. This does the initial processing.
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
// Then, run the shutdown function. Testing is a unique case where indexing
// and searching has to happen in the same request, so running the shutdown
// function manually is needed to finish the indexing process.
search_update_totals();
// Search for the title of the node with a POST query.
$edit = ['or' => 'testing'];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Check if the node has been found.
$this->assertText('Search results');
$this->assertText('we are testing');
// Search for the same node using a different query.
$edit = ['or' => 'test'];
$this->drupalPostForm('search/node', $edit, 'edit-submit--2');
// Check if the node has been found.
$this->assertText('Search results');
$this->assertText('we are testing');
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that the node search query can be altered via the query alter hook.
*
* @group search
*/
class SearchQueryAlterTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search', 'search_query_alter'];
/**
* Tests that the query alter works.
*/
public function testQueryAlter() {
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
// Log in with sufficient privileges.
$this->drupalLogin($this->drupalCreateUser(['create page content', 'search content']));
// Create a node and an article with the same keyword. The query alter
// test module will alter the query so only articles should be returned.
$data = [
'type' => 'page',
'title' => 'test page',
'body' => [['value' => 'pizza']],
];
$this->drupalCreateNode($data);
$data['type'] = 'article';
$data['title'] = 'test article';
$this->drupalCreateNode($data);
// Update the search index.
$this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
// Search for the body keyword 'pizza'.
$this->drupalPostForm('search/node', ['keys' => 'pizza'], t('Search'));
// The article should be there but not the page.
$this->assertText('article', 'Article is in search results');
$this->assertNoText('page', 'Page is not in search results');
}
}

View file

@ -0,0 +1,282 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Core\Url;
use Drupal\filter\Entity\FilterFormat;
use Drupal\search\Entity\SearchPage;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
/**
* Indexes content and tests ranking factors.
*
* @group search
*/
class SearchRankingTest extends BrowserTestBase {
use CommentTestTrait;
use CronRunTrait;
/**
* The node search page.
*
* @var \Drupal\search\SearchPageInterface
*/
protected $nodeSearch;
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'search', 'statistics', 'comment'];
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create a plugin instance.
$this->nodeSearch = SearchPage::load('node_search');
// Log in with sufficient privileges.
$this->drupalLogin($this->drupalCreateUser(['post comments', 'skip comment approval', 'create page content', 'administer search']));
}
public function testRankings() {
// Add a comment field.
$this->addDefaultCommentField('node', 'page');
// Build a list of the rankings to test.
$node_ranks = ['sticky', 'promote', 'relevance', 'recent', 'comments', 'views'];
// Create nodes for testing.
$nodes = [];
foreach ($node_ranks as $node_rank) {
$settings = [
'type' => 'page',
'comment' => [
['status' => CommentItemInterface::HIDDEN],
],
'title' => 'Drupal rocks',
'body' => [['value' => "Drupal's search rocks"]],
// Node is one day old.
'created' => REQUEST_TIME - 24 * 3600,
'sticky' => 0,
'promote' => 0,
];
foreach ([0, 1] as $num) {
if ($num == 1) {
switch ($node_rank) {
case 'sticky':
case 'promote':
$settings[$node_rank] = 1;
break;
case 'relevance':
$settings['body'][0]['value'] .= " really rocks";
break;
case 'recent':
// Node is 1 hour hold.
$settings['created'] = REQUEST_TIME - 3600;
break;
case 'comments':
$settings['comment'][0]['status'] = CommentItemInterface::OPEN;
break;
}
}
$nodes[$node_rank][$num] = $this->drupalCreateNode($settings);
}
}
// Add a comment to one of the nodes.
$edit = [];
$edit['subject[0][value]'] = 'my comment title';
$edit['comment_body[0][value]'] = 'some random comment';
$this->drupalGet('comment/reply/node/' . $nodes['comments'][1]->id() . '/comment');
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->drupalPostForm(NULL, $edit, t('Save'));
// Enable counting of statistics.
$this->config('statistics.settings')->set('count_content_views', 1)->save();
// Simulating content views is kind of difficult in the test. Leave that
// to the Statistics module. So instead go ahead and manually update the
// counter for this node.
$nid = $nodes['views'][1]->id();
db_insert('node_counter')
->fields(['totalcount' => 5, 'daycount' => 5, 'timestamp' => REQUEST_TIME, 'nid' => $nid])
->execute();
// Run cron to update the search index and comment/statistics totals.
$this->cronRun();
// Test that the settings form displays the content ranking section.
$this->drupalGet('admin/config/search/pages/manage/node_search');
$this->assertText(t('Content ranking'));
// Check that all rankings are visible and set to 0.
foreach ($node_ranks as $node_rank) {
$this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="0"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 0.');
}
// Test each of the possible rankings.
$edit = [];
foreach ($node_ranks as $node_rank) {
// Enable the ranking we are testing.
$edit['rankings[' . $node_rank . '][value]'] = 10;
$this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
$this->drupalGet('admin/config/search/pages/manage/node_search');
$this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="10"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 10.');
// Reload the plugin to get the up-to-date values.
$this->nodeSearch = SearchPage::load('node_search');
// Do the search and assert the results.
$this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
$set = $this->nodeSearch->getPlugin()->execute();
$this->assertEqual($set[0]['node']->id(), $nodes[$node_rank][1]->id(), 'Search ranking "' . $node_rank . '" order.');
// Clear this ranking for the next test.
$edit['rankings[' . $node_rank . '][value]'] = 0;
}
// Save the final node_rank change then check that all rankings are visible
// and have been set back to 0.
$this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
$this->drupalGet('admin/config/search/pages/manage/node_search');
foreach ($node_ranks as $node_rank) {
$this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="0"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 0.');
}
// Try with sticky, then promoted. This is a test for issue
// https://www.drupal.org/node/771596.
$node_ranks = [
'sticky' => 10,
'promote' => 1,
'relevance' => 0,
'recent' => 0,
'comments' => 0,
'views' => 0,
];
$configuration = $this->nodeSearch->getPlugin()->getConfiguration();
foreach ($node_ranks as $var => $value) {
$configuration['rankings'][$var] = $value;
}
$this->nodeSearch->getPlugin()->setConfiguration($configuration);
$this->nodeSearch->save();
// Do the search and assert the results. The sticky node should show up
// first, then the promoted node, then all the rest.
$this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
$set = $this->nodeSearch->getPlugin()->execute();
$this->assertEqual($set[0]['node']->id(), $nodes['sticky'][1]->id(), 'Search ranking for sticky first worked.');
$this->assertEqual($set[1]['node']->id(), $nodes['promote'][1]->id(), 'Search ranking for promoted second worked.');
// Try with recent, then comments. This is a test for issues
// https://www.drupal.org/node/771596 and
// https://www.drupal.org/node/303574.
$node_ranks = [
'sticky' => 0,
'promote' => 0,
'relevance' => 0,
'recent' => 10,
'comments' => 1,
'views' => 0,
];
$configuration = $this->nodeSearch->getPlugin()->getConfiguration();
foreach ($node_ranks as $var => $value) {
$configuration['rankings'][$var] = $value;
}
$this->nodeSearch->getPlugin()->setConfiguration($configuration);
$this->nodeSearch->save();
// Do the search and assert the results. The recent node should show up
// first, then the commented node, then all the rest.
$this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
$set = $this->nodeSearch->getPlugin()->execute();
$this->assertEqual($set[0]['node']->id(), $nodes['recent'][1]->id(), 'Search ranking for recent first worked.');
$this->assertEqual($set[1]['node']->id(), $nodes['comments'][1]->id(), 'Search ranking for comments second worked.');
}
/**
* Test rankings of HTML tags.
*/
public function testHTMLRankings() {
$full_html_format = FilterFormat::create([
'format' => 'full_html',
'name' => 'Full HTML',
]);
$full_html_format->save();
// Test HTML tags with different weights.
$sorted_tags = ['h1', 'h2', 'h3', 'h4', 'a', 'h5', 'h6', 'notag'];
$shuffled_tags = $sorted_tags;
// Shuffle tags to ensure HTML tags are ranked properly.
shuffle($shuffled_tags);
$settings = [
'type' => 'page',
'title' => 'Simple node',
];
$nodes = [];
foreach ($shuffled_tags as $tag) {
switch ($tag) {
case 'a':
$settings['body'] = [['value' => \Drupal::l('Drupal Rocks', new Url('<front>')), 'format' => 'full_html']];
break;
case 'notag':
$settings['body'] = [['value' => 'Drupal Rocks']];
break;
default:
$settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
break;
}
$nodes[$tag] = $this->drupalCreateNode($settings);
}
// Update the search index.
$this->nodeSearch->getPlugin()->updateIndex();
search_update_totals();
$this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
// Do the search and assert the results.
$set = $this->nodeSearch->getPlugin()->execute();
// Test the ranking of each tag.
foreach ($sorted_tags as $tag_rank => $tag) {
// Assert the results.
if ($tag == 'notag') {
$this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for plain text order.');
}
else {
$this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for "&lt;' . $sorted_tags[$tag_rank] . '&gt;" order.');
}
}
// Test tags with the same weight against the sorted tags.
$unsorted_tags = ['u', 'b', 'i', 'strong', 'em'];
foreach ($unsorted_tags as $tag) {
$settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
$node = $this->drupalCreateNode($settings);
// Update the search index.
$this->nodeSearch->getPlugin()->updateIndex();
search_update_totals();
$this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
// Do the search and assert the results.
$set = $this->nodeSearch->getPlugin()->execute();
// Ranking should always be second to last.
$set = array_slice($set, -2, 1);
// Assert the results.
$this->assertEqual($set[0]['node']->id(), $node->id(), 'Search tag ranking for "&lt;' . $tag . '&gt;" order.');
// Delete node so it doesn't show up in subsequent search results.
$node->delete();
}
}
}

View file

@ -2,19 +2,19 @@
namespace Drupal\Tests\search\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that search works with numeric locale settings.
*
* @group search
*/
class SearchSetLocaleTest extends SearchTestBase {
class SearchSetLocaleTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
* {@inheritdoc}
*/
public static $modules = ['comment'];
protected static $modules = ['comment', 'node', 'search'];
/**
* A node search plugin instance.
@ -26,6 +26,8 @@ class SearchSetLocaleTest extends SearchTestBase {
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create a plugin instance.
$this->nodeSearchPlugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
// Create a node with a very simple body.

View file

@ -1,14 +1,21 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that the search_simply() function works as intended.
*
* @group search
*/
class SearchSimplifyTest extends SearchTestBase {
class SearchSimplifyTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['search'];
/**
* Tests that all Unicode characters simplify correctly.
*/
@ -20,7 +27,7 @@ class SearchSimplifyTest extends SearchTestBase {
// their own lines). So the even-numbered lines should simplify to nothing,
// and the odd-numbered lines we need to split into shorter chunks and
// verify that simplification doesn't lose any characters.
$input = file_get_contents(\Drupal::root() . '/core/modules/search/tests/UnicodeTest.txt');
$input = file_get_contents($this->root . '/core/modules/search/tests/UnicodeTest.txt');
$basestrings = explode(chr(10), $input);
$strings = [];
foreach ($basestrings as $key => $string) {
@ -34,8 +41,8 @@ class SearchSimplifyTest extends SearchTestBase {
// Split this into 30-character chunks, so we don't run into limits
// of truncation in search_simplify().
$start = 0;
while ($start < Unicode::strlen($string)) {
$newstr = Unicode::substr($string, $start, 30);
while ($start < mb_strlen($string)) {
$newstr = mb_substr($string, $start, 30);
// Special case: leading zeros are removed from numeric strings,
// and there's one string in this file that is numbers starting with
// zero, so prepend a 1 on that string.
@ -49,7 +56,7 @@ class SearchSimplifyTest extends SearchTestBase {
}
foreach ($strings as $key => $string) {
$simplified = search_simplify($string);
$this->assertTrue(Unicode::strlen($simplified) >= Unicode::strlen($string), "Nothing is removed from string $key.");
$this->assertTrue(mb_strlen($simplified) >= mb_strlen($string), "Nothing is removed from string $key.");
}
// Test the low-numbered ASCII control characters separately. They are not

View file

@ -2,11 +2,17 @@
namespace Drupal\Tests\search\Functional;
@trigger_error(__NAMESPACE__ . '\SearchTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\BrowserTestBase. See https://www.drupal.org/node/2979950.', E_USER_DEPRECATED);
use Drupal\Tests\BrowserTestBase;
use Drupal\Component\Utility\SafeMarkup;
/**
* Defines the common search test code.
*
* @deprecated in Drupal 8.6.0 and will be removed in Drupal 9.0.0. Use
* \Drupal\Tests\BrowserTestBase instead.
*
* @see https://www.drupal.org/node/2979950
*/
abstract class SearchTestBase extends BrowserTestBase {
@ -28,17 +34,7 @@ abstract class SearchTestBase extends BrowserTestBase {
}
/**
* Simulates submission of a form using GET instead of POST.
*
* Forms that use the GET method cannot be submitted with
* WebTestBase::drupalPostForm(), which explicitly uses POST to submit the
* form. So this method finds the form, verifies that it has input fields and
* a submit button matching the inputs to this method, and then calls
* WebTestBase::drupalGet() to simulate the form submission to the 'action'
* URL of the form (if set, or the current URL if not).
*
* See WebTestBase::drupalPostForm() for more detailed documentation of the
* function parameters.
* Submission of a form via press submit button.
*
* @param string $path
* Location of the form to be submitted: either a Drupal path, absolute
@ -51,42 +47,15 @@ abstract class SearchTestBase extends BrowserTestBase {
* this does not support AJAX.
* @param string $form_html_id
* (optional) HTML ID of the form, to disambiguate.
*
* @deprecated in Drupal 8.6.x, to be removed before Drupal 9.0.x. Use
* \Drupal\Tests\BrowserTestBase::drupalPostForm() instead.
*
* @see https://www.drupal.org/node/2979950
*/
protected function submitGetForm($path, $edit, $submit, $form_html_id = NULL) {
if (isset($path)) {
$this->drupalGet($path);
}
if ($this->parse()) {
// Iterate over forms to find one that matches $edit and $submit.
$edit_save = $edit;
$xpath = '//form';
if (!empty($form_html_id)) {
$xpath .= "[@id='" . $form_html_id . "']";
}
$forms = $this->xpath($xpath);
foreach ($forms as $form) {
// Try to set the fields of this form as specified in $edit.
$edit = $edit_save;
$post = [];
$upload = [];
$submit_matches = $this->handleForm($post, $edit, $upload, $submit, $form);
if (!$edit && $submit_matches) {
// Everything matched, so "submit" the form.
$action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : NULL;
$this->drupalGet($action, ['query' => $post]);
return;
}
}
// We have not found a form which contained all fields of $edit and
// the submit button.
foreach ($edit as $name => $value) {
$this->fail(SafeMarkup::format('Failed to set field @name to @value', ['@name' => $name, '@value' => $value]));
}
$this->assertTrue($submit_matches, format_string('Found the @submit button', ['@submit' => $submit]));
$this->fail(format_string('Found the requested form fields at @path', ['@path' => $path]));
}
@trigger_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated in Drupal 8.6.x, for removal before the Drupal 9.0.0 release. Use \Drupal\Tests\BrowserTestBase::drupalPostForm() instead. See https://www.drupal.org/node/2979950.', E_USER_DEPRECATED);
$this->drupalPostForm($path, $edit, $submit, [], $form_html_id);
}
}

View file

@ -1,14 +1,20 @@
<?php
namespace Drupal\Tests\search\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that CJK tokenizer works as intended.
*
* @group search
*/
class SearchTokenizerTest extends SearchTestBase {
class SearchTokenizerTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['search'];
/**
* Verifies that strings of CJK characters are tokenized.
@ -94,7 +100,7 @@ class SearchTokenizerTest extends SearchTestBase {
// Merge into a string and tokenize.
$string = implode('', $chars);
$out = trim(search_simplify($string));
$expected = Unicode::strtolower(implode(' ', $chars));
$expected = mb_strtolower(implode(' ', $chars));
// Verify that the output matches what we expect.
$this->assertEqual($out, $expected, 'CJK tokenizer worked on all supplied CJK characters');
@ -124,9 +130,9 @@ class SearchTokenizerTest extends SearchTestBase {
/**
* Like PHP chr() function, but for unicode characters.
*
* chr() only works for ASCII characters up to character 255. This function
* converts a number to the corresponding unicode character. Adapted from
* functions supplied in comments on several functions on php.net.
* Function chr() only works for ASCII characters up to character 255. This
* function converts a number to the corresponding unicode character. Adapted
* from functions supplied in comments on several functions on php.net.
*/
public function code2utf($num) {
if ($num < 128) {

View file

@ -156,7 +156,7 @@ class SearchMatchTest extends KernelTestBase {
'"am minim veniam" -"cillum dolore"' => [5, 6],
'"am minim veniam" -"dolore cillum"' => [5, 6, 7],
'xxxxx "minim am veniam es" OR dolore' => [],
'xx "minim am veniam es" OR dolore' => []
'xx "minim am veniam es" OR dolore' => [],
];
foreach ($queries as $query => $results) {
$result = db_select('search_index', 'i')

View file

@ -273,11 +273,13 @@ class SearchPageRepositoryTest extends UnitTestCase {
}
class TestSearchPage extends SearchPage {
public function __construct(array $values) {
foreach ($values as $key => $value) {
$this->$key = $value;
}
}
public function label($langcode = NULL) {
return $this->label;
}