3 namespace Drupal\Tests\link\Functional;
5 use Drupal\Component\Utility\Html;
6 use Drupal\Component\Utility\Unicode;
8 use Drupal\entity_test\Entity\EntityTest;
9 use Drupal\field\Entity\FieldConfig;
10 use Drupal\link\LinkItemInterface;
11 use Drupal\node\NodeInterface;
12 use Drupal\Tests\BrowserTestBase;
13 use Drupal\field\Entity\FieldStorageConfig;
16 * Tests link field widgets and formatters.
20 class LinkFieldTest extends BrowserTestBase {
27 public static $modules = ['entity_test', 'link', 'node'];
30 * A field to use in this test class.
32 * @var \Drupal\field\Entity\FieldStorageConfig
34 protected $fieldStorage;
37 * The instance used in this test class.
39 * @var \Drupal\field\Entity\FieldConfig
43 protected function setUp() {
46 $this->drupalLogin($this->drupalCreateUser([
48 'administer entity_test content',
54 * Tests link field URL validation.
56 public function testURLValidation() {
57 $field_name = Unicode::strtolower($this->randomMachineName());
58 // Create a field with settings to validate.
59 $this->fieldStorage = FieldStorageConfig::create([
60 'field_name' => $field_name,
61 'entity_type' => 'entity_test',
64 $this->fieldStorage->save();
65 $this->field = FieldConfig::create([
66 'field_storage' => $this->fieldStorage,
67 'bundle' => 'entity_test',
69 'title' => DRUPAL_DISABLED,
70 'link_type' => LinkItemInterface::LINK_GENERIC,
74 entity_get_form_display('entity_test', 'entity_test', 'default')
75 ->setComponent($field_name, [
76 'type' => 'link_default',
78 'placeholder_url' => 'http://example.com',
82 entity_get_display('entity_test', 'entity_test', 'full')
83 ->setComponent($field_name, [
88 // Display creation form.
89 $this->drupalGet('entity_test/add');
90 $this->assertFieldByName("{$field_name}[0][uri]", '', 'Link URL field is displayed');
91 $this->assertRaw('placeholder="http://example.com"');
93 // Create a path alias.
94 \Drupal::service('path.alias_storage')->save('/admin', '/a/path/alias');
96 // Create a node to test the link widget.
97 $node = $this->drupalCreateNode();
99 $restricted_node = $this->drupalCreateNode(['status' => NodeInterface::NOT_PUBLISHED]);
101 // Define some valid URLs (keys are the entered values, values are the
102 // strings displayed to the user).
103 $valid_external_entries = [
104 'http://www.example.com/' => 'http://www.example.com/',
105 // Strings within parenthesis without leading space char.
106 'http://www.example.com/strings_(string_within_parenthesis)' => 'http://www.example.com/strings_(string_within_parenthesis)',
107 // Numbers within parenthesis without leading space char.
108 'http://www.example.com/numbers_(9999)' => 'http://www.example.com/numbers_(9999)',
110 $valid_internal_entries = [
111 '/entity_test/add' => '/entity_test/add',
112 '/a/path/alias' => '/a/path/alias',
114 // Front page, with query string and fragment.
115 '/' => '<front>',
116 '/?example=llama' => '<front>?example=llama',
117 '/#example' => '<front>#example',
119 // @todo '<front>' is valid input for BC reasons, may be removed by
120 // https://www.drupal.org/node/2421941
121 '<front>' => '<front>',
122 '<front>#example' => '<front>#example',
123 '<front>?example=llama' => '<front>?example=llama',
125 // Query string and fragment.
126 '?example=llama' => '?example=llama',
127 '#example' => '#example',
129 // Entity reference autocomplete value.
130 $node->label() . ' (1)' => $node->label() . ' (1)',
131 // Entity URI displayed as ER autocomplete value when displayed in a form.
132 'entity:node/1' => $node->label() . ' (1)',
133 // URI for an entity that exists, but is not accessible by the user.
134 'entity:node/' . $restricted_node->id() => '- Restricted access - (' . $restricted_node->id() . ')',
135 // URI for an entity that doesn't exist, but with a valid ID.
136 'entity:user/999999' => 'entity:user/999999',
139 // Define some invalid URLs.
140 $validation_error_1 = "The path '@link_path' is invalid.";
141 $validation_error_2 = 'Manually entered paths should start with /, ? or #.';
142 $validation_error_3 = "The path '@link_path' is inaccessible.";
143 $invalid_external_entries = [
145 'invalid://not-a-valid-protocol' => $validation_error_1,
147 'http://' => $validation_error_1,
149 $invalid_internal_entries = [
150 'no-leading-slash' => $validation_error_2,
151 'entity:non_existing_entity_type/yar' => $validation_error_1,
152 // URI for an entity that doesn't exist, with an invalid ID.
153 'entity:user/invalid-parameter' => $validation_error_1,
156 // Test external and internal URLs for 'link_type' = LinkItemInterface::LINK_GENERIC.
157 $this->assertValidEntries($field_name, $valid_external_entries + $valid_internal_entries);
158 $this->assertInvalidEntries($field_name, $invalid_external_entries + $invalid_internal_entries);
160 // Test external URLs for 'link_type' = LinkItemInterface::LINK_EXTERNAL.
161 $this->field->setSetting('link_type', LinkItemInterface::LINK_EXTERNAL);
162 $this->field->save();
163 $this->assertValidEntries($field_name, $valid_external_entries);
164 $this->assertInvalidEntries($field_name, $valid_internal_entries + $invalid_external_entries);
166 // Test external URLs for 'link_type' = LinkItemInterface::LINK_INTERNAL.
167 $this->field->setSetting('link_type', LinkItemInterface::LINK_INTERNAL);
168 $this->field->save();
169 $this->assertValidEntries($field_name, $valid_internal_entries);
170 $this->assertInvalidEntries($field_name, $valid_external_entries + $invalid_internal_entries);
172 // Ensure that users with 'link to any page', don't apply access checking.
173 $this->drupalLogin($this->drupalCreateUser([
175 'administer entity_test content',
177 $this->assertValidEntries($field_name, ['/entity_test/add' => '/entity_test/add']);
178 $this->assertInValidEntries($field_name, ['/admin' => $validation_error_3]);
182 * Asserts that valid URLs can be submitted.
184 * @param string $field_name
186 * @param array $valid_entries
187 * An array of valid URL entries.
189 protected function assertValidEntries($field_name, array $valid_entries) {
190 foreach ($valid_entries as $uri => $string) {
192 "{$field_name}[0][uri]" => $uri,
194 $this->drupalPostForm('entity_test/add', $edit, t('Save'));
195 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
197 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
198 $this->assertRaw($string);
203 * Asserts that invalid URLs cannot be submitted.
205 * @param string $field_name
207 * @param array $invalid_entries
208 * An array of invalid URL entries.
210 protected function assertInvalidEntries($field_name, array $invalid_entries) {
211 foreach ($invalid_entries as $invalid_value => $error_message) {
213 "{$field_name}[0][uri]" => $invalid_value,
215 $this->drupalPostForm('entity_test/add', $edit, t('Save'));
216 $this->assertText(t($error_message, ['@link_path' => $invalid_value]));
221 * Tests the link title settings of a link field.
223 public function testLinkTitle() {
224 $field_name = Unicode::strtolower($this->randomMachineName());
225 // Create a field with settings to validate.
226 $this->fieldStorage = FieldStorageConfig::create([
227 'field_name' => $field_name,
228 'entity_type' => 'entity_test',
231 $this->fieldStorage->save();
232 $this->field = FieldConfig::create([
233 'field_storage' => $this->fieldStorage,
234 'bundle' => 'entity_test',
235 'label' => 'Read more about this entity',
237 'title' => DRUPAL_OPTIONAL,
238 'link_type' => LinkItemInterface::LINK_GENERIC,
241 $this->field->save();
242 entity_get_form_display('entity_test', 'entity_test', 'default')
243 ->setComponent($field_name, [
244 'type' => 'link_default',
246 'placeholder_url' => 'http://example.com',
247 'placeholder_title' => 'Enter the text for this link',
251 entity_get_display('entity_test', 'entity_test', 'full')
252 ->setComponent($field_name, [
258 // Verify that the link text field works according to the field setting.
259 foreach ([DRUPAL_DISABLED, DRUPAL_REQUIRED, DRUPAL_OPTIONAL] as $title_setting) {
260 // Update the link title field setting.
261 $this->field->setSetting('title', $title_setting);
262 $this->field->save();
264 // Display creation form.
265 $this->drupalGet('entity_test/add');
266 // Assert label is shown.
267 $this->assertText('Read more about this entity');
268 $this->assertFieldByName("{$field_name}[0][uri]", '', 'URL field found.');
269 $this->assertRaw('placeholder="http://example.com"');
271 if ($title_setting === DRUPAL_DISABLED) {
272 $this->assertNoFieldByName("{$field_name}[0][title]", '', 'Link text field not found.');
273 $this->assertNoRaw('placeholder="Enter the text for this link"');
276 $this->assertRaw('placeholder="Enter the text for this link"');
278 $this->assertFieldByName("{$field_name}[0][title]", '', 'Link text field found.');
279 if ($title_setting === DRUPAL_REQUIRED) {
280 // Verify that the link text is required, if the URL is non-empty.
282 "{$field_name}[0][uri]" => 'http://www.example.com',
284 $this->drupalPostForm(NULL, $edit, t('Save'));
285 $this->assertText(t('@name field is required.', ['@name' => t('Link text')]));
287 // Verify that the link text is not required, if the URL is empty.
289 "{$field_name}[0][uri]" => '',
291 $this->drupalPostForm(NULL, $edit, t('Save'));
292 $this->assertNoText(t('@name field is required.', ['@name' => t('Link text')]));
294 // Verify that a URL and link text meets requirements.
295 $this->drupalGet('entity_test/add');
297 "{$field_name}[0][uri]" => 'http://www.example.com',
298 "{$field_name}[0][title]" => 'Example',
300 $this->drupalPostForm(NULL, $edit, t('Save'));
301 $this->assertNoText(t('@name field is required.', ['@name' => t('Link text')]));
306 // Verify that a link without link text is rendered using the URL as text.
307 $value = 'http://www.example.com/';
309 "{$field_name}[0][uri]" => $value,
310 "{$field_name}[0][title]" => '',
312 $this->drupalPostForm(NULL, $edit, t('Save'));
313 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
315 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
317 $output = $this->renderTestEntity($id);
318 $expected_link = (string) \Drupal::l($value, Url::fromUri($value));
319 $this->assertContains($expected_link, $output);
321 // Verify that a link with text is rendered using the link text.
322 $title = $this->randomMachineName();
324 "{$field_name}[0][title]" => $title,
326 $this->drupalPostForm("entity_test/manage/$id/edit", $edit, t('Save'));
327 $this->assertText(t('entity_test @id has been updated.', ['@id' => $id]));
329 $output = $this->renderTestEntity($id);
330 $expected_link = (string) \Drupal::l($title, Url::fromUri($value));
331 $this->assertContains($expected_link, $output);
335 * Tests the default 'link' formatter.
337 public function testLinkFormatter() {
338 $field_name = Unicode::strtolower($this->randomMachineName());
339 // Create a field with settings to validate.
340 $this->fieldStorage = FieldStorageConfig::create([
341 'field_name' => $field_name,
342 'entity_type' => 'entity_test',
346 $this->fieldStorage->save();
347 FieldConfig::create([
348 'field_storage' => $this->fieldStorage,
349 'label' => 'Read more about this entity',
350 'bundle' => 'entity_test',
352 'title' => DRUPAL_OPTIONAL,
353 'link_type' => LinkItemInterface::LINK_GENERIC,
356 entity_get_form_display('entity_test', 'entity_test', 'default')
357 ->setComponent($field_name, [
358 'type' => 'link_default',
365 entity_get_display('entity_test', 'entity_test', 'full')
366 ->setComponent($field_name, $display_options)
369 // Create an entity with three link field values:
370 // - The first field item uses a URL only.
371 // - The second field item uses a URL and link text.
372 // - The third field item uses a fragment-only URL with text.
373 // For consistency in assertion code below, the URL is assigned to the title
374 // variable for the first field.
375 $this->drupalGet('entity_test/add');
376 $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com';
377 $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org';
380 // Intentionally contains an ampersand that needs sanitization on output.
381 $title2 = 'A very long & strange example title that could break the nice layout of the site';
382 $title3 = 'Fragment only';
384 "{$field_name}[0][uri]" => $url1,
385 // Note that $title1 is not submitted.
386 "{$field_name}[0][title]" => '',
387 "{$field_name}[1][uri]" => $url2,
388 "{$field_name}[1][title]" => $title2,
389 "{$field_name}[2][uri]" => $url3,
390 "{$field_name}[2][title]" => $title3,
392 // Assert label is shown.
393 $this->assertText('Read more about this entity');
394 $this->drupalPostForm(NULL, $edit, t('Save'));
395 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
397 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
399 // Verify that the link is output according to the formatter settings.
400 // Not using generatePermutations(), since that leads to 32 cases, which
401 // would not test actual link field formatter functionality but rather
402 // the link generator and options/attributes. Only 'url_plain' has a
403 // dependency on 'url_only', so we have a total of ~10 cases.
405 'trim_length' => [NULL, 6],
406 'rel' => [NULL, 'nofollow'],
407 'target' => [NULL, '_blank'],
409 ['url_only' => FALSE],
410 ['url_only' => FALSE, 'url_plain' => TRUE],
411 ['url_only' => TRUE],
412 ['url_only' => TRUE, 'url_plain' => TRUE],
415 foreach ($options as $setting => $values) {
416 foreach ($values as $new_value) {
417 // Update the field formatter settings.
418 if (!is_array($new_value)) {
419 $display_options['settings'] = [$setting => $new_value];
422 $display_options['settings'] = $new_value;
424 entity_get_display('entity_test', 'entity_test', 'full')
425 ->setComponent($field_name, $display_options)
428 $output = $this->renderTestEntity($id);
432 $title = isset($new_value) ? Unicode::truncate($title1, $new_value, FALSE, TRUE) : $title1;
433 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output);
436 $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2;
437 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output);
440 $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3;
441 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output);
445 $rel = isset($new_value) ? ' rel="' . $new_value . '"' : '';
446 $this->assertContains('<a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($title1) . '</a>', $output);
447 $this->assertContains('<a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($title2) . '</a>', $output);
448 $this->assertContains('<a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($title3) . '</a>', $output);
452 $target = isset($new_value) ? ' target="' . $new_value . '"' : '';
453 $this->assertContains('<a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($title1) . '</a>', $output);
454 $this->assertContains('<a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($title2) . '</a>', $output);
455 $this->assertContains('<a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($title3) . '</a>', $output);
459 // In this case, $new_value is an array.
460 if (!$new_value['url_only']) {
461 $this->assertContains('<a href="' . Html::escape($url1) . '">' . Html::escape($title1) . '</a>', $output);
462 $this->assertContains('<a href="' . Html::escape($url2) . '">' . Html::escape($title2) . '</a>', $output);
463 $this->assertContains('<a href="' . Html::escape($url3) . '">' . Html::escape($title3) . '</a>', $output);
466 if (empty($new_value['url_plain'])) {
467 $this->assertContains('<a href="' . Html::escape($url1) . '">' . Html::escape($url1) . '</a>', $output);
468 $this->assertContains('<a href="' . Html::escape($url2) . '">' . Html::escape($url2) . '</a>', $output);
469 $this->assertContains('<a href="' . Html::escape($url3) . '">' . Html::escape($url3) . '</a>', $output);
472 $this->assertNotContains('<a href="' . Html::escape($url1) . '">' . Html::escape($url1) . '</a>', $output);
473 $this->assertNotContains('<a href="' . Html::escape($url2) . '">' . Html::escape($url2) . '</a>', $output);
474 $this->assertNotContains('<a href="' . Html::escape($url3) . '">' . Html::escape($url3) . '</a>', $output);
475 $this->assertContains(Html::escape($url1), $output);
476 $this->assertContains(Html::escape($url2), $output);
477 $this->assertContains(Html::escape($url3), $output);
487 * Tests the 'link_separate' formatter.
489 * This test is mostly the same as testLinkFormatter(), but they cannot be
490 * merged, since they involve different configuration and output.
492 public function testLinkSeparateFormatter() {
493 $field_name = Unicode::strtolower($this->randomMachineName());
494 // Create a field with settings to validate.
495 $this->fieldStorage = FieldStorageConfig::create([
496 'field_name' => $field_name,
497 'entity_type' => 'entity_test',
501 $this->fieldStorage->save();
502 FieldConfig::create([
503 'field_storage' => $this->fieldStorage,
504 'bundle' => 'entity_test',
506 'title' => DRUPAL_OPTIONAL,
507 'link_type' => LinkItemInterface::LINK_GENERIC,
511 'type' => 'link_separate',
514 entity_get_form_display('entity_test', 'entity_test', 'default')
515 ->setComponent($field_name, [
516 'type' => 'link_default',
519 entity_get_display('entity_test', 'entity_test', 'full')
520 ->setComponent($field_name, $display_options)
523 // Create an entity with three link field values:
524 // - The first field item uses a URL only.
525 // - The second field item uses a URL and link text.
526 // - The third field item uses a fragment-only URL with text.
527 // For consistency in assertion code below, the URL is assigned to the title
528 // variable for the first field.
529 $this->drupalGet('entity_test/add');
530 $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com';
531 $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org';
533 // Intentionally contains an ampersand that needs sanitization on output.
534 $title2 = 'A very long & strange example title that could break the nice layout of the site';
535 $title3 = 'Fragment only';
537 "{$field_name}[0][uri]" => $url1,
538 "{$field_name}[1][uri]" => $url2,
539 "{$field_name}[1][title]" => $title2,
540 "{$field_name}[2][uri]" => $url3,
541 "{$field_name}[2][title]" => $title3,
543 $this->drupalPostForm(NULL, $edit, t('Save'));
544 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
546 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
548 // Verify that the link is output according to the formatter settings.
550 'trim_length' => [NULL, 6],
551 'rel' => [NULL, 'nofollow'],
552 'target' => [NULL, '_blank'],
554 foreach ($options as $setting => $values) {
555 foreach ($values as $new_value) {
556 // Update the field formatter settings.
557 $display_options['settings'] = [$setting => $new_value];
558 entity_get_display('entity_test', 'entity_test', 'full')
559 ->setComponent($field_name, $display_options)
562 $output = $this->renderTestEntity($id);
566 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url;
567 $expected = '<div class="link-item">';
568 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>';
569 $expected .= '</div>';
570 $this->assertContains($expected, $output);
573 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url;
574 $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2;
575 $expected = '<div class="link-item">';
576 $expected .= '<div class="link-title">' . Html::escape($title) . '</div>';
577 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>';
578 $expected .= '</div>';
579 $this->assertContains($expected, $output);
582 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url;
583 $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3;
584 $expected = '<div class="link-item">';
585 $expected .= '<div class="link-title">' . Html::escape($title) . '</div>';
586 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>';
587 $expected .= '</div>';
588 $this->assertContains($expected, $output);
592 $rel = isset($new_value) ? ' rel="' . $new_value . '"' : '';
593 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($url1) . '</a></div>', $output);
594 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($url2) . '</a></div>', $output);
595 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($url3) . '</a></div>', $output);
599 $target = isset($new_value) ? ' target="' . $new_value . '"' : '';
600 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($url1) . '</a></div>', $output);
601 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($url2) . '</a></div>', $output);
602 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($url3) . '</a></div>', $output);
611 * Tests editing a link to a non-node entity.
613 public function testEditNonNodeEntityLink() {
615 $entity_type_manager = \Drupal::entityTypeManager();
616 $entity_test_storage = $entity_type_manager->getStorage('entity_test');
618 // Create a field with settings to validate.
619 $this->fieldStorage = FieldStorageConfig::create([
620 'field_name' => 'field_link',
621 'entity_type' => 'entity_test',
625 $this->fieldStorage->save();
626 FieldConfig::create([
627 'field_storage' => $this->fieldStorage,
628 'label' => 'Read more about this entity',
629 'bundle' => 'entity_test',
631 'title' => DRUPAL_OPTIONAL,
636 ->getStorage('entity_form_display')
637 ->load('entity_test.entity_test.default')
638 ->setComponent('field_link', [
639 'type' => 'link_default',
643 // Create a node and a test entity to have a possibly valid reference for
644 // both. Create another test entity that references the first test entity.
645 $entity_test_link = $entity_test_storage->create(['name' => 'correct link target']);
646 $entity_test_link->save();
648 $node = $this->drupalCreateNode(['wrong link target']);
650 $correct_link = 'entity:entity_test/' . $entity_test_link->id();
651 $entity_test = $entity_test_storage->create([
652 'name' => 'correct link target',
653 'field_link' => $correct_link,
655 $entity_test->save();
657 // Edit the entity and save it, verify the correct link is kept and not
658 // changed to point to a node. Currently, widget does not support non-node
659 // autocomplete and therefore must show the link unaltered.
660 $this->drupalGet($entity_test->toUrl('edit-form'));
661 $this->assertSession()->fieldValueEquals('field_link[0][uri]', $correct_link);
662 $this->drupalPostForm(NULL, [], 'Save');
664 $entity_test_storage->resetCache();
665 $entity_test = $entity_test_storage->load($entity_test->id());
667 $this->assertEquals($correct_link, $entity_test->get('field_link')->uri);
671 * Renders a test_entity and returns the output.
674 * The test_entity ID to render.
675 * @param string $view_mode
676 * (optional) The view mode to use for rendering.
678 * (optional) Whether to reset the entity_test storage cache. Defaults to
679 * TRUE to simplify testing.
682 * The rendered HTML output.
684 protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) {
686 $this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]);
688 $entity = EntityTest::load($id);
689 $display = entity_get_display($entity->getEntityTypeId(), $entity->bundle(), $view_mode);
690 $content = $display->build($entity);
691 $output = \Drupal::service('renderer')->renderRoot($content);
692 $output = (string) $output;
693 $this->verbose($output);