function RendererTest::providerTestRenderBasic

Same name and namespace in other branches
  1. 9 core/tests/Drupal/Tests/Core/Render/RendererTest.php \Drupal\Tests\Core\Render\RendererTest::providerTestRenderBasic()
  2. 8.9.x core/tests/Drupal/Tests/Core/Render/RendererTest.php \Drupal\Tests\Core\Render\RendererTest::providerTestRenderBasic()
  3. 10 core/tests/Drupal/Tests/Core/Render/RendererTest.php \Drupal\Tests\Core\Render\RendererTest::providerTestRenderBasic()

Provides a list of render arrays to test basic rendering.

Return value

array

File

core/tests/Drupal/Tests/Core/Render/RendererTest.php, line 66

Class

RendererTest
@coversDefaultClass <a href="/api/drupal/core%21lib%21Drupal%21Core%21Render%21Renderer.php/class/Renderer/11.x" title="Turns a render array into an HTML string." class="local">\Drupal\Core\Render\Renderer</a> @group Render

Namespace

Drupal\Tests\Core\Render

Code

public static function providerTestRenderBasic() {
    $data = [];
    // Part 1: the most simplistic render arrays possible, none using #theme.
    // Pass a NULL.
    $data[] = [
        NULL,
        '',
    ];
    // Pass an empty string.
    $data[] = [
        '',
        '',
    ];
    // Previously printed, see ::renderTwice for a more integration-like test.
    $data[] = [
        [
            '#markup' => 'foo',
            '#printed' => TRUE,
        ],
        '',
    ];
    // Printed in pre_render.
    $data[] = [
        [
            '#markup' => 'foo',
            '#pre_render' => [
                [
                    new TestCallables(),
                    'preRenderPrinted',
                ],
            ],
        ],
        '',
    ];
    // Basic #markup based renderable array.
    $data[] = [
        [
            '#markup' => 'foo',
        ],
        'foo',
    ];
    // Basic #markup based renderable array with value '0'.
    $data[] = [
        [
            '#markup' => '0',
        ],
        '0',
    ];
    // Basic #markup based renderable array with value 0.
    $data[] = [
        [
            '#markup' => 0,
        ],
        '0',
    ];
    // Basic #markup based renderable array with value ''.
    $data[] = [
        [
            '#markup' => '',
        ],
        '',
    ];
    // Basic #markup based renderable array with value NULL.
    $data[] = [
        [
            '#markup' => NULL,
        ],
        '',
    ];
    // Basic #plain_text based renderable array.
    $data[] = [
        [
            '#plain_text' => 'foo',
        ],
        'foo',
    ];
    // Mixing #plain_text and #markup based renderable array.
    $data[] = [
        [
            '#plain_text' => '<em>foo</em>',
            '#markup' => 'bar',
        ],
        '&lt;em&gt;foo&lt;/em&gt;',
    ];
    // Safe strings in #plain_text are still escaped.
    $data[] = [
        [
            '#plain_text' => Markup::create('<em>foo</em>'),
        ],
        '&lt;em&gt;foo&lt;/em&gt;',
    ];
    // #plain_text based renderable array with value '0'.
    $data[] = [
        [
            '#plain_text' => '0',
        ],
        '0',
    ];
    // #plain_text based renderable array with value 0.
    $data[] = [
        [
            '#plain_text' => 0,
        ],
        '0',
    ];
    // #plain_text based renderable array with value ''.
    $data[] = [
        [
            '#plain_text' => '',
        ],
        '',
    ];
    // #plain_text based renderable array with value NULL.
    $data[] = [
        [
            '#plain_text' => NULL,
        ],
        '',
    ];
    // Renderable child element.
    $data[] = [
        [
            'child' => [
                '#markup' => 'bar',
            ],
        ],
        'bar',
    ];
    // XSS filtering test.
    $data[] = [
        [
            'child' => [
                '#markup' => "This is <script>alert('XSS')</script> test",
            ],
        ],
        "This is alert('XSS') test",
    ];
    // XSS filtering test.
    $data[] = [
        [
            'child' => [
                '#markup' => "This is <script>alert('XSS')</script> test",
                '#allowed_tags' => [
                    'script',
                ],
            ],
        ],
        "This is <script>alert('XSS')</script> test",
    ];
    // XSS filtering test.
    $data[] = [
        [
            'child' => [
                '#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>",
                '#allowed_tags' => [
                    'em',
                    'strong',
                ],
            ],
        ],
        "This is <em>alert('XSS')</em> <strong>test</strong>",
    ];
    // Html escaping test.
    $data[] = [
        [
            'child' => [
                '#plain_text' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>",
            ],
        ],
        "This is &lt;script&gt;&lt;em&gt;alert(&#039;XSS&#039;)&lt;/em&gt;&lt;/script&gt; &lt;strong&gt;test&lt;/strong&gt;",
    ];
    // XSS filtering by default test.
    $data[] = [
        [
            'child' => [
                '#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>",
            ],
        ],
        "This is <em>alert('XSS')</em> <strong>test</strong>",
    ];
    // Ensure non-XSS tags are not filtered out.
    $data[] = [
        [
            'child' => [
                '#markup' => "This is <strong><script>alert('not a giraffe')</script></strong> test",
            ],
        ],
        "This is <strong>alert('not a giraffe')</strong> test",
    ];
    // #children set but empty, and renderable children.
    $data[] = [
        [
            '#children' => '',
            'child' => [
                '#markup' => 'bar',
            ],
        ],
        'bar',
    ];
    // #children set, not empty, and renderable children. #children will be
    // assumed oto be the rendered child elements, even though the #markup for
    // 'child' differs.
    $data[] = [
        [
            '#children' => 'foo',
            'child' => [
                '#markup' => 'bar',
            ],
        ],
        'foo',
    ];
    // Ensure that content added to #markup via a #pre_render callback is safe.
    $data[] = [
        [
            '#markup' => 'foo',
            '#pre_render' => [
                function ($elements) {
                    $elements['#markup'] .= '<script>alert("bar");</script>';
                    return $elements;
                },
            ],
        ],
        'fooalert("bar");',
    ];
    // Test #allowed_tags in combination with #markup and #pre_render.
    $data[] = [
        [
            '#markup' => 'foo',
            '#allowed_tags' => [
                'script',
            ],
            '#pre_render' => [
                function ($elements) {
                    $elements['#markup'] .= '<script>alert("bar");</script>';
                    return $elements;
                },
            ],
        ],
        'foo<script>alert("bar");</script>',
    ];
    // Ensure output is escaped when adding content to #check_plain through
    // a #pre_render callback.
    $data[] = [
        [
            '#plain_text' => 'foo',
            '#pre_render' => [
                function ($elements) {
                    $elements['#plain_text'] .= '<script>alert("bar");</script>';
                    return $elements;
                },
            ],
        ],
        'foo&lt;script&gt;alert(&quot;bar&quot;);&lt;/script&gt;',
    ];
    // Part 2: render arrays using #theme and #theme_wrappers.
    // Tests that #theme and #theme_wrappers can co-exist on an element.
    $build = [
        '#theme' => 'common_test_foo',
        '#foo' => 'foo',
        '#bar' => 'bar',
        '#theme_wrappers' => [
            'container',
        ],
        '#attributes' => [
            'class' => [
                'baz',
            ],
        ],
    ];
    $setup_code_type_link = function ($themeManager) {
        $themeManager->expects(static::exactly(2))
            ->method('render')
            ->with(static::logicalOr('common_test_foo', 'container'))
            ->willReturnCallback(function ($theme, $vars) {
            if ($theme == 'container') {
                return '<div' . (string) new Attribute($vars['#attributes']) . '>' . $vars['#children'] . "</div>\n";
            }
            return $vars['#foo'] . $vars['#bar'];
        });
    };
    $data[] = [
        $build,
        '<div class="baz">foobar</div>' . "\n",
        $setup_code_type_link,
    ];
    // Tests that #theme_wrappers can disambiguate element attributes shared
    // with rendering methods that build #children by using the alternate
    // #theme_wrappers attribute override syntax.
    $build = [
        '#type' => 'link',
        '#theme_wrappers' => [
            'container' => [
                '#attributes' => [
                    'class' => [
                        'baz',
                    ],
                ],
            ],
        ],
        '#attributes' => [
            'id' => 'foo',
        ],
        '#url' => 'https://www.drupal.org',
        '#title' => 'bar',
    ];
    $setup_code_type_link = function ($themeManager) {
        $themeManager->expects(static::exactly(2))
            ->method('render')
            ->with(static::logicalOr('link', 'container'))
            ->willReturnCallback(function ($theme, $vars) {
            if ($theme == 'container') {
                return '<div' . (string) new Attribute($vars['#attributes']) . '>' . $vars['#children'] . "</div>\n";
            }
            $attributes = new Attribute([
                'href' => $vars['#url'],
            ] + ($vars['#attributes'] ?? []));
            return '<a' . (string) $attributes . '>' . $vars['#title'] . '</a>';
        });
    };
    $data[] = [
        $build,
        '<div class="baz"><a href="https://www.drupal.org" id="foo">bar</a></div>' . "\n",
        $setup_code_type_link,
    ];
    // Tests that #theme_wrappers can disambiguate element attributes when the
    // "base" attribute is not set for #theme.
    $build = [
        '#type' => 'link',
        '#url' => 'https://www.drupal.org',
        '#title' => 'foo',
        '#theme_wrappers' => [
            'container' => [
                '#attributes' => [
                    'class' => [
                        'baz',
                    ],
                ],
            ],
        ],
    ];
    $data[] = [
        $build,
        '<div class="baz"><a href="https://www.drupal.org">foo</a></div>' . "\n",
        $setup_code_type_link,
    ];
    // Tests two 'container' #theme_wrappers, one using the "base" attributes
    // and one using an override.
    $build = [
        '#attributes' => [
            'class' => [
                'foo',
            ],
        ],
        '#theme_wrappers' => [
            'container' => [
                '#attributes' => [
                    'class' => [
                        'bar',
                    ],
                ],
            ],
            'container',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::exactly(2))
            ->method('render')
            ->with('container')
            ->willReturnCallback(function ($theme, $vars) {
            return '<div' . (string) new Attribute($vars['#attributes']) . '>' . $vars['#children'] . "</div>\n";
        });
    };
    $data[] = [
        $build,
        '<div class="foo"><div class="bar"></div>' . "\n" . '</div>' . "\n",
        $setup_code,
    ];
    // Tests array syntax theme hook suggestion in #theme_wrappers.
    $build = [
        '#theme_wrappers' => [
            [
                'container',
            ],
        ],
        '#attributes' => [
            'class' => [
                'foo',
            ],
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::once())
            ->method('render')
            ->with([
            'container',
        ])
            ->willReturnCallback(function ($theme, $vars) {
            return '<div' . (string) new Attribute($vars['#attributes']) . '>' . $vars['#children'] . "</div>\n";
        });
    };
    $data[] = [
        $build,
        '<div class="foo"></div>' . "\n",
        $setup_code,
    ];
    // Part 3: render arrays using #markup as a fallback for #theme hooks.
    // Theme suggestion is not implemented, #markup should be rendered.
    $build = [
        '#theme' => [
            'suggestion_not_implemented',
        ],
        '#markup' => 'foo',
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::once())
            ->method('render')
            ->with([
            'suggestion_not_implemented',
        ], static::anything())
            ->willReturn(FALSE);
    };
    $data[] = [
        $build,
        'foo',
        $setup_code,
    ];
    // Tests unimplemented theme suggestion, child #markup should be rendered.
    $build = [
        '#theme' => [
            'suggestion_not_implemented',
        ],
        'child' => [
            '#markup' => 'foo',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::once())
            ->method('render')
            ->with([
            'suggestion_not_implemented',
        ], static::anything())
            ->willReturn(FALSE);
    };
    $data[] = [
        $build,
        'foo',
        $setup_code,
    ];
    // Tests implemented theme suggestion: #markup should not be rendered.
    $build = [
        '#theme' => [
            'common_test_empty',
        ],
        '#markup' => 'foo',
    ];
    $theme_function_output = static::randomContextValue();
    $setup_code = function ($themeManager) use ($theme_function_output) {
        $themeManager->expects(static::once())
            ->method('render')
            ->with([
            'common_test_empty',
        ], static::anything())
            ->willReturn($theme_function_output);
    };
    $data[] = [
        $build,
        $theme_function_output,
        $setup_code,
    ];
    // Tests implemented theme suggestion: children should not be rendered.
    $build = [
        '#theme' => [
            'common_test_empty',
        ],
        'child' => [
            '#markup' => 'foo',
        ],
    ];
    $data[] = [
        $build,
        $theme_function_output,
        $setup_code,
    ];
    // Part 4: handling of #children and child renderable elements.
    // #theme is implemented so the values of both #children and 'child' will
    // be ignored - it is the responsibility of the theme hook to render these
    // if appropriate.
    $build = [
        '#theme' => 'common_test_foo',
        '#children' => 'baz',
        'child' => [
            '#markup' => 'boo',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::once())
            ->method('render')
            ->with('common_test_foo', static::anything())
            ->willReturn('foobar');
    };
    $data[] = [
        $build,
        'foobar',
        $setup_code,
    ];
    // #theme is implemented but #render_children is TRUE. As in the case where
    // #theme is not set, empty #children means child elements are rendered
    // recursively.
    $build = [
        '#theme' => 'common_test_foo',
        '#children' => '',
        '#render_children' => TRUE,
        'child' => [
            '#markup' => 'boo',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::never())
            ->method('render');
    };
    $data[] = [
        $build,
        'boo',
        $setup_code,
    ];
    // #theme is implemented but #render_children is TRUE. As in the case where
    // #theme is not set, #children will take precedence over 'child'.
    $build = [
        '#theme' => 'common_test_foo',
        '#children' => 'baz',
        '#render_children' => TRUE,
        'child' => [
            '#markup' => 'boo',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::never())
            ->method('render');
    };
    $data[] = [
        $build,
        'baz',
        $setup_code,
    ];
    // #theme is implemented but #render_children is TRUE. In this case the
    // calling code is expecting only the children to be rendered. #prefix and
    // #suffix should not be inherited for the children.
    $build = [
        '#theme' => 'common_test_foo',
        '#children' => '',
        '#prefix' => 'kangaroo',
        '#suffix' => 'unicorn',
        '#render_children' => TRUE,
        'child' => [
            '#markup' => 'kitten',
        ],
    ];
    $setup_code = function ($themeManager) {
        $themeManager->expects(static::never())
            ->method('render');
    };
    $data[] = [
        $build,
        'kitten',
        $setup_code,
    ];
    return $data;
}

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