public function RendererTest::providerTestRenderBasic in Drupal 9
Same name and namespace in other branches
- 8 core/tests/Drupal/Tests/Core/Render/RendererTest.php \Drupal\Tests\Core\Render\RendererTest::providerTestRenderBasic()
- 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 - Contains \Drupal\Tests\Core\Render\RendererTest.
Class
- RendererTest
- @coversDefaultClass \Drupal\Core\Render\Renderer @group Render
Namespace
Drupal\Tests\Core\RenderCode
public 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',
],
'<em>foo</em>',
];
// Safe strings in #plain_text are still escaped.
$data[] = [
[
'#plain_text' => Markup::create('<em>foo</em>'),
],
'<em>foo</em>',
];
// #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 <script><em>alert('XSS')</em></script> <strong>test</strong>",
];
// 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<script>alert("bar");</script>',
];
// 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 () {
$this->themeManager
->expects($this
->exactly(2))
->method('render')
->with($this
->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 () {
$this->themeManager
->expects($this
->exactly(2))
->method('render')
->with($this
->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'],
] + (isset($vars['#attributes']) ? $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 () {
$this->themeManager
->expects($this
->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 () {
$this->themeManager
->expects($this
->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' => [
'suggestionnotimplemented',
],
'#markup' => 'foo',
];
$setup_code = function () {
$this->themeManager
->expects($this
->once())
->method('render')
->with([
'suggestionnotimplemented',
], $this
->anything())
->willReturn(FALSE);
};
$data[] = [
$build,
'foo',
$setup_code,
];
// Tests unimplemented theme suggestion, child #markup should be rendered.
$build = [
'#theme' => [
'suggestionnotimplemented',
],
'child' => [
'#markup' => 'foo',
],
];
$setup_code = function () {
$this->themeManager
->expects($this
->once())
->method('render')
->with([
'suggestionnotimplemented',
], $this
->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 = $this
->randomContextValue();
$setup_code = function () use ($theme_function_output) {
$this->themeManager
->expects($this
->once())
->method('render')
->with([
'common_test_empty',
], $this
->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 () {
$this->themeManager
->expects($this
->once())
->method('render')
->with('common_test_foo', $this
->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 () {
$this->themeManager
->expects($this
->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 () {
$this->themeManager
->expects($this
->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 () {
$this->themeManager
->expects($this
->never())
->method('render');
};
$data[] = [
$build,
'kitten',
$setup_code,
];
return $data;
}