5 * Contains \Drupal\KernelTests\Core\Theme\ThemeRenderAndAutoescapeTest.
8 namespace Drupal\KernelTests\Core\Theme;
10 use Drupal\Component\Utility\Html;
11 use Drupal\Core\GeneratedLink;
13 use Drupal\Core\Render\RenderContext;
14 use Drupal\Core\Render\Markup;
16 use Drupal\KernelTests\KernelTestBase;
19 * Tests the theme_render_and_autoescape() function.
23 class ThemeRenderAndAutoescapeTest extends KernelTestBase {
28 public static $modules = ['system'];
33 protected function setUp() {
36 \Drupal::service('router.builder')->rebuild();
40 * @dataProvider providerTestThemeRenderAndAutoescape
42 public function testThemeRenderAndAutoescape($arg, $expected) {
43 if (is_array($arg) && isset($arg['#type']) && $arg['#type'] === 'link') {
44 $arg = Link::createFromRoute($arg['#title'], $arg['#url']);
47 $context = new RenderContext();
48 // Use a closure here since we need to render with a render context.
49 $theme_render_and_autoescape = function () use ($arg) {
50 return theme_render_and_autoescape($arg);
52 /** @var \Drupal\Core\Render\RendererInterface $renderer */
53 $renderer = \Drupal::service('renderer');
54 $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
55 $this->assertEquals($expected, $output);
56 $this->assertInternalType('string', $output);
60 * Provide test examples.
62 public function providerTestThemeRenderAndAutoescape() {
64 'empty string unchanged' => ['', ''],
65 'simple string unchanged' => ['ab', 'ab'],
66 'int (scalar) cast to string' => [111, '111'],
67 'float (scalar) cast to string' => [2.10, '2.10'],
68 '> is escaped' => ['>', '>'],
69 'Markup EM tag is unchanged' => [Markup::create('<em>hi</em>'), '<em>hi</em>'],
70 'Markup SCRIPT tag is unchanged' => [Markup::create('<script>alert("hi");</script>'), '<script>alert("hi");</script>'],
71 'EM tag in string is escaped' => ['<em>hi</em>', Html::escape('<em>hi</em>')],
72 'type link render array is rendered' => [['#type' => 'link', '#title' => 'Text', '#url' => '<none>'], '<a href="">Text</a>'],
73 'type markup with EM tags is rendered' => [['#markup' => '<em>hi</em>'], '<em>hi</em>'],
74 'SCRIPT tag in string is escaped' => [
75 '<script>alert(123)</script>',
76 Html::escape('<script>alert(123)</script>')
78 'type plain_text render array EM tag is escaped' => [['#plain_text' => '<em>hi</em>'], Html::escape('<em>hi</em>')],
79 'type hidden render array is rendered' => [['#type' => 'hidden', '#name' => 'foo', '#value' => 'bar'], "<input type=\"hidden\" name=\"foo\" value=\"bar\" />\n"],
84 * Ensures invalid content is handled correctly.
86 public function testThemeEscapeAndRenderNotPrintable() {
87 $this->setExpectedException(\Exception::class);
88 theme_render_and_autoescape(new NonPrintable());
92 * Ensure cache metadata is bubbled when using theme_render_and_autoescape().
94 public function testBubblingMetadata() {
95 $link = new GeneratedLink();
96 $link->setGeneratedLink('<a href="http://example.com"></a>');
97 $link->addCacheTags(['foo']);
98 $link->addAttachments(['library' => ['system/base']]);
100 $context = new RenderContext();
101 // Use a closure here since we need to render with a render context.
102 $theme_render_and_autoescape = function () use ($link) {
103 return theme_render_and_autoescape($link);
105 /** @var \Drupal\Core\Render\RendererInterface $renderer */
106 $renderer = \Drupal::service('renderer');
107 $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
108 $this->assertEquals('<a href="http://example.com"></a>', $output);
109 /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
110 $metadata = $context->pop();
111 $this->assertEquals(['foo'], $metadata->getCacheTags());
112 $this->assertEquals(['library' => ['system/base']], $metadata->getAttachments());
116 * Ensure cache metadata is bubbled when using theme_render_and_autoescape().
118 public function testBubblingMetadataWithRenderable() {
119 $link = new Link('', Url::fromRoute('<current>'));
121 $context = new RenderContext();
122 // Use a closure here since we need to render with a render context.
123 $theme_render_and_autoescape = function () use ($link) {
124 return theme_render_and_autoescape($link);
126 /** @var \Drupal\Core\Render\RendererInterface $renderer */
127 $renderer = \Drupal::service('renderer');
128 $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
129 $this->assertEquals('<a href="/' . urlencode('<none>') . '"></a>', $output);
130 /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
131 $metadata = $context->pop();
132 $this->assertEquals(['route'], $metadata->getCacheContexts());
137 class NonPrintable { }