PromotedContentPageTest.php

Namespace

Drupal\Tests\node\Functional\Views

File

core/modules/node/tests/src/Functional/Views/PromotedContentPageTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\node\Functional\Views;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\filter\FilterFormatRepositoryInterface;
use Drupal\node\Entity\Node;
use Drupal\Tests\node\Traits\PromotedContentViewTestTrait;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\ResultRow;
use Drupal\views\Tests\AssertViewsCacheTagsTrait;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

/**
 * Tests the promoted content view provided with views.
 */
class PromotedContentPageTest extends ViewTestBase {
  use AssertPageCacheContextsAndTagsTrait;
  use AssertViewsCacheTagsTrait;
  use PromotedContentViewTestTrait;
  
  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';
  
  /**
   * The entity storage for nodes.
   *
   * @var \Drupal\node\NodeStorage
   */
  protected $nodeStorage;
  
  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'node',
    'contextual',
  ];
  
  /**
   * {@inheritdoc}
   */
  protected function setUp($import_test_views = TRUE, $modules = []) : void {
    parent::setUp($import_test_views, $modules);
    $this->nodeStorage = $this->container
      ->get('entity_type.manager')
      ->getStorage('node');
    $this->enablePromotedContentView();
  }
  
  /**
   * Tests the promoted content view.
   */
  public function testPromotedContentPage() : void {
    $site_name = $this->randomMachineName();
    $this->config('system.site')
      ->set('name', $site_name)
      ->save();
    $view = Views::getView('promoted_content');
    // Tests
    // \Drupal\node\Plugin\views\row\RssPluginBase::calculateDependencies().
    $expected = [
      'config' => [
        'core.entity_view_mode.node.rss',
        'core.entity_view_mode.node.teaser',
      ],
      'module' => [
        'node',
        'user',
      ],
    ];
    $this->assertSame($expected, $view->getDependencies());
    $view->destroy();
    // Create some nodes on the promoted_content view. Add more than 10 nodes in order
    // to enable paging.
    $expected = [];
    for ($i = 0; $i < 20; $i++) {
      $values = [];
      $values['type'] = 'article';
      $values['title'] = $this->randomMachineName();
      $values['promote'] = TRUE;
      $values['status'] = TRUE;
      // Test descending sort order.
      $values['created'] = \Drupal::time()->getRequestTime() - $i;
      // Test the sticky order.
      if ($i == 5) {
        $values['sticky'] = TRUE;
        $node = $this->nodeStorage
          ->create($values);
        $node->save();
        // Put the sticky on at the front.
        array_unshift($expected, [
          'nid' => $node->id(),
        ]);
      }
      else {
        $values['sticky'] = FALSE;
        $node = $this->nodeStorage
          ->create($values);
        $node->save();
        array_push($expected, [
          'nid' => $node->id(),
        ]);
      }
    }
    // Create some nodes which aren't on the promoted_content, either because they
    // aren't promoted or because they aren't published.
    $not_expected_nids = [];
    $values = [];
    $values['type'] = 'article';
    $values['title'] = $this->randomMachineName();
    $values['status'] = TRUE;
    $values['promote'] = FALSE;
    $node = $this->nodeStorage
      ->create($values);
    $node->save();
    $not_expected_nids[] = $node->id();
    $values['promote'] = TRUE;
    $values['status'] = FALSE;
    $values['title'] = $this->randomMachineName();
    $node = $this->nodeStorage
      ->create($values);
    $node->save();
    $not_expected_nids[] = $node->id();
    $values['promote'] = TRUE;
    $values['sticky'] = TRUE;
    $values['status'] = FALSE;
    $values['title'] = $this->randomMachineName();
    $node = $this->nodeStorage
      ->create($values);
    $node->save();
    $not_expected_nids[] = $node->id();
    $column_map = [
      'nid' => 'nid',
    ];
    $view->setDisplay('page_1');
    $this->executeView($view);
    $this->assertIdenticalResultset($view, array_slice($expected, 0, 10), $column_map, 'Ensure that the right nodes are displayed on the promoted_content.');
    $this->assertNotInResultSet($view, $not_expected_nids, 'Ensure no unexpected node is in the result.');
    $view->destroy();
    $view->setDisplay('page_1');
    $view->setCurrentPage(1);
    $this->executeView($view);
    $this->assertIdenticalResultset($view, array_slice($expected, 10, 10), $column_map, 'Ensure that the right nodes are displayed on second page of the promoted_content.');
    $this->assertNotInResultSet($view, $not_expected_nids, 'Ensure no unexpected node is in the result.');
    $view->destroy();
  }
  
  /**
   * Verifies that an amount of nids aren't in the result.
   *
   * @param \Drupal\views\ViewExecutable $view
   *   An executed View.
   * @param array $not_expected_nids
   *   An array of nids which should not be part of the resultset.
   * @param string $message
   *   (optional) A custom message to display with the assertion.
   *
   * @internal
   */
  protected function assertNotInResultSet(ViewExecutable $view, array $not_expected_nids, string $message = '') : void {
    $found_nids = array_filter($view->result, function (ResultRow $row) use ($not_expected_nids) : bool {
      return in_array($row->nid, $not_expected_nids);
    });
    $this->assertEmpty($found_nids, $message);
  }
  
  /**
   * Tests the cache tags when using the "none" cache plugin.
   */
  public function testCacheTagsWithCachePluginNone() : void {
    $this->enablePageCaching();
    $this->doTestPromotedContentPageViewCacheTags(FALSE);
  }
  
  /**
   * Tests the cache tags when using the "tag" cache plugin.
   */
  public function testCacheTagsWithCachePluginTag() : void {
    $this->enablePageCaching();
    $view = Views::getView('promoted_content');
    $view->setDisplay('page_1');
    $view->display_handler
      ->overrideOption('cache', [
      'type' => 'tag',
    ]);
    $view->save();
    $this->doTestPromotedContentPageViewCacheTags(TRUE);
  }
  
  /**
   * Tests the cache tags when using the "time" cache plugin.
   */
  public function testCacheTagsWithCachePluginTime() : void {
    $this->enablePageCaching();
    $view = Views::getView('promoted_content');
    $view->setDisplay('page_1');
    $view->display_handler
      ->overrideOption('cache', [
      'type' => 'time',
      'options' => [
        'results_lifespan' => 3600,
        'output_lifespan' => 3600,
      ],
    ]);
    $view->save();
    $this->doTestPromotedContentPageViewCacheTags(TRUE);
  }
  
  /**
   * Tests the cache tags on the promoted content page.
   *
   * @param bool $do_assert_views_caches
   *   Whether to check Views' result & output caches.
   */
  protected function doTestPromotedContentPageViewCacheTags($do_assert_views_caches) : void {
    $view = Views::getView('promoted_content');
    $view->setDisplay('page_1');
    $cache_contexts = [
      // Cache contexts associated with the view.
'user.node_grants:view',
      'languages:' . LanguageInterface::TYPE_INTERFACE,
      // Cache contexts associated with the route's access checking.
'user.permissions',
      // Default cache contexts of the renderer.
'theme',
      'url.query_args',
      // Attached feed.
'url.site',
    ];
    $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)
      ->getCacheTags();
    // Test before there are any nodes.
    $empty_node_listing_cache_tags = [
      'config:views.view.promoted_content',
      'node_list',
    ];
    $render_cache_tags = Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags);
    $this->assertViewsCacheTags($view, $empty_node_listing_cache_tags, $do_assert_views_caches, $render_cache_tags);
    $expected_tags = Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags);
    $expected_tags = Cache::mergeTags($expected_tags, [
      'http_response',
      'rendered',
      'config:user.role.anonymous',
    ]);
    $this->assertPageCacheContextsAndTags(Url::fromRoute('view.promoted_content.page_1'), $cache_contexts, $expected_tags);
    // Create some nodes on the promoted_content view. Add more than 10 nodes in order
    // to enable paging.
    $this->drupalCreateContentType([
      'type' => 'article',
    ]);
    for ($i = 0; $i < 15; $i++) {
      $node = Node::create([
        'body' => [
          [
            'value' => $this->randomMachineName(32),
            'format' => \Drupal::service(FilterFormatRepositoryInterface::class)->getDefaultFormat()
              ->id(),
          ],
        ],
        'type' => 'article',
        'created' => $i,
        'title' => $this->randomMachineName(8),
        'nid' => $i + 1,
        'promote' => TRUE,
      ]);
      $node->enforceIsNew(TRUE);
      $node->save();
    }
    $cache_contexts = Cache::mergeContexts($cache_contexts, [
      'timezone',
    ]);
    // First page.
    $first_page_result_cache_tags = [
      'config:views.view.promoted_content',
      'node_list',
      'node:6',
      'node:7',
      'node:8',
      'node:9',
      'node:10',
      'node:11',
      'node:12',
      'node:13',
      'node:14',
      'node:15',
    ];
    $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)
      ->getCacheTags();
    $first_page_output_cache_tags = Cache::mergeTags($first_page_result_cache_tags, $cache_context_tags);
    $first_page_output_cache_tags = Cache::mergeTags($first_page_output_cache_tags, [
      'config:filter.format.plain_text',
      'node_view',
      'user_view',
      'user:0',
    ]);
    $view->setDisplay('page_1');
    $view->setCurrentPage(0);
    $this->assertViewsCacheTags($view, $first_page_result_cache_tags, $do_assert_views_caches, $first_page_output_cache_tags);
    $this->assertPageCacheContextsAndTags(Url::fromRoute('view.promoted_content.page_1'), $cache_contexts, Cache::mergeTags($first_page_output_cache_tags, [
      'http_response',
      'rendered',
      'config:user.role.anonymous',
    ]));
    // Second page.
    $this->assertPageCacheContextsAndTags(Url::fromRoute('view.promoted_content.page_1', [], [
      'query' => [
        'page' => 1,
      ],
    ]), $cache_contexts, [
      // The cache tags for the listed nodes.
'node:1',
      'node:2',
      'node:3',
      'node:4',
      'node:5',
      // The rest.
'config:filter.format.plain_text',
      'config:views.view.promoted_content',
      'node_list',
      'node_view',
      'user_view',
      'user:0',
      'http_response',
      'rendered',
      // FinishResponseSubscriber adds this cache tag to responses that have the
      // 'user.permissions' cache context for anonymous users.
'config:user.role.anonymous',
    ]);
    // Let's update a node title on the first page and ensure that the page
    // cache entry invalidates.
    $node = Node::load(10);
    $title = $node->getTitle() . 'a';
    $node->setTitle($title);
    $node->save();
    $this->drupalGet(Url::fromRoute('view.promoted_content.page_1'));
    $this->assertSession()
      ->pageTextContains($title);
  }

}

Classes

Title Deprecated Summary
PromotedContentPageTest Tests the promoted content view provided with views.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.