ThemeRenderAndAutoescapeTest.php

Same filename and directory in other branches
  1. 9 core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php
  2. 8.9.x core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php
  3. 11.x core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php

Namespace

Drupal\KernelTests\Core\Theme

File

core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\KernelTests\Core\Theme;

use Drupal\Component\Utility\Html;
use Drupal\Core\GeneratedLink;
use Drupal\Core\Link;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\KernelTests\KernelTestBase;

/**
 * Tests the theme_render_and_autoescape() function.
 *
 * @group Theme
 * @group legacy
 * @group #slow
 */
class ThemeRenderAndAutoescapeTest extends KernelTestBase {
  
  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
  ];
  
  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    $this->expectDeprecation('theme_render_and_autoescape() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. Theme engines must handle escaping by themselves. See https://www.drupal.org/node/3336253');
  }
  
  /**
   * @dataProvider providerTestThemeRenderAndAutoescape
   */
  public function testThemeRenderAndAutoescape($arg, $expected) : void {
    if (is_array($arg) && isset($arg['#type']) && $arg['#type'] === 'link') {
      $arg = Link::createFromRoute($arg['#title'], $arg['#url']);
    }
    $context = new RenderContext();
    // Use a closure here since we need to render with a render context.
    $theme_render_and_autoescape = function () use ($arg) {
      return theme_render_and_autoescape($arg);
    };
    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');
    $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
    $this->assertEquals($expected, $output);
    $this->assertIsString($output);
  }
  
  /**
   * Provide test examples.
   */
  public static function providerTestThemeRenderAndAutoescape() {
    return [
      'empty string unchanged' => [
        '',
        '',
      ],
      'simple string unchanged' => [
        'ab',
        'ab',
      ],
      'int (scalar) cast to string' => [
        111,
        '111',
      ],
      'float (scalar) cast to string' => [
        2.1,
        '2.1',
      ],
      '> is escaped' => [
        '>',
        '&gt;',
      ],
      'Markup EM tag is unchanged' => [
        Markup::create('<em>hi</em>'),
        '<em>hi</em>',
      ],
      'Markup SCRIPT tag is unchanged' => [
        Markup::create('<script>alert("hi");</script>'),
        '<script>alert("hi");</script>',
      ],
      'EM tag in string is escaped' => [
        '<em>hi</em>',
        Html::escape('<em>hi</em>'),
      ],
      'type link render array is rendered' => [
        [
          '#type' => 'link',
          '#title' => 'Text',
          '#url' => '<none>',
        ],
        '<a href="">Text</a>',
      ],
      'type markup with EM tags is rendered' => [
        [
          '#markup' => '<em>hi</em>',
        ],
        '<em>hi</em>',
      ],
      'SCRIPT tag in string is escaped' => [
        '<script>alert(123)</script>',
        Html::escape('<script>alert(123)</script>'),
      ],
      'type plain_text render array EM tag is escaped' => [
        [
          '#plain_text' => '<em>hi</em>',
        ],
        Html::escape('<em>hi</em>'),
      ],
      'type hidden render array is rendered' => [
        [
          '#type' => 'hidden',
          '#name' => 'foo',
          '#value' => 'bar',
        ],
        "<input type=\"hidden\" name=\"foo\" value=\"bar\" />\n",
      ],
    ];
  }
  
  /**
   * Ensures invalid content is handled correctly.
   */
  public function testThemeEscapeAndRenderNotPrintable() : void {
    $this->expectException(\Exception::class);
    theme_render_and_autoescape(new NonPrintable());
  }
  
  /**
   * Ensure cache metadata is bubbled when using theme_render_and_autoescape().
   */
  public function testBubblingMetadata() : void {
    $link = new GeneratedLink();
    $link->setGeneratedLink('<a href="http://example.com"></a>');
    $link->addCacheTags([
      'foo',
    ]);
    $link->addAttachments([
      'library' => [
        'system/base',
      ],
    ]);
    $context = new RenderContext();
    // Use a closure here since we need to render with a render context.
    $theme_render_and_autoescape = function () use ($link) {
      return theme_render_and_autoescape($link);
    };
    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');
    $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
    $this->assertEquals('<a href="http://example.com"></a>', $output);
    /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
    $metadata = $context->pop();
    $this->assertEquals([
      'foo',
    ], $metadata->getCacheTags());
    $this->assertEquals([
      'library' => [
        'system/base',
      ],
    ], $metadata->getAttachments());
  }
  
  /**
   * Ensure cache metadata is bubbled when using theme_render_and_autoescape().
   */
  public function testBubblingMetadataWithRenderable() : void {
    $link = new Link('', Url::fromRoute('<current>'));
    $context = new RenderContext();
    // Use a closure here since we need to render with a render context.
    $theme_render_and_autoescape = function () use ($link) {
      return theme_render_and_autoescape($link);
    };
    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');
    $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
    $this->assertEquals('<a href="/' . urlencode('<none>') . '"></a>', $output);
    /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
    $metadata = $context->pop();
    $this->assertEquals([
      'route',
    ], $metadata->getCacheContexts());
  }

}
class NonPrintable {

}

Classes

Title Deprecated Summary
NonPrintable
ThemeRenderAndAutoescapeTest Tests the theme_render_and_autoescape() function.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.