3 namespace Drupal\Tests\node\Functional\Views;
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Language\LanguageInterface;
8 use Drupal\node\Entity\Node;
9 use Drupal\Tests\views\Functional\ViewTestBase;
10 use Drupal\views\Tests\AssertViewsCacheTagsTrait;
11 use Drupal\views\ViewExecutable;
12 use Drupal\views\Views;
15 * Tests the default frontpage provided by views.
19 class FrontPageTest extends ViewTestBase {
21 use AssertViewsCacheTagsTrait;
26 protected $dumpHeaders = TRUE;
29 * The entity storage for nodes.
31 * @var \Drupal\node\NodeStorage
33 protected $nodeStorage;
40 public static $modules = ['node', 'contextual'];
45 protected function setUp($import_test_views = TRUE) {
46 parent::setUp($import_test_views);
48 $this->nodeStorage = $this->container->get('entity.manager')
53 * Tests the frontpage.
55 public function testFrontPage() {
56 $site_name = $this->randomMachineName();
57 $this->config('system.site')
58 ->set('name', $site_name)
61 $view = Views::getView('frontpage');
63 // Tests \Drupal\node\Plugin\views\row\RssPluginBase::calculateDependencies().
66 'core.entity_view_mode.node.rss',
67 'core.entity_view_mode.node.teaser',
74 $this->assertIdentical($expected, $view->getDependencies());
76 $view->setDisplay('page_1');
77 $this->executeView($view);
80 $this->assertEqual($view->getTitle(), format_string('Welcome to @site_name', ['@site_name' => $site_name]), 'The welcome title is used for the empty view.');
83 // Create some nodes on the frontpage view. Add more than 10 nodes in order
86 for ($i = 0; $i < 20; $i++) {
88 $values['type'] = 'article';
89 $values['title'] = $this->randomMachineName();
90 $values['promote'] = TRUE;
91 $values['status'] = TRUE;
92 // Test descending sort order.
93 $values['created'] = REQUEST_TIME - $i;
94 // Test the sticky order.
96 $values['sticky'] = TRUE;
97 $node = $this->nodeStorage->create($values);
99 // Put the sticky on at the front.
100 array_unshift($expected, ['nid' => $node->id()]);
103 $values['sticky'] = FALSE;
104 $node = $this->nodeStorage->create($values);
106 array_push($expected, ['nid' => $node->id()]);
110 // Create some nodes which aren't on the frontpage, either because they
111 // aren't promoted or because they aren't published.
112 $not_expected_nids = [];
115 $values['type'] = 'article';
116 $values['title'] = $this->randomMachineName();
117 $values['status'] = TRUE;
118 $values['promote'] = FALSE;
119 $node = $this->nodeStorage->create($values);
121 $not_expected_nids[] = $node->id();
123 $values['promote'] = TRUE;
124 $values['status'] = FALSE;
125 $values['title'] = $this->randomMachineName();
126 $node = $this->nodeStorage->create($values);
128 $not_expected_nids[] = $node->id();
130 $values['promote'] = TRUE;
131 $values['sticky'] = TRUE;
132 $values['status'] = FALSE;
133 $values['title'] = $this->randomMachineName();
134 $node = $this->nodeStorage->create($values);
136 $not_expected_nids[] = $node->id();
138 $column_map = ['nid' => 'nid'];
140 $view->setDisplay('page_1');
141 $this->executeView($view);
142 $this->assertIdenticalResultset($view, array_slice($expected, 0, 10), $column_map, 'Ensure that the right nodes are displayed on the frontpage.');
143 $this->assertNotInResultSet($view, $not_expected_nids, 'Ensure no unexpected node is in the result.');
146 $view->setDisplay('page_1');
147 $view->setCurrentPage(1);
148 $this->executeView($view);
149 $this->assertIdenticalResultset($view, array_slice($expected, 10, 10), $column_map, 'Ensure that the right nodes are displayed on second page of the frontpage.');
150 $this->assertNotInResultSet($view, $not_expected_nids, 'Ensure no unexpected node is in the result.');
155 * Verifies that an amount of nids aren't in the result.
157 * @param \Drupal\views\ViewExecutable $view
159 * @param array $not_expected_nids
160 * An array of nids which should not be part of the resultset.
161 * @param string $message
162 * (optional) A custom message to display with the assertion.
164 protected function assertNotInResultSet(ViewExecutable $view, array $not_expected_nids, $message = '') {
165 $found_nids = array_filter($view->result, function ($row) use ($not_expected_nids) {
166 return in_array($row->nid, $not_expected_nids);
168 $this->assertFalse($found_nids, $message);
172 * Tests the frontpage when logged in as admin.
174 public function testAdminFrontPage() {
175 // When a user with sufficient permissions is logged in, views_ui adds
176 // contextual links to the homepage view. This verifies there are no errors.
177 \Drupal::service('module_installer')->install(['views_ui']);
178 // Log in root user with sufficient permissions.
179 $this->drupalLogin($this->rootUser);
180 // Test frontpage view.
181 $this->drupalGet('node');
182 $this->assertResponse(200);
183 // Check that the frontpage view was rendered.
184 $this->assertPattern('/class=".+view-frontpage/', 'Frontpage view was rendered');
188 * Tests the cache tags when using the "none" cache plugin.
190 public function testCacheTagsWithCachePluginNone() {
191 $this->enablePageCaching();
192 $this->doTestFrontPageViewCacheTags(FALSE);
196 * Tests the cache tags when using the "tag" cache plugin.
198 public function testCacheTagsWithCachePluginTag() {
199 $this->enablePageCaching();
201 $view = Views::getView('frontpage');
202 $view->setDisplay('page_1');
203 $view->display_handler->overrideOption('cache', [
208 $this->doTestFrontPageViewCacheTags(TRUE);
212 * Tests the cache tags when using the "time" cache plugin.
214 public function testCacheTagsWithCachePluginTime() {
215 $this->enablePageCaching();
217 $view = Views::getView('frontpage');
218 $view->setDisplay('page_1');
219 $view->display_handler->overrideOption('cache', [
222 'results_lifespan' => 3600,
223 'output_lifespan' => 3600,
228 $this->doTestFrontPageViewCacheTags(TRUE);
232 * Tests the cache tags on the front page.
234 * @param bool $do_assert_views_caches
235 * Whether to check Views' result & output caches.
237 protected function doTestFrontPageViewCacheTags($do_assert_views_caches) {
238 $view = Views::getView('frontpage');
239 $view->setDisplay('page_1');
242 // Cache contexts associated with the view.
243 'user.node_grants:view',
244 'languages:' . LanguageInterface::TYPE_INTERFACE,
245 // Cache contexts associated with the route's access checking.
247 // Default cache contexts of the renderer.
254 $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)->getCacheTags();
256 // Test before there are any nodes.
257 $empty_node_listing_cache_tags = [
258 'config:views.view.frontpage',
262 $render_cache_tags = Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags);
263 $render_cache_tags = Cache::mergeTags($render_cache_tags, ['config:system.site']);
264 $this->assertViewsCacheTags(
266 $empty_node_listing_cache_tags,
267 $do_assert_views_caches,
270 $expected_tags = Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags);
271 $expected_tags = Cache::mergeTags($expected_tags, ['http_response', 'rendered', 'config:user.role.anonymous', 'config:system.site']);
272 $this->assertPageCacheContextsAndTags(
273 Url::fromRoute('view.frontpage.page_1'),
278 // Create some nodes on the frontpage view. Add more than 10 nodes in order
280 $this->drupalCreateContentType(['type' => 'article']);
281 for ($i = 0; $i < 15; $i++) {
282 $node = Node::create([
285 'value' => $this->randomMachineName(32),
286 'format' => filter_default_format(),
291 'title' => $this->randomMachineName(8),
294 $node->enforceIsNew(TRUE);
297 $cache_contexts = Cache::mergeContexts($cache_contexts, [
301 $this->pass('First page');
303 $first_page_result_cache_tags = [
304 'config:views.view.frontpage',
317 $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)->getCacheTags();
318 $first_page_output_cache_tags = Cache::mergeTags($first_page_result_cache_tags, $cache_context_tags);
319 $first_page_output_cache_tags = Cache::mergeTags($first_page_output_cache_tags, [
320 'config:filter.format.plain_text',
326 $view->setDisplay('page_1');
327 $view->setCurrentPage(0);
328 $this->assertViewsCacheTags(
330 $first_page_result_cache_tags,
331 $do_assert_views_caches,
332 $first_page_output_cache_tags
334 $this->assertPageCacheContextsAndTags(
335 Url::fromRoute('view.frontpage.page_1'),
337 Cache::mergeTags($first_page_output_cache_tags, ['http_response', 'rendered', 'config:user.role.anonymous'])
341 $this->pass('Second page');
342 $this->assertPageCacheContextsAndTags(Url::fromRoute('view.frontpage.page_1', [], ['query' => ['page' => 1]]), $cache_contexts, [
343 // The cache tags for the listed nodes.
350 'config:filter.format.plain_text',
351 'config:views.view.frontpage',
358 // FinishResponseSubscriber adds this cache tag to responses that have the
359 // 'user.permissions' cache context for anonymous users.
360 'config:user.role.anonymous',
363 // Let's update a node title on the first page and ensure that the page
364 // cache entry invalidates.
365 $node = Node::load(10);
366 $title = $node->getTitle() . 'a';
367 $node->setTitle($title);
370 $this->drupalGet(Url::fromRoute('view.frontpage.page_1'));
371 $this->assertText($title);