Loading config/schema/link_description.schema.yml 0 → 100644 +95 −0 Original line number Diff line number Diff line # Schema for the configuration files of the Link description module. field.formatter.settings.link_description: type: mapping label: 'Link description format settings' mapping: trim_length: type: integer label: 'Trim link text length' url_only: type: boolean label: 'URL only' url_plain: type: boolean label: 'Show URL as plain text' rel: type: string label: 'Add rel="nofollow" to links' target: type: string label: 'Open link in new window' field.formatter.settings.link_separate_description: type: field.formatter.settings.link_description label: 'Link description format settings' field.widget.settings.link_description: type: mapping label: 'Link description widget settings' mapping: placeholder_url: type: string label: 'Placeholder for URL' placeholder_title: type: label label: 'Placeholder for link text' field.storage_settings.link_description: type: mapping label: 'Link description settings' field.field_settings.link_description: type: mapping label: 'Link description settings' mapping: title: type: integer label: 'Allow link text' link_type: type: integer label: 'Allowed link type' field.value.link_description: type: mapping label: 'Default value' mapping: attributes: type: mapping label: 'Link attributes' mapping: title: type: label label: 'Link text' uri: type: string label: 'URL' title: type: label label: 'Link text' description: type: string label: 'Link description' options: type: mapping label: 'Link options' mapping: query: type: sequence label: 'URL query key value pairs' sequence: type: string fragment: type: string label: 'URL fragment' absolute: type: boolean label: 'Whether to force the output to be an absolute link (beginning with http: or https:)' https: type: boolean label: 'Whether to force this URL to point to a secure location (beginning with https:)' attributes: type: sequence label: 'Link attributes' sequence: type: string tests/src/Functional/LinkDescriptionFieldFormattersTest.php 0 → 100644 +286 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; use Drupal\entity_test\Entity\EntityTest; /** * Tests link description field formatters. * * @group link_description */ class LinkDescriptionFieldFormattersTest extends LinkDescriptionFieldTestBase { /** * Tests the 'link_description' formatter. * * Rework of the test from Drupal\Tests\link\Functional\LinkFieldTest. */ public function testLinkDescriptionFormatter() { $display_options = [ 'type' => 'link_description', 'label' => 'hidden', ]; $this->setViewDisplayOptions($display_options); // Create an entity with three link field values: // The first field item uses a URL only. // The second field item uses URL, link text. // The third field item uses a fragment-only URL with text and description. $this->drupalGet('entity_test/add'); $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; $url3 = '#net'; $title1 = $url1; // Intentionally contains an ampersand that needs sanitization on output. $title2 = 'A very long & strange example title that could break the nice layout of the site'; $title3 = 'Fragment only'; $edit = [ "{$this->fieldName}[0][uri]" => $url1, "{$this->fieldName}[1][uri]" => $url2, "{$this->fieldName}[1][title]" => $title2, "{$this->fieldName}[2][uri]" => $url3, "{$this->fieldName}[2][title]" => $title3, "{$this->fieldName}[2][description]" => "Link 1 & &\nLine 2", ]; // Assert label is shown. $this->assertSession()->pageTextContains('Read more about this entity'); $this->submitForm($edit, 'Save'); preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); $id = $match[1]; $this->assertSession()->pageTextContains('entity_test ' . $id . ' has been created.'); $options = [ 'trim_length' => [NULL, 6], 'rel' => [NULL, 'nofollow'], 'target' => [NULL, '_blank'], ]; foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the field formatter settings. $display_options['settings'] = [$setting => $new_value]; $this->setViewDisplayOptions($display_options); $output = $this->renderTestEntity($id); switch ($setting) { case 'trim_length': $url = $url1; $title = isset($new_value) ? Unicode::truncate($title1, $new_value, FALSE, TRUE) : $title1; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url2; $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url3; $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'rel': $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($title1) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($title2) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($title3) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'target': $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($title1) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($title2) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($title3) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; } } } } /** * Tests the 'link_separate_description' formatter. * * Rework of the test from Drupal\Tests\link\Functional\LinkFieldTest. */ public function testLinkSeparateFormatter() { $display_options = [ 'type' => 'link_separate_description', 'label' => 'hidden', ]; $this->setViewDisplayOptions($display_options); // Create an entity with three link field values: // The first field item uses a URL only. // The second field item uses a URL and link text. // The third field item uses a fragment-only URL with text and description. $this->drupalGet('entity_test/add'); $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; $url3 = '#net'; // Intentionally contains an ampersand that needs sanitization on output. $title2 = 'A very long & strange example title that could break the nice layout of the site'; $title3 = 'Fragment only'; $edit = [ "{$this->fieldName}[0][uri]" => $url1, "{$this->fieldName}[1][uri]" => $url2, "{$this->fieldName}[1][title]" => $title2, "{$this->fieldName}[2][uri]" => $url3, "{$this->fieldName}[2][title]" => $title3, "{$this->fieldName}[2][description]" => "Link 1 & &\nLine 2", ]; $this->submitForm($edit, 'Save'); preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); $id = $match[1]; $this->assertSession()->pageTextContains('entity_test ' . $id . ' has been created.'); // Verify that the link is output according to the formatter settings. $options = [ 'trim_length' => [NULL, 6], 'rel' => [NULL, 'nofollow'], 'target' => [NULL, '_blank'], ]; foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the field formatter settings. $display_options['settings'] = [$setting => $new_value]; $this->setViewDisplayOptions($display_options); $output = $this->renderTestEntity($id); switch ($setting) { case 'trim_length': $url = $url1; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url2; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url3; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'rel': $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($url1) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title2) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($url2) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title3) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($url3) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'target': $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($url1) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title2) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($url2) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title3) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($url3) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; } } } } /** * Renders a test_entity and returns the output. * * @param int $id * The test_entity ID to render. * * @return string * The rendered HTML output. */ protected function renderTestEntity($id) { \Drupal::entityTypeManager()->getStorage('entity_test')->resetCache([$id]); $entity = EntityTest::load($id); $display = \Drupal::service('entity_display.repository') ->getViewDisplay($entity->getEntityTypeId(), $entity->bundle(), 'full'); $content = $display->build($entity); $output = \Drupal::service('renderer')->renderRoot($content); return (string) $output; } /** * Sets display options for the test field in the test entity. * * @param array $display_options * Display options. */ protected function setViewDisplayOptions(array $display_options) { \Drupal::service('entity_display.repository') ->getViewDisplay('entity_test', 'entity_test', 'full') ->setComponent($this->fieldName, $display_options) ->save(); } } tests/src/Functional/LinkDescriptionFieldTestBase.php 0 → 100644 +76 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\field\Entity\FieldConfig; use Drupal\link\LinkItemInterface; use Drupal\Tests\BrowserTestBase; use Drupal\field\Entity\FieldStorageConfig; /** * Tests link description field widgets and formatters. * * @group link_description */ abstract class LinkDescriptionFieldTestBase extends BrowserTestBase { /** * {@inheritdoc} */ protected static $modules = [ 'entity_test', 'link_description', ]; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * Link description test field name. * * @var string */ protected $fieldName; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->fieldName = mb_strtolower($this->randomMachineName()); // Create a field with settings to validate. $field_storage = FieldStorageConfig::create([ 'field_name' => $this->fieldName, 'entity_type' => 'entity_test', 'type' => 'link_description', 'cardinality' => 3, ]); $field_storage->save(); FieldConfig::create([ 'field_storage' => $field_storage, 'label' => 'Read more about this entity', 'bundle' => 'entity_test', 'settings' => [ 'title' => DRUPAL_OPTIONAL, 'link_type' => LinkItemInterface::LINK_GENERIC, ], ])->save(); \Drupal::service('entity_display.repository')->getFormDisplay('entity_test', 'entity_test') ->setComponent($this->fieldName, [ 'type' => 'link_description', ]) ->save(); $this->drupalLogin($this->drupalCreateUser([ 'view test entity', 'administer entity_test content', 'link to any page', ])); } } tests/src/Functional/LinkDescriptionFieldWidgetTest.php 0 → 100644 +37 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\entity_test\Entity\EntityTest; /** * Tests link description field widget. * * @group link_description */ class LinkDescriptionFieldWidgetTest extends LinkDescriptionFieldTestBase { /** * Tests 'description' field exists on the 'link_description' widget. */ public function testLinkDescriptionWidget() { $entity_form_builder = \Drupal::service('entity.form_builder'); $form = $entity_form_builder->getForm(EntityTest::create()); $this->assertEquals('textarea', $form[$this->fieldName]['widget'][0]['description']['#type']); $this->assertEquals('Long description', $form[$this->fieldName]['widget'][0]['description']['#title']); $this->assertEmpty($form[$this->fieldName]['widget'][0]['description']['#default_value']); // Assert default value of the link description field. $entity_test = EntityTest::create([ 'name' => $this->randomMachineName(), $this->fieldName => [ 'uri' => 'https://www.example.com', 'title' => 'Example site', 'description' => 'Link description &' ], ]); $entity_test->save(); $form = $entity_form_builder->getForm($entity_test); $this->assertEquals('Link description &', $form[$this->fieldName]['widget'][0]['description']['#default_value']); } } Loading
config/schema/link_description.schema.yml 0 → 100644 +95 −0 Original line number Diff line number Diff line # Schema for the configuration files of the Link description module. field.formatter.settings.link_description: type: mapping label: 'Link description format settings' mapping: trim_length: type: integer label: 'Trim link text length' url_only: type: boolean label: 'URL only' url_plain: type: boolean label: 'Show URL as plain text' rel: type: string label: 'Add rel="nofollow" to links' target: type: string label: 'Open link in new window' field.formatter.settings.link_separate_description: type: field.formatter.settings.link_description label: 'Link description format settings' field.widget.settings.link_description: type: mapping label: 'Link description widget settings' mapping: placeholder_url: type: string label: 'Placeholder for URL' placeholder_title: type: label label: 'Placeholder for link text' field.storage_settings.link_description: type: mapping label: 'Link description settings' field.field_settings.link_description: type: mapping label: 'Link description settings' mapping: title: type: integer label: 'Allow link text' link_type: type: integer label: 'Allowed link type' field.value.link_description: type: mapping label: 'Default value' mapping: attributes: type: mapping label: 'Link attributes' mapping: title: type: label label: 'Link text' uri: type: string label: 'URL' title: type: label label: 'Link text' description: type: string label: 'Link description' options: type: mapping label: 'Link options' mapping: query: type: sequence label: 'URL query key value pairs' sequence: type: string fragment: type: string label: 'URL fragment' absolute: type: boolean label: 'Whether to force the output to be an absolute link (beginning with http: or https:)' https: type: boolean label: 'Whether to force this URL to point to a secure location (beginning with https:)' attributes: type: sequence label: 'Link attributes' sequence: type: string
tests/src/Functional/LinkDescriptionFieldFormattersTest.php 0 → 100644 +286 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; use Drupal\entity_test\Entity\EntityTest; /** * Tests link description field formatters. * * @group link_description */ class LinkDescriptionFieldFormattersTest extends LinkDescriptionFieldTestBase { /** * Tests the 'link_description' formatter. * * Rework of the test from Drupal\Tests\link\Functional\LinkFieldTest. */ public function testLinkDescriptionFormatter() { $display_options = [ 'type' => 'link_description', 'label' => 'hidden', ]; $this->setViewDisplayOptions($display_options); // Create an entity with three link field values: // The first field item uses a URL only. // The second field item uses URL, link text. // The third field item uses a fragment-only URL with text and description. $this->drupalGet('entity_test/add'); $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; $url3 = '#net'; $title1 = $url1; // Intentionally contains an ampersand that needs sanitization on output. $title2 = 'A very long & strange example title that could break the nice layout of the site'; $title3 = 'Fragment only'; $edit = [ "{$this->fieldName}[0][uri]" => $url1, "{$this->fieldName}[1][uri]" => $url2, "{$this->fieldName}[1][title]" => $title2, "{$this->fieldName}[2][uri]" => $url3, "{$this->fieldName}[2][title]" => $title3, "{$this->fieldName}[2][description]" => "Link 1 & &\nLine 2", ]; // Assert label is shown. $this->assertSession()->pageTextContains('Read more about this entity'); $this->submitForm($edit, 'Save'); preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); $id = $match[1]; $this->assertSession()->pageTextContains('entity_test ' . $id . ' has been created.'); $options = [ 'trim_length' => [NULL, 6], 'rel' => [NULL, 'nofollow'], 'target' => [NULL, '_blank'], ]; foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the field formatter settings. $display_options['settings'] = [$setting => $new_value]; $this->setViewDisplayOptions($display_options); $output = $this->renderTestEntity($id); switch ($setting) { case 'trim_length': $url = $url1; $title = isset($new_value) ? Unicode::truncate($title1, $new_value, FALSE, TRUE) : $title1; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url2; $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url3; $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'rel': $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($title1) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($title2) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($title3) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'target': $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($title1) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($title2) . '</a>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($title3) . '</a>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; } } } } /** * Tests the 'link_separate_description' formatter. * * Rework of the test from Drupal\Tests\link\Functional\LinkFieldTest. */ public function testLinkSeparateFormatter() { $display_options = [ 'type' => 'link_separate_description', 'label' => 'hidden', ]; $this->setViewDisplayOptions($display_options); // Create an entity with three link field values: // The first field item uses a URL only. // The second field item uses a URL and link text. // The third field item uses a fragment-only URL with text and description. $this->drupalGet('entity_test/add'); $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; $url3 = '#net'; // Intentionally contains an ampersand that needs sanitization on output. $title2 = 'A very long & strange example title that could break the nice layout of the site'; $title3 = 'Fragment only'; $edit = [ "{$this->fieldName}[0][uri]" => $url1, "{$this->fieldName}[1][uri]" => $url2, "{$this->fieldName}[1][title]" => $title2, "{$this->fieldName}[2][uri]" => $url3, "{$this->fieldName}[2][title]" => $title3, "{$this->fieldName}[2][description]" => "Link 1 & &\nLine 2", ]; $this->submitForm($edit, 'Save'); preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); $id = $match[1]; $this->assertSession()->pageTextContains('entity_test ' . $id . ' has been created.'); // Verify that the link is output according to the formatter settings. $options = [ 'trim_length' => [NULL, 6], 'rel' => [NULL, 'nofollow'], 'target' => [NULL, '_blank'], ]; foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the field formatter settings. $display_options['settings'] = [$setting => $new_value]; $this->setViewDisplayOptions($display_options); $output = $this->renderTestEntity($id); switch ($setting) { case 'trim_length': $url = $url1; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url2; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $url = $url3; $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'rel': $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($url1) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title2) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($url2) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title3) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($url3) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; case 'target': $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; $expected = '<div class="link-item">'; $expected .= '<div class="link-url"><a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($url1) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title2) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($url2) . '</a></div>'; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); $expected = '<div class="link-item">'; $expected .= '<div class="link-title">' . Html::escape($title3) . '</div>'; $expected .= '<div class="link-url"><a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($url3) . '</a></div>'; $expected .= "<p class=\"link-description\">Link 1 & &amp;<br />\nLine 2</p>"; $expected .= '</div>'; $this->assertStringContainsString($expected, $output); break; } } } } /** * Renders a test_entity and returns the output. * * @param int $id * The test_entity ID to render. * * @return string * The rendered HTML output. */ protected function renderTestEntity($id) { \Drupal::entityTypeManager()->getStorage('entity_test')->resetCache([$id]); $entity = EntityTest::load($id); $display = \Drupal::service('entity_display.repository') ->getViewDisplay($entity->getEntityTypeId(), $entity->bundle(), 'full'); $content = $display->build($entity); $output = \Drupal::service('renderer')->renderRoot($content); return (string) $output; } /** * Sets display options for the test field in the test entity. * * @param array $display_options * Display options. */ protected function setViewDisplayOptions(array $display_options) { \Drupal::service('entity_display.repository') ->getViewDisplay('entity_test', 'entity_test', 'full') ->setComponent($this->fieldName, $display_options) ->save(); } }
tests/src/Functional/LinkDescriptionFieldTestBase.php 0 → 100644 +76 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\field\Entity\FieldConfig; use Drupal\link\LinkItemInterface; use Drupal\Tests\BrowserTestBase; use Drupal\field\Entity\FieldStorageConfig; /** * Tests link description field widgets and formatters. * * @group link_description */ abstract class LinkDescriptionFieldTestBase extends BrowserTestBase { /** * {@inheritdoc} */ protected static $modules = [ 'entity_test', 'link_description', ]; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * Link description test field name. * * @var string */ protected $fieldName; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->fieldName = mb_strtolower($this->randomMachineName()); // Create a field with settings to validate. $field_storage = FieldStorageConfig::create([ 'field_name' => $this->fieldName, 'entity_type' => 'entity_test', 'type' => 'link_description', 'cardinality' => 3, ]); $field_storage->save(); FieldConfig::create([ 'field_storage' => $field_storage, 'label' => 'Read more about this entity', 'bundle' => 'entity_test', 'settings' => [ 'title' => DRUPAL_OPTIONAL, 'link_type' => LinkItemInterface::LINK_GENERIC, ], ])->save(); \Drupal::service('entity_display.repository')->getFormDisplay('entity_test', 'entity_test') ->setComponent($this->fieldName, [ 'type' => 'link_description', ]) ->save(); $this->drupalLogin($this->drupalCreateUser([ 'view test entity', 'administer entity_test content', 'link to any page', ])); } }
tests/src/Functional/LinkDescriptionFieldWidgetTest.php 0 → 100644 +37 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\link_description\Functional; use Drupal\entity_test\Entity\EntityTest; /** * Tests link description field widget. * * @group link_description */ class LinkDescriptionFieldWidgetTest extends LinkDescriptionFieldTestBase { /** * Tests 'description' field exists on the 'link_description' widget. */ public function testLinkDescriptionWidget() { $entity_form_builder = \Drupal::service('entity.form_builder'); $form = $entity_form_builder->getForm(EntityTest::create()); $this->assertEquals('textarea', $form[$this->fieldName]['widget'][0]['description']['#type']); $this->assertEquals('Long description', $form[$this->fieldName]['widget'][0]['description']['#title']); $this->assertEmpty($form[$this->fieldName]['widget'][0]['description']['#default_value']); // Assert default value of the link description field. $entity_test = EntityTest::create([ 'name' => $this->randomMachineName(), $this->fieldName => [ 'uri' => 'https://www.example.com', 'title' => 'Example site', 'description' => 'Link description &' ], ]); $entity_test->save(); $form = $entity_form_builder->getForm($entity_test); $this->assertEquals('Link description &', $form[$this->fieldName]['widget'][0]['description']['#default_value']); } }