<?php declare(strict_types=1); namespace Drupal\Tests\node\Functional; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\node\NodeInterface; use Drupal\user\UserInterface; /** * Tests making node base fields' displays configurable. * * @group node */ class NodeDisplayConfigurableTest extends NodeTestBase { /** * {@inheritdoc} */ protected static $modules = ['block']; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * Sets base fields to configurable display and check settings are respected. * * @param string $theme * The name of the theme being tested. * @param string $metadata_region * The region of the node html content where meta data is expected. * @param bool $field_classes * If TRUE, check for field--name-XXX classes. * * @dataProvider provideThemes */ public function testDisplayConfigurable(string $theme, string $metadata_region, bool $field_classes): void { \Drupal::service('theme_installer')->install([$theme]); $this->config('system.theme')->set('default', $theme)->save(); $settings = [ 'theme' => $theme, 'region' => 'content', 'weight' => -100, ]; $this->drupalPlaceBlock('page_title_block', $settings); // Change the node type setting to show submitted by information. $node_type = \Drupal::entityTypeManager()->getStorage('node_type')->load('page'); $node_type->setDisplaySubmitted(TRUE); $node_type->save(); $user = $this->drupalCreateUser([ 'administer nodes', ], $this->randomMachineName(14)); $this->drupalLogin($user); $node = $this->drupalCreateNode(['uid' => $user->id()]); $assert = $this->assertSession(); // Check the node with Drupal default non-configurable display. $this->drupalGet($node->toUrl()); $this->assertNodeHtml($node, $user, TRUE, $metadata_region, $field_classes, $field_classes); // Enable module to make base fields' displays configurable. \Drupal::service('module_installer')->install(['node_display_configurable_test']); // Configure display. $display = EntityViewDisplay::load('node.page.default'); $display->setComponent('uid', [ 'type' => 'entity_reference_label', 'label' => 'above', 'settings' => ['link' => FALSE], ]) ->removeComponent('title') ->save(); // Recheck the node with configurable display. $this->drupalGet($node->toUrl()); $this->assertNodeHtml($node, $user, FALSE, $metadata_region, $field_classes, FALSE); // Remove from display. $display->removeComponent('uid') ->removeComponent('created') ->save(); $this->drupalGet($node->toUrl()); $assert->elementTextNotContains('css', 'article', $user->getAccountName()); } /** * Asserts that the node HTML is as expected. * * @param \Drupal\node\NodeInterface $node * The node being tested. * @param \Drupal\user\UserInterface $user * The logged in user. * @param bool $is_inline * Whether the fields are rendered inline or not. * @param string $metadata_region * The region of the node html content where meta data is expected. * @param bool $field_classes * If TRUE, check for field--name-XXX classes on created/uid fields. * @param bool $title_classes * If TRUE, check for field--name-XXX classes on title field. * * @internal */ protected function assertNodeHtml(NodeInterface $node, UserInterface $user, bool $is_inline, string $metadata_region, bool $field_classes, bool $title_classes): void { $assert = $this->assertSession(); $html_element = $is_inline ? 'span' : 'div'; $title_selector = 'h1 span' . ($title_classes ? '.field--name-title' : ''); $assert->elementTextContains('css', $title_selector, $node->getTitle()); // With field classes, the selector can be very specific. if ($field_classes) { $created_selector = 'article ' . $html_element . '.field--name-created'; $assert->elementTextContains('css', $created_selector, \Drupal::service('date.formatter')->format($node->getCreatedTime())); } else { // When field classes aren't available, use HTML elements for testing. $formatted_time = \Drupal::service('date.formatter')->format($node->getCreatedTime()); if ($is_inline) { $created_selector = sprintf('//article//%s//%s/time[text()="%s"]', $metadata_region, $html_element, $formatted_time); } else { $created_selector = sprintf('//article//%s//%s/time[text()="%s"]', $html_element, $html_element, $formatted_time); } $assert->elementExists('xpath', $created_selector); } $uid_selector = 'article ' . $html_element . ($field_classes ? '.field--name-uid' : ''); if (!$is_inline) { $field_classes_selector = $field_classes ? "[contains(concat(' ', normalize-space(@class), ' '), ' field--name-uid ')]" : ''; $assert->elementExists('xpath', sprintf('//article//%s//*%s//%s[text()="Authored by"]', $html_element, $field_classes_selector, $html_element)); $assert->elementTextContains('css', $uid_selector, $user->getAccountName()); $assert->elementNotExists('css', "$uid_selector a"); if ($field_classes) { $assert->elementExists('css', $created_selector); } } else { $assert->elementTextContains('css', $uid_selector . ' a', $user->getAccountName()); $assert->elementTextContains('css', 'article ' . $metadata_region, 'Submitted by'); } } /** * Data provider for ::testDisplayConfigurable(). * * @return array * An array of test cases. */ public static function provideThemes() { return [ ['claro', 'footer', TRUE], // @todo Add coverage for olivero after fixing // https://www.drupal.org/project/drupal/issues/3215220. // ['olivero', 'footer', TRUE], ['stable9', 'footer', FALSE], ]; } }