annotate core/modules/search/tests/src/Functional/SearchRankingTest.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents a9cd425dd02b
children
rev   line source
Chris@4 1 <?php
Chris@4 2
Chris@4 3 namespace Drupal\Tests\search\Functional;
Chris@4 4
Chris@4 5 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
Chris@4 6 use Drupal\comment\Tests\CommentTestTrait;
Chris@5 7 use Drupal\Core\Database\Database;
Chris@4 8 use Drupal\Core\Url;
Chris@4 9 use Drupal\filter\Entity\FilterFormat;
Chris@4 10 use Drupal\search\Entity\SearchPage;
Chris@4 11 use Drupal\Tests\BrowserTestBase;
Chris@4 12 use Drupal\Tests\Traits\Core\CronRunTrait;
Chris@4 13
Chris@4 14 /**
Chris@4 15 * Indexes content and tests ranking factors.
Chris@4 16 *
Chris@4 17 * @group search
Chris@4 18 */
Chris@4 19 class SearchRankingTest extends BrowserTestBase {
Chris@4 20
Chris@4 21 use CommentTestTrait;
Chris@4 22 use CronRunTrait;
Chris@4 23
Chris@4 24 /**
Chris@4 25 * The node search page.
Chris@4 26 *
Chris@4 27 * @var \Drupal\search\SearchPageInterface
Chris@4 28 */
Chris@4 29 protected $nodeSearch;
Chris@4 30
Chris@4 31 /**
Chris@4 32 * {@inheritdoc}
Chris@4 33 */
Chris@4 34 protected static $modules = ['node', 'search', 'statistics', 'comment'];
Chris@4 35
Chris@4 36 protected function setUp() {
Chris@4 37 parent::setUp();
Chris@4 38
Chris@4 39 $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
Chris@4 40
Chris@4 41 // Create a plugin instance.
Chris@4 42 $this->nodeSearch = SearchPage::load('node_search');
Chris@4 43
Chris@4 44 // Log in with sufficient privileges.
Chris@4 45 $this->drupalLogin($this->drupalCreateUser(['post comments', 'skip comment approval', 'create page content', 'administer search']));
Chris@4 46 }
Chris@4 47
Chris@4 48 public function testRankings() {
Chris@4 49 // Add a comment field.
Chris@4 50 $this->addDefaultCommentField('node', 'page');
Chris@4 51
Chris@4 52 // Build a list of the rankings to test.
Chris@4 53 $node_ranks = ['sticky', 'promote', 'relevance', 'recent', 'comments', 'views'];
Chris@4 54
Chris@4 55 // Create nodes for testing.
Chris@4 56 $nodes = [];
Chris@4 57 foreach ($node_ranks as $node_rank) {
Chris@4 58 $settings = [
Chris@4 59 'type' => 'page',
Chris@4 60 'comment' => [
Chris@4 61 ['status' => CommentItemInterface::HIDDEN],
Chris@4 62 ],
Chris@4 63 'title' => 'Drupal rocks',
Chris@4 64 'body' => [['value' => "Drupal's search rocks"]],
Chris@4 65 // Node is one day old.
Chris@4 66 'created' => REQUEST_TIME - 24 * 3600,
Chris@4 67 'sticky' => 0,
Chris@4 68 'promote' => 0,
Chris@4 69 ];
Chris@4 70 foreach ([0, 1] as $num) {
Chris@4 71 if ($num == 1) {
Chris@4 72 switch ($node_rank) {
Chris@4 73 case 'sticky':
Chris@4 74 case 'promote':
Chris@4 75 $settings[$node_rank] = 1;
Chris@4 76 break;
Chris@4 77 case 'relevance':
Chris@4 78 $settings['body'][0]['value'] .= " really rocks";
Chris@4 79 break;
Chris@4 80 case 'recent':
Chris@4 81 // Node is 1 hour hold.
Chris@4 82 $settings['created'] = REQUEST_TIME - 3600;
Chris@4 83 break;
Chris@4 84 case 'comments':
Chris@4 85 $settings['comment'][0]['status'] = CommentItemInterface::OPEN;
Chris@4 86 break;
Chris@4 87 }
Chris@4 88 }
Chris@4 89 $nodes[$node_rank][$num] = $this->drupalCreateNode($settings);
Chris@4 90 }
Chris@4 91 }
Chris@4 92
Chris@4 93 // Add a comment to one of the nodes.
Chris@4 94 $edit = [];
Chris@4 95 $edit['subject[0][value]'] = 'my comment title';
Chris@4 96 $edit['comment_body[0][value]'] = 'some random comment';
Chris@4 97 $this->drupalGet('comment/reply/node/' . $nodes['comments'][1]->id() . '/comment');
Chris@4 98 $this->drupalPostForm(NULL, $edit, t('Preview'));
Chris@4 99 $this->drupalPostForm(NULL, $edit, t('Save'));
Chris@4 100
Chris@4 101 // Enable counting of statistics.
Chris@4 102 $this->config('statistics.settings')->set('count_content_views', 1)->save();
Chris@4 103
Chris@4 104 // Simulating content views is kind of difficult in the test. Leave that
Chris@4 105 // to the Statistics module. So instead go ahead and manually update the
Chris@4 106 // counter for this node.
Chris@4 107 $nid = $nodes['views'][1]->id();
Chris@5 108 Database::getConnection()->insert('node_counter')
Chris@4 109 ->fields(['totalcount' => 5, 'daycount' => 5, 'timestamp' => REQUEST_TIME, 'nid' => $nid])
Chris@4 110 ->execute();
Chris@4 111
Chris@4 112 // Run cron to update the search index and comment/statistics totals.
Chris@4 113 $this->cronRun();
Chris@4 114
Chris@4 115 // Test that the settings form displays the content ranking section.
Chris@4 116 $this->drupalGet('admin/config/search/pages/manage/node_search');
Chris@4 117 $this->assertText(t('Content ranking'));
Chris@4 118
Chris@4 119 // Check that all rankings are visible and set to 0.
Chris@4 120 foreach ($node_ranks as $node_rank) {
Chris@4 121 $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.');
Chris@4 122 }
Chris@4 123
Chris@4 124 // Test each of the possible rankings.
Chris@4 125 $edit = [];
Chris@4 126 foreach ($node_ranks as $node_rank) {
Chris@4 127 // Enable the ranking we are testing.
Chris@4 128 $edit['rankings[' . $node_rank . '][value]'] = 10;
Chris@4 129 $this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
Chris@4 130 $this->drupalGet('admin/config/search/pages/manage/node_search');
Chris@4 131 $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.');
Chris@4 132
Chris@4 133 // Reload the plugin to get the up-to-date values.
Chris@4 134 $this->nodeSearch = SearchPage::load('node_search');
Chris@4 135 // Do the search and assert the results.
Chris@4 136 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
Chris@4 137 $set = $this->nodeSearch->getPlugin()->execute();
Chris@4 138 $this->assertEqual($set[0]['node']->id(), $nodes[$node_rank][1]->id(), 'Search ranking "' . $node_rank . '" order.');
Chris@4 139
Chris@4 140 // Clear this ranking for the next test.
Chris@4 141 $edit['rankings[' . $node_rank . '][value]'] = 0;
Chris@4 142 }
Chris@4 143
Chris@4 144 // Save the final node_rank change then check that all rankings are visible
Chris@4 145 // and have been set back to 0.
Chris@4 146 $this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
Chris@4 147 $this->drupalGet('admin/config/search/pages/manage/node_search');
Chris@4 148 foreach ($node_ranks as $node_rank) {
Chris@4 149 $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.');
Chris@4 150 }
Chris@4 151
Chris@4 152 // Try with sticky, then promoted. This is a test for issue
Chris@4 153 // https://www.drupal.org/node/771596.
Chris@4 154 $node_ranks = [
Chris@4 155 'sticky' => 10,
Chris@4 156 'promote' => 1,
Chris@4 157 'relevance' => 0,
Chris@4 158 'recent' => 0,
Chris@4 159 'comments' => 0,
Chris@4 160 'views' => 0,
Chris@4 161 ];
Chris@4 162 $configuration = $this->nodeSearch->getPlugin()->getConfiguration();
Chris@4 163 foreach ($node_ranks as $var => $value) {
Chris@4 164 $configuration['rankings'][$var] = $value;
Chris@4 165 }
Chris@4 166 $this->nodeSearch->getPlugin()->setConfiguration($configuration);
Chris@4 167 $this->nodeSearch->save();
Chris@4 168
Chris@4 169 // Do the search and assert the results. The sticky node should show up
Chris@4 170 // first, then the promoted node, then all the rest.
Chris@4 171 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
Chris@4 172 $set = $this->nodeSearch->getPlugin()->execute();
Chris@4 173 $this->assertEqual($set[0]['node']->id(), $nodes['sticky'][1]->id(), 'Search ranking for sticky first worked.');
Chris@4 174 $this->assertEqual($set[1]['node']->id(), $nodes['promote'][1]->id(), 'Search ranking for promoted second worked.');
Chris@4 175
Chris@4 176 // Try with recent, then comments. This is a test for issues
Chris@4 177 // https://www.drupal.org/node/771596 and
Chris@4 178 // https://www.drupal.org/node/303574.
Chris@4 179 $node_ranks = [
Chris@4 180 'sticky' => 0,
Chris@4 181 'promote' => 0,
Chris@4 182 'relevance' => 0,
Chris@4 183 'recent' => 10,
Chris@4 184 'comments' => 1,
Chris@4 185 'views' => 0,
Chris@4 186 ];
Chris@4 187 $configuration = $this->nodeSearch->getPlugin()->getConfiguration();
Chris@4 188 foreach ($node_ranks as $var => $value) {
Chris@4 189 $configuration['rankings'][$var] = $value;
Chris@4 190 }
Chris@4 191 $this->nodeSearch->getPlugin()->setConfiguration($configuration);
Chris@4 192 $this->nodeSearch->save();
Chris@4 193
Chris@4 194 // Do the search and assert the results. The recent node should show up
Chris@4 195 // first, then the commented node, then all the rest.
Chris@4 196 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
Chris@4 197 $set = $this->nodeSearch->getPlugin()->execute();
Chris@4 198 $this->assertEqual($set[0]['node']->id(), $nodes['recent'][1]->id(), 'Search ranking for recent first worked.');
Chris@4 199 $this->assertEqual($set[1]['node']->id(), $nodes['comments'][1]->id(), 'Search ranking for comments second worked.');
Chris@4 200
Chris@4 201 }
Chris@4 202
Chris@4 203 /**
Chris@4 204 * Test rankings of HTML tags.
Chris@4 205 */
Chris@4 206 public function testHTMLRankings() {
Chris@4 207 $full_html_format = FilterFormat::create([
Chris@4 208 'format' => 'full_html',
Chris@4 209 'name' => 'Full HTML',
Chris@4 210 ]);
Chris@4 211 $full_html_format->save();
Chris@4 212
Chris@4 213 // Test HTML tags with different weights.
Chris@4 214 $sorted_tags = ['h1', 'h2', 'h3', 'h4', 'a', 'h5', 'h6', 'notag'];
Chris@4 215 $shuffled_tags = $sorted_tags;
Chris@4 216
Chris@4 217 // Shuffle tags to ensure HTML tags are ranked properly.
Chris@4 218 shuffle($shuffled_tags);
Chris@4 219 $settings = [
Chris@4 220 'type' => 'page',
Chris@4 221 'title' => 'Simple node',
Chris@4 222 ];
Chris@4 223 $nodes = [];
Chris@4 224 foreach ($shuffled_tags as $tag) {
Chris@4 225 switch ($tag) {
Chris@4 226 case 'a':
Chris@4 227 $settings['body'] = [['value' => \Drupal::l('Drupal Rocks', new Url('<front>')), 'format' => 'full_html']];
Chris@4 228 break;
Chris@4 229 case 'notag':
Chris@4 230 $settings['body'] = [['value' => 'Drupal Rocks']];
Chris@4 231 break;
Chris@4 232 default:
Chris@4 233 $settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
Chris@4 234 break;
Chris@4 235 }
Chris@4 236 $nodes[$tag] = $this->drupalCreateNode($settings);
Chris@4 237 }
Chris@4 238
Chris@4 239 // Update the search index.
Chris@4 240 $this->nodeSearch->getPlugin()->updateIndex();
Chris@4 241 search_update_totals();
Chris@4 242
Chris@4 243 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
Chris@4 244 // Do the search and assert the results.
Chris@4 245 $set = $this->nodeSearch->getPlugin()->execute();
Chris@4 246
Chris@4 247 // Test the ranking of each tag.
Chris@4 248 foreach ($sorted_tags as $tag_rank => $tag) {
Chris@4 249 // Assert the results.
Chris@4 250 if ($tag == 'notag') {
Chris@4 251 $this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for plain text order.');
Chris@4 252 }
Chris@4 253 else {
Chris@4 254 $this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for "&lt;' . $sorted_tags[$tag_rank] . '&gt;" order.');
Chris@4 255 }
Chris@4 256 }
Chris@4 257
Chris@4 258 // Test tags with the same weight against the sorted tags.
Chris@4 259 $unsorted_tags = ['u', 'b', 'i', 'strong', 'em'];
Chris@4 260 foreach ($unsorted_tags as $tag) {
Chris@4 261 $settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
Chris@4 262 $node = $this->drupalCreateNode($settings);
Chris@4 263
Chris@4 264 // Update the search index.
Chris@4 265 $this->nodeSearch->getPlugin()->updateIndex();
Chris@4 266 search_update_totals();
Chris@4 267
Chris@4 268 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
Chris@4 269 // Do the search and assert the results.
Chris@4 270 $set = $this->nodeSearch->getPlugin()->execute();
Chris@4 271
Chris@4 272 // Ranking should always be second to last.
Chris@4 273 $set = array_slice($set, -2, 1);
Chris@4 274
Chris@4 275 // Assert the results.
Chris@4 276 $this->assertEqual($set[0]['node']->id(), $node->id(), 'Search tag ranking for "&lt;' . $tag . '&gt;" order.');
Chris@4 277
Chris@4 278 // Delete node so it doesn't show up in subsequent search results.
Chris@4 279 $node->delete();
Chris@4 280 }
Chris@4 281 }
Chris@4 282
Chris@4 283 }