smart_trim-8.x-1.3/tests/src/Functional/SmartTrimFunctionalTest.php
tests/src/Functional/SmartTrimFunctionalTest.php
<?php declare(strict_types=1); namespace Drupal\Tests\smart_trim\Functional; use Drupal\Core\Session\AccountInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\BrowserTestBase; /** * This class provides methods specifically for testing something. * * @group smart_trim */ class SmartTrimFunctionalTest extends BrowserTestBase { /** * {@inheritdoc} */ protected static $modules = [ 'node', 'test_page_test', 'field', 'filter', 'text', 'token', 'token_filter', 'smart_trim', 'filter_test', 'field_ui', ]; /** * A user with authenticated permissions. * * @var \Drupal\Core\Session\AccountInterface */ protected AccountInterface $user; /** * A user with admin permissions. * * @var \Drupal\Core\Session\AccountInterface */ protected AccountInterface $adminUser; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->createContentType(['type' => 'article', 'name' => 'Article']); $this->config('system.site')->set('page.front', '/test-page')->save(); $this->user = $this->drupalCreateUser(); $this->adminUser = $this->drupalCreateUser(); $this->adminUser->addRole($this->createAdminRole('admin', 'admin')); $this->adminUser->save(); $this->drupalLogin($this->adminUser); $this->drupalCreateNode([ 'title' => $this->randomString(), 'id' => 1, 'type' => 'article', 'body' => [ 'value' => "Test [node:content-type]\r\n ", 'format' => 'filter_test', ], ])->save(); $this->drupalCreateNode([ 'title' => $this->randomString(), 'id' => 2, 'type' => 'article', 'body' => [ 'value' => '<h3>The situation</h3><p>is dire</p><p>& there is no hope.</p><p>Full stop should not be preceded by <em>space</em>. Really, they should not be.</p>', 'format' => 'filter_test', ], ])->save(); NodeType::create(['type' => 'plain_text_test', 'name' => 'Plain text test'])->save(); // Create Description field. FieldStorageConfig::create([ 'field_name' => 'field_plain_text', 'type' => 'string_long', 'entity_type' => 'node', 'cardinality' => 1, ])->save(); FieldConfig::create([ 'field_name' => 'field_plain_text', 'entity_type' => 'node', 'bundle' => 'plain_text_test', 'label' => 'Plain text test field', ])->save(); $node = Node::create([ 'type' => 'plain_text_test', 'id' => 3, 'title' => $this->randomString(), 'field_plain_text' => 'This is a really long string with Fire & ice right in the middle of it.', ]); $node->save(); } /** * Tests if installing the module, won't break the site. */ public function testInstallation() :void { $session = $this->assertSession(); $this->drupalGet('<front>'); // Ensure the status code is success: $session->statusCodeEquals(200); // Ensure the correct test page is loaded as front page: $session->pageTextContains('Test page text.'); } /** * Tests if uninstalling the module, won't break the site. */ public function testUninstallation(): void { // Go to uninstallation page to uninstall smart_trim. $session = $this->assertSession(); $page = $this->getSession()->getPage(); $this->drupalGet('/admin/modules/uninstall'); $session->statusCodeEquals(200); $page->checkField('edit-uninstall-smart-trim'); $page->pressButton('edit-submit'); $session->statusCodeEquals(200); // Confirm uninstall. $page->pressButton('edit-submit'); $session->statusCodeEquals(200); $session->pageTextContains('The selected modules have been uninstalled.'); // Retest the frontpage. $this->drupalGet('<front>'); // Ensure the status code is success. $session->statusCodeEquals(200); // Ensure the correct test page is loaded as front page. $session->pageTextContains('Test page text.'); } /** * Tests if the token will not get cut off when trimming by characters. */ public function testTokenNotCutOffTrimTypeCharacters(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); // Editing our "filter_test" format: $edit = [ 'edit-filters-token-filter-status' => 1, 'edit-filters-filter-html-escape-status' => 0, ]; $this->drupalGet('admin/config/content/formats/manage/filter_test'); $this->submitForm($edit, 'Save configuration'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'chars', 'summary_handler' => 'trim', 'trim_options' => [ 'replace_tokens' => TRUE, ], ], ]) ->save(); $this->drupalGet('/node/1'); // @todo This might change to "Test Article" in the future, because the // "trim_type" is a bit confusing, see // https://www.drupal.org/project/smart_trim/issues/3308868. $session->elementTextEquals('css', 'article > div > div > div:nth-child(2) > p', 'Test'); } /** * Tests if the token will not get cut off when trimming by words. */ public function testTokenNotCutOffTrimTypeWords(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); // Editing our "filter_test" format: $edit = [ 'edit-filters-token-filter-status' => 1, 'edit-filters-filter-html-escape-status' => 0, ]; $this->drupalGet('admin/config/content/formats/manage/filter_test'); $this->submitForm($edit, 'Save configuration'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'summary_handler' => 'trim', 'trim_options' => [ 'replace_tokens' => TRUE, ], ], ]) ->save(); $this->drupalGet('/node/1'); $session->elementTextEquals('css', 'article > div > div > div:nth-child(2) > p', 'Test Article'); } /** * Tests the Strip HTML option. */ public function testStripHtml(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 7, 'trim_type' => 'words', 'summary_handler' => 'trim', 'trim_options' => [ 'text' => TRUE, ], ], ]) ->save(); $this->drupalGet('/node/2'); $session->elementTextEquals('css', 'article > div > div > div:nth-child(2) > p', 'The situation is dire & there is'); } /** * Test to ensure no extra spaces before punctuation. * * See https://www.drupal.org/project/smart_trim/issues/3369954. */ public function testNoExtraSpaces(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 18, 'trim_type' => 'words', 'summary_handler' => 'trim', 'trim_options' => [ 'text' => TRUE, ], ], ]) ->save(); $this->drupalGet('/node/2'); $session->elementTextEquals('css', 'article > div > div > div:nth-child(2) > p', 'The situation is dire & there is no hope. Full stop should not be preceded by space. Really'); } /** * Tests the formatter settings summary. * * @covers \Drupal\smart_trim\Plugin\Field\FieldFormatter\SmartTrimFormatter::settingsSummary * * @test */ public function testFormatterSettingsSummary(): void { /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */ $display_repository = \Drupal::service('entity_display.repository'); // Check summary with minimal settings and not more link. $display_repository->getViewDisplay('node', 'article', 'default') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 100, 'trim_type' => 'chars', 'more' => [ 'display_link' => FALSE, ], 'trim_options' => [], ], ]) ->save(); $this->drupalGet('admin/structure/types/manage/article/display'); $this->assertSession()->responseContains('100 characters'); $this->assertSession()->responseNotContains('Suffix:'); $this->assertSession()->responseNotContains('<em>More</em> link enabled'); $this->assertSession()->responseNotContains('Only display <em>More</em> link when trimmed'); $this->assertSession()->responseNotContains('Open <em>More</em> link in new window'); $this->assertSession()->responseNotContains('<em>More</em> link aria-label:'); $this->assertSession()->responseNotContains('<em>More</em> link class:'); $this->assertSession()->responseNotContains('Strip HTML'); $this->assertSession()->responseNotContains('Honor a zero trim length'); $this->assertSession()->responseNotContains('Replace tokens before trimming'); // Check summary with 15 words, a suffix, default more link settings, and // strip HTML checked. $display_repository->getViewDisplay('node', 'article', 'default') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 15, 'trim_type' => 'words', 'trim_suffix' => '- - -', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], 'trim_options' => ['text' => 1], ], ]) ->save(); $this->drupalGet('admin/structure/types/manage/article/display'); $this->assertSession()->responseContains('15 words'); $this->assertSession()->responseContains('Suffix: <em class="placeholder">- - -</em>'); $this->assertSession()->responseContains('<em>More</em> link enabled, text: <em class="placeholder">More</em>'); $this->assertSession()->responseNotContains('Only display <em>More</em> link when trimmed'); $this->assertSession()->responseNotContains('Open <em>More</em> link in new window'); $this->assertSession()->responseContains('<em>More</em> link aria-label: <em class="placeholder">Read more about [node:title]</em>'); $this->assertSession()->responseContains('<em>More</em> link class: <em class="placeholder">more-link</em>'); $this->assertSession()->responseContains('Strip HTML'); $this->assertSession()->responseNotContains('Honor a zero trim length'); $this->assertSession()->responseNotContains('Replace tokens before trimming'); // Check summary with 99 chars, no suffix, customized more settings, and // honor zero length and apply tokens before checked. $display_repository->getViewDisplay('node', 'article', 'default') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 99, 'trim_type' => 'chars', 'more' => [ 'display_link' => TRUE, 'class' => 'blah-link', 'link_trim_only' => TRUE, 'target_blank' => TRUE, 'text' => 'Blah', 'aria_label' => 'Blah blah blah [node:title]', ], 'trim_options' => [ 'trim_zero' => 1, 'replace_tokens' => 1, ], ], ]) ->save(); $this->drupalGet('admin/structure/types/manage/article/display'); $this->assertSession()->responseContains('99 characters'); $this->assertSession()->responseNotContains('Suffix:'); $this->assertSession()->responseContains('<em>More</em> link enabled, text: <em class="placeholder">Blah</em>'); $this->assertSession()->responseContains('Only display <em>More</em> link when trimmed'); $this->assertSession()->responseContains('Open <em>More</em> link in new window'); $this->assertSession()->responseContains('<em>More</em> link aria-label: <em class="placeholder">Blah blah blah [node:title]</em>'); $this->assertSession()->responseContains('<em>More</em> link class: <em class="placeholder">blah-link</em>'); $this->assertSession()->responseNotContains('Strip HTML'); $this->assertSession()->responseContains('Honor a zero trim length'); $this->assertSession()->responseContains('Replace tokens before trimming'); } /** * Tests the more link displays when option selected. * * @test */ public function testMoreLink(): void { $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 6, 'trim_type' => 'words', 'summary_handler' => 'trim', 'more' => [ 'display_link' => FALSE, ], ], ]) ->save(); $this->drupalGet('/node/1'); $query = $this->xpath('//a[text() = "More"]'); $this->assertEmpty($query, 'Expected zero "More" links.'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 6, 'trim_type' => 'words', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); $this->drupalGet('/node/1'); $query = $this->xpath('//a[text() = "More"]'); $this->assertCount(1, $query, 'Expected 1 "More" link.'); } /** * Tests that when "wrap output" is selected, wrapper class is output. */ public function testWrapperClass() { $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings, specify no wrapper: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'wrap_output' => FALSE, 'summary_handler' => 'trim', 'more' => [ 'display_link' => FALSE, ], ], ]) ->save(); // Confirm no wrapper class present. $this->drupalGet('/node/1'); $query = $this->xpath('//div[contains(@class, "trimmed")]'); $this->assertEquals(0, count($query)); // Find div following "Body" label. $query = $this->xpath('//div[text() = "Body"]/following-sibling::div'); $this->assertEquals('Test [node:content-type]', $query[0]->getText()); // Edit formatter settings to use wrapper div and class. $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'wrap_output' => TRUE, 'wrap_class' => 'trimmed', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); // Check that wrapper class present in output. $this->drupalGet('/node/1'); $query = $this->xpath('//div[contains(@class, "trimmed")]'); $this->assertEquals(1, count($query)); } /** * Tests wrapper class applied to more link when present. */ public function testMoreLinkWrapperClass() { $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings, specify no wrapper: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'wrap_output' => FALSE, 'summary_handler' => 'trim', 'more' => [ 'display_link' => FALSE, ], ], ]) ->save(); // Confirm that when more link not shown, more wrapper not in content. $this->drupalGet('/node/1'); $query = $this->xpath('//div[contains(@class, "more-link")]'); $this->assertEquals(0, count($query)); // Edit formatter settings to display more link wrapper class. $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'wrap_output' => FALSE, 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); // Check that default more link wrapper class present in output. $this->drupalGet('/node/1'); $query = $this->xpath('//div[contains(@class, "more-link")]'); $this->assertEquals(1, count($query)); // Edit formatter settings with custom more link wrapper class. $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'wrap_output' => FALSE, 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-wrapper', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); // Check that default more link wrapper class not present. $this->drupalGet('/node/1'); $query = $this->xpath('//div[contains(@class, "more-link")]'); $this->assertEquals(0, count($query)); // Check that modified more link wrapper class present in output. $query = $this->xpath('//div[contains(@class, "more-wrapper")]'); $this->assertEquals(1, count($query)); } /** * Tests the more link's "open in a new window" configuration. */ public function testOpenInNewWindow() { $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 6, 'trim_type' => 'words', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => TRUE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); // Verify more link specifies target: _blank. $this->drupalGet('/node/1'); $query = $this->xpath('//a[text() = "More"]'); $this->assertEquals('_blank', $query[0]->getAttribute('target')); // Edit formatter settings: $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => FALSE, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); // Verify target not present. $this->drupalGet('/node/1'); $query = $this->xpath('//a[text() = "More"]'); $this->assertNull($query[0]->getAttribute('target')); } /** * Tests the "More link only when content is trimmed" formatter config option. */ public function testMoreLinkOnlyWhenContentIsTrimmed(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 100, 'trim_type' => 'chars', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => TRUE, 'target_blank' => 0, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); $this->drupalGet('/node/1'); $session->linkNotExists('More'); $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 5, 'trim_type' => 'chars', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => TRUE, 'target_blank' => 0, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); $this->drupalGet('/node/1'); $session->linkExists('More'); $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 100, 'trim_type' => 'chars', 'summary_handler' => 'trim', 'more' => [ 'display_link' => TRUE, 'class' => 'more-link', 'link_trim_only' => FALSE, 'target_blank' => 0, 'text' => 'More', 'aria_label' => 'Read more about [node:title]', ], ], ]) ->save(); $this->drupalGet('/node/1'); $session->linkExists('More'); } /** * Tests that HTML entities are handled correctly. * * @test */ public function testHtmlEntities(): void { $session = $this->assertSession(); $display_repository = \Drupal::service('entity_display.repository'); // Edit formatter settings: $display_repository->getViewDisplay('node', 'plain_text_test') ->setComponent('field_plain_text', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 10, 'trim_type' => 'words', 'summary_handler' => 'ignore', 'more' => [ 'display_link' => FALSE, ], ], ]) ->save(); $this->drupalGet('/node/3'); $session->pageTextContains('Fire & ice'); $display_repository->getViewDisplay('node', 'article') ->setComponent('body', [ 'type' => 'smart_trim', 'settings' => [ 'trim_length' => 30, 'trim_type' => 'chars', 'summary_handler' => 'trim', 'more' => [ 'display_link' => FALSE, ], ], ]) ->save(); $this->drupalGet('/node/2'); $session->pageTextContains('& there'); } }