Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -39,7 +39,7 @@ class BigPipeRegressionTestController {
|
|||
public static function currentTime() {
|
||||
return [
|
||||
'#markup' => '<time datetime="' . date('Y-m-d', time()) . '"></time>',
|
||||
'#cache' => ['max-age' => 0]
|
||||
'#cache' => ['max-age' => 0],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -23,4 +23,3 @@ big_pipe_test_multi_occurrence:
|
|||
_title: 'BigPipe test multiple occurrences of the same placeholder'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
namespace Drupal\big_pipe_test;
|
||||
|
||||
use Drupal\big_pipe\Render\BigPipeMarkup;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* BigPipe placeholder test cases for use in both unit and integration tests.
|
||||
*
|
||||
* - Unit test:
|
||||
* \Drupal\Tests\big_pipe\Unit\Render\Placeholder\BigPipeStrategyTest
|
||||
* - Integration test for BigPipe with JS on:
|
||||
* \Drupal\Tests\big_pipe\Functional\BigPipeTest::testBigPipe()
|
||||
* - Integration test for BigPipe with JS off:
|
||||
* \Drupal\Tests\big_pipe\Functional\BigPipeTest::testBigPipeNoJs()
|
||||
*/
|
||||
class BigPipePlaceholderTestCases {
|
||||
|
||||
/**
|
||||
* Gets all BigPipe placeholder test cases.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface|null $container
|
||||
* Optional. Necessary to get the embedded AJAX/HTML responses.
|
||||
* @param \Drupal\Core\Session\AccountInterface|null $user
|
||||
* Optional. Necessary to get the embedded AJAX/HTML responses.
|
||||
*
|
||||
* @return \Drupal\big_pipe_test\BigPipePlaceholderTestCase[]
|
||||
*/
|
||||
public static function cases(ContainerInterface $container = NULL, AccountInterface $user = NULL) {
|
||||
// Define the two types of cacheability that we expect to see. These will be
|
||||
// used in the expectations.
|
||||
$cacheability_depends_on_session_only = [
|
||||
'max-age' => 0,
|
||||
'contexts' => ['session.exists'],
|
||||
];
|
||||
$cacheability_depends_on_session_and_nojs_cookie = [
|
||||
'max-age' => 0,
|
||||
'contexts' => ['session.exists', 'cookies:big_pipe_nojs'],
|
||||
];
|
||||
|
||||
// 1. Real-world example of HTML placeholder.
|
||||
$status_messages = new BigPipePlaceholderTestCase(
|
||||
['#type' => 'status_messages'],
|
||||
'<drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></drupal-render-placeholder>',
|
||||
[
|
||||
'#lazy_builder' => [
|
||||
'Drupal\Core\Render\Element\StatusMessages::renderMessages',
|
||||
[NULL],
|
||||
],
|
||||
]
|
||||
);
|
||||
$status_messages->bigPipePlaceholderId = 'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA';
|
||||
$status_messages->bigPipePlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'library' => ['big_pipe/big_pipe'],
|
||||
'drupalSettings' => [
|
||||
'bigPipePlaceholderIds' => [
|
||||
'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA' => TRUE,
|
||||
],
|
||||
],
|
||||
'big_pipe_placeholders' => [
|
||||
'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA' => $status_messages->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$status_messages->bigPipeNoJsPlaceholder = '<span data-big-pipe-nojs-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></span>';
|
||||
$status_messages->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-nojs-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
'<span data-big-pipe-nojs-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></span>' => $status_messages->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
if ($container && $user) {
|
||||
$status_messages->embeddedAjaxResponseCommands = [
|
||||
[
|
||||
'command' => 'insert',
|
||||
'method' => 'replaceWith',
|
||||
'selector' => '[data-big-pipe-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"]',
|
||||
'data' => ' <div role="contentinfo" aria-label="Status message" class="messages messages--status">' . "\n" . ' <h2 class="visually-hidden">Status message</h2>' . "\n" . ' Hello from BigPipe!' . "\n" . ' </div>' . "\n ",
|
||||
'settings' => NULL,
|
||||
],
|
||||
];
|
||||
$status_messages->embeddedHtmlResponse = '<div role="contentinfo" aria-label="Status message" class="messages messages--status">' . "\n" . ' <h2 class="visually-hidden">Status message</h2>' . "\n" . ' Hello from BigPipe!' . "\n" . ' </div>' . "\n \n";
|
||||
}
|
||||
|
||||
// 2. Real-world example of HTML attribute value placeholder: form action.
|
||||
$form_action = new BigPipePlaceholderTestCase(
|
||||
$container ? $container->get('form_builder')->getForm('Drupal\big_pipe_test\Form\BigPipeTestForm') : [],
|
||||
'form_action_cc611e1d',
|
||||
[
|
||||
'#lazy_builder' => ['form_builder:renderPlaceholderFormAction', []],
|
||||
]
|
||||
);
|
||||
$form_action->bigPipeNoJsPlaceholder = 'big_pipe_nojs_placeholder_attribute_safe:form_action_cc611e1d';
|
||||
$form_action->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => 'big_pipe_nojs_placeholder_attribute_safe:form_action_cc611e1d',
|
||||
'#cache' => $cacheability_depends_on_session_only,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
'big_pipe_nojs_placeholder_attribute_safe:form_action_cc611e1d' => $form_action->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
if ($container) {
|
||||
$form_action->embeddedHtmlResponse = '<form class="big-pipe-test-form" data-drupal-selector="big-pipe-test-form" action="' . base_path() . 'big_pipe_test"';
|
||||
}
|
||||
|
||||
// 3. Real-world example of HTML attribute value subset placeholder: CSRF
|
||||
// token in link.
|
||||
$csrf_token = new BigPipePlaceholderTestCase(
|
||||
[
|
||||
'#title' => 'Link with CSRF token',
|
||||
'#type' => 'link',
|
||||
'#url' => Url::fromRoute('system.theme_set_default'),
|
||||
],
|
||||
'e88b559cce72c80b687d56b0e2a3a5ae4b66bc0e',
|
||||
[
|
||||
'#lazy_builder' => [
|
||||
'route_processor_csrf:renderPlaceholderCsrfToken',
|
||||
['admin/config/user-interface/shortcut/manage/default/add-link-inline'],
|
||||
],
|
||||
]
|
||||
);
|
||||
$csrf_token->bigPipeNoJsPlaceholder = 'big_pipe_nojs_placeholder_attribute_safe:e88b559cce72c80b687d56b0e2a3a5ae4b66bc0e';
|
||||
$csrf_token->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => 'big_pipe_nojs_placeholder_attribute_safe:e88b559cce72c80b687d56b0e2a3a5ae4b66bc0e',
|
||||
'#cache' => $cacheability_depends_on_session_only,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
'big_pipe_nojs_placeholder_attribute_safe:e88b559cce72c80b687d56b0e2a3a5ae4b66bc0e' => $csrf_token->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
if ($container) {
|
||||
$csrf_token->embeddedHtmlResponse = $container->get('csrf_token')->get('admin/appearance/default');
|
||||
}
|
||||
|
||||
// 4. Edge case: custom string to be considered as a placeholder that
|
||||
// happens to not be valid HTML.
|
||||
$hello = new BigPipePlaceholderTestCase(
|
||||
[
|
||||
'#markup' => BigPipeMarkup::create('<hello'),
|
||||
'#attached' => [
|
||||
'placeholders' => [
|
||||
'<hello' => ['#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::helloOrYarhar', []]],
|
||||
],
|
||||
],
|
||||
],
|
||||
'<hello',
|
||||
[
|
||||
'#lazy_builder' => [
|
||||
'hello_or_yarhar',
|
||||
[],
|
||||
],
|
||||
]
|
||||
);
|
||||
$hello->bigPipeNoJsPlaceholder = 'big_pipe_nojs_placeholder_attribute_safe:<hello';
|
||||
$hello->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => 'big_pipe_nojs_placeholder_attribute_safe:<hello',
|
||||
'#cache' => $cacheability_depends_on_session_only,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
'big_pipe_nojs_placeholder_attribute_safe:<hello' => $hello->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$hello->embeddedHtmlResponse = '<marquee>Yarhar llamas forever!</marquee>';
|
||||
|
||||
// 5. Edge case: non-#lazy_builder placeholder.
|
||||
$current_time = new BigPipePlaceholderTestCase(
|
||||
[
|
||||
'#markup' => BigPipeMarkup::create('<time>CURRENT TIME</time>'),
|
||||
'#attached' => [
|
||||
'placeholders' => [
|
||||
'<time>CURRENT TIME</time>' => [
|
||||
'#pre_render' => [
|
||||
'\Drupal\big_pipe_test\BigPipeTestController::currentTime',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'<time>CURRENT TIME</time>',
|
||||
[
|
||||
'#pre_render' => ['current_time'],
|
||||
]
|
||||
);
|
||||
$current_time->bigPipePlaceholderId = 'timecurrent-timetime';
|
||||
$current_time->bigPipePlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-placeholder-id="timecurrent-timetime"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'library' => ['big_pipe/big_pipe'],
|
||||
'drupalSettings' => [
|
||||
'bigPipePlaceholderIds' => [
|
||||
'timecurrent-timetime' => TRUE,
|
||||
],
|
||||
],
|
||||
'big_pipe_placeholders' => [
|
||||
'timecurrent-timetime' => $current_time->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$current_time->embeddedAjaxResponseCommands = [
|
||||
[
|
||||
'command' => 'insert',
|
||||
'method' => 'replaceWith',
|
||||
'selector' => '[data-big-pipe-placeholder-id="timecurrent-timetime"]',
|
||||
'data' => '<time datetime="1991-03-14"></time>',
|
||||
'settings' => NULL,
|
||||
],
|
||||
];
|
||||
$current_time->bigPipeNoJsPlaceholder = '<span data-big-pipe-nojs-placeholder-id="timecurrent-timetime"></span>';
|
||||
$current_time->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-nojs-placeholder-id="timecurrent-timetime"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
'<span data-big-pipe-nojs-placeholder-id="timecurrent-timetime"></span>' => $current_time->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$current_time->embeddedHtmlResponse = '<time datetime="1991-03-14"></time>';
|
||||
|
||||
// 6. Edge case: #lazy_builder that throws an exception.
|
||||
$exception = new BigPipePlaceholderTestCase(
|
||||
[
|
||||
'#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::exception', ['llamas', 'suck']],
|
||||
'#create_placeholder' => TRUE,
|
||||
],
|
||||
'<drupal-render-placeholder callback="\Drupal\big_pipe_test\BigPipeTestController::exception" arguments="0=llamas&1=suck" token="uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU"></drupal-render-placeholder>',
|
||||
[
|
||||
'#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::exception', ['llamas', 'suck']],
|
||||
]
|
||||
);
|
||||
$exception->bigPipePlaceholderId = 'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU';
|
||||
$exception->bigPipePlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'library' => ['big_pipe/big_pipe'],
|
||||
'drupalSettings' => [
|
||||
'bigPipePlaceholderIds' => [
|
||||
'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU' => TRUE,
|
||||
],
|
||||
],
|
||||
'big_pipe_placeholders' => [
|
||||
'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU' => $exception->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$exception->embeddedAjaxResponseCommands = NULL;
|
||||
$exception->bigPipeNoJsPlaceholder = '<span data-big-pipe-nojs-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU"></span>';
|
||||
$exception->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => $exception->bigPipeNoJsPlaceholder,
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
$exception->bigPipeNoJsPlaceholder => $exception->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$exception->embeddedHtmlResponse = NULL;
|
||||
|
||||
// 7. Edge case: response filter throwing an exception for this placeholder.
|
||||
$embedded_response_exception = new BigPipePlaceholderTestCase(
|
||||
[
|
||||
'#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::responseException', []],
|
||||
'#create_placeholder' => TRUE,
|
||||
],
|
||||
'<drupal-render-placeholder callback="\Drupal\big_pipe_test\BigPipeTestController::responseException" arguments="" token="PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU"></drupal-render-placeholder>',
|
||||
[
|
||||
'#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::responseException', []],
|
||||
]
|
||||
);
|
||||
$embedded_response_exception->bigPipePlaceholderId = 'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU';
|
||||
$embedded_response_exception->bigPipePlaceholderRenderArray = [
|
||||
'#markup' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU"></span>',
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'library' => ['big_pipe/big_pipe'],
|
||||
'drupalSettings' => [
|
||||
'bigPipePlaceholderIds' => [
|
||||
'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU' => TRUE,
|
||||
],
|
||||
],
|
||||
'big_pipe_placeholders' => [
|
||||
'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU' => $embedded_response_exception->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$embedded_response_exception->embeddedAjaxResponseCommands = NULL;
|
||||
$embedded_response_exception->bigPipeNoJsPlaceholder = '<span data-big-pipe-nojs-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU"></span>';
|
||||
$embedded_response_exception->bigPipeNoJsPlaceholderRenderArray = [
|
||||
'#markup' => $embedded_response_exception->bigPipeNoJsPlaceholder,
|
||||
'#cache' => $cacheability_depends_on_session_and_nojs_cookie,
|
||||
'#attached' => [
|
||||
'big_pipe_nojs_placeholders' => [
|
||||
$embedded_response_exception->bigPipeNoJsPlaceholder => $embedded_response_exception->placeholderRenderArray,
|
||||
],
|
||||
],
|
||||
];
|
||||
$exception->embeddedHtmlResponse = NULL;
|
||||
|
||||
return [
|
||||
'html' => $status_messages,
|
||||
'html_attribute_value' => $form_action,
|
||||
'html_attribute_value_subset' => $csrf_token,
|
||||
'edge_case__invalid_html' => $hello,
|
||||
'edge_case__html_non_lazy_builder' => $current_time,
|
||||
'exception__lazy_builder' => $exception,
|
||||
'exception__embedded_response' => $embedded_response_exception,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BigPipePlaceholderTestCase {
|
||||
|
||||
/**
|
||||
* The original render array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $renderArray;
|
||||
|
||||
/**
|
||||
* The expected corresponding placeholder string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $placeholder;
|
||||
|
||||
/**
|
||||
* The expected corresponding placeholder render array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $placeholderRenderArray;
|
||||
|
||||
/**
|
||||
* The expected BigPipe placeholder ID.
|
||||
*
|
||||
* (Only possible for HTML placeholders.)
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $bigPipePlaceholderId = NULL;
|
||||
|
||||
/**
|
||||
* The corresponding expected BigPipe placeholder render array.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
public $bigPipePlaceholderRenderArray = NULL;
|
||||
|
||||
/**
|
||||
* The corresponding expected embedded AJAX response.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
public $embeddedAjaxResponseCommands = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* The expected BigPipe no-JS placeholder.
|
||||
*
|
||||
* (Possible for all placeholders, HTML or non-HTML.)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $bigPipeNoJsPlaceholder;
|
||||
|
||||
/**
|
||||
* The corresponding expected BigPipe no-JS placeholder render array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $bigPipeNoJsPlaceholderRenderArray;
|
||||
|
||||
/**
|
||||
* The corresponding expected embedded HTML response.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $embeddedHtmlResponse;
|
||||
|
||||
public function __construct(array $render_array, $placeholder, array $placeholder_render_array) {
|
||||
$this->renderArray = $render_array;
|
||||
$this->placeholder = $placeholder;
|
||||
$this->placeholderRenderArray = $placeholder_render_array;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\big_pipe_test;
|
||||
|
||||
use Drupal\big_pipe\Render\BigPipeMarkup;
|
||||
use Drupal\big_pipe\Tests\BigPipePlaceholderTestCases;
|
||||
use Drupal\big_pipe_test\EventSubscriber\BigPipeTestSubscriber;
|
||||
|
||||
class BigPipeTestController {
|
||||
|
@ -25,7 +24,7 @@ class BigPipeTestController {
|
|||
if ($has_session) {
|
||||
// Only set a message if a session already exists, otherwise we always
|
||||
// trigger a session, which means we can't test no-session requests.
|
||||
drupal_set_message('Hello from BigPipe!');
|
||||
\Drupal::messenger()->addStatus('Hello from BigPipe!');
|
||||
}
|
||||
$build['html'] = $cases['html']->renderArray;
|
||||
|
||||
|
@ -61,7 +60,7 @@ class BigPipeTestController {
|
|||
/**
|
||||
* A page with multiple occurrences of the same placeholder.
|
||||
*
|
||||
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
|
||||
* @see \Drupal\Tests\big_pipe\Functional\BigPipeTest::testBigPipeMultiOccurrencePlaceholders()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -92,7 +91,7 @@ class BigPipeTestController {
|
|||
public static function currentTime() {
|
||||
return [
|
||||
'#markup' => '<time datetime="' . date('Y-m-d', 668948400) . '"></time>',
|
||||
'#cache' => ['max-age' => 0]
|
||||
'#cache' => ['max-age' => 0],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -134,7 +133,7 @@ class BigPipeTestController {
|
|||
/**
|
||||
* #lazy_builder callback; returns the current count.
|
||||
*
|
||||
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
|
||||
* @see \Drupal\Tests\big_pipe\Functional\BigPipeTest::testBigPipeMultiOccurrencePlaceholders()
|
||||
*
|
||||
* @return array
|
||||
* The render array.
|
||||
|
|
|
@ -5,6 +5,11 @@ namespace Drupal\big_pipe_test\Form;
|
|||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form to test BigPipe.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class BigPipeTestForm extends FormBase {
|
||||
|
||||
/**
|
||||
|
@ -35,6 +40,6 @@ class BigPipeTestForm extends FormBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) { }
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {}
|
||||
|
||||
}
|
||||
|
|
486
web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
Normal file
486
web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
Normal file
|
@ -0,0 +1,486 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\big_pipe\Functional;
|
||||
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Drupal\big_pipe\Render\Placeholder\BigPipeStrategy;
|
||||
use Drupal\big_pipe\Render\BigPipe;
|
||||
use Drupal\big_pipe_test\BigPipePlaceholderTestCases;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Logger\RfcLogLevel;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests BigPipe's no-JS detection & response delivery (with and without JS).
|
||||
*
|
||||
* Covers:
|
||||
* - big_pipe_page_attachments()
|
||||
* - \Drupal\big_pipe\Controller\BigPipeController
|
||||
* - \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber
|
||||
* - \Drupal\big_pipe\Render\BigPipe
|
||||
*
|
||||
* @group big_pipe
|
||||
*/
|
||||
class BigPipeTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['big_pipe', 'big_pipe_test', 'dblog'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $dumpHeaders = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Ignore the <meta> refresh that big_pipe.module sets. It causes a redirect
|
||||
// to a page that sets another cookie, which causes WebTestBase to lose the
|
||||
// session cookie. To avoid this problem, tests should first call
|
||||
// drupalGet() and then call checkForMetaRefresh() manually, and then reset
|
||||
// $this->maximumMetaRefreshCount and $this->metaRefreshCount.
|
||||
// @see doMetaRefresh()
|
||||
$this->maximumMetaRefreshCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a single <meta> refresh explicitly.
|
||||
*
|
||||
* This test disables the automatic <meta> refresh checking, each time it is
|
||||
* desired that this runs, a test case must explicitly call this.
|
||||
*
|
||||
* @see setUp()
|
||||
*/
|
||||
protected function performMetaRefresh() {
|
||||
$this->maximumMetaRefreshCount = 1;
|
||||
$this->checkForMetaRefresh();
|
||||
$this->maximumMetaRefreshCount = 0;
|
||||
$this->metaRefreshCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigPipe's no-JS detection.
|
||||
*
|
||||
* Covers:
|
||||
* - big_pipe_page_attachments()
|
||||
* - \Drupal\big_pipe\Controller\BigPipeController
|
||||
*/
|
||||
public function testNoJsDetection() {
|
||||
$no_js_to_js_markup = '<script>document.cookie = "' . BigPipeStrategy::NOJS_COOKIE . '=1; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"</script>';
|
||||
|
||||
// 1. No session (anonymous).
|
||||
$this->drupalGet(Url::fromRoute('<front>'));
|
||||
$this->assertSessionCookieExists(FALSE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=');
|
||||
$this->assertNoRaw($no_js_to_js_markup);
|
||||
|
||||
// 2. Session (authenticated).
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
$this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/1" />' . "\n" . '</noscript>');
|
||||
$this->assertNoRaw($no_js_to_js_markup);
|
||||
$this->assertBigPipeNoJsMetaRefreshRedirect();
|
||||
$this->assertBigPipeNoJsCookieExists(TRUE);
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=');
|
||||
$this->assertRaw($no_js_to_js_markup);
|
||||
$this->drupalLogout();
|
||||
|
||||
// Close the prior connection and remove the collected state.
|
||||
$this->getSession()->reset();
|
||||
|
||||
// 3. Session (anonymous).
|
||||
$this->drupalGet(Url::fromRoute('user.login', [], ['query' => ['trigger_session' => 1]]));
|
||||
$this->drupalGet(Url::fromRoute('user.login'));
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
$this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/login" />' . "\n" . '</noscript>');
|
||||
$this->assertNoRaw($no_js_to_js_markup);
|
||||
$this->assertBigPipeNoJsMetaRefreshRedirect();
|
||||
$this->assertBigPipeNoJsCookieExists(TRUE);
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=');
|
||||
$this->assertRaw($no_js_to_js_markup);
|
||||
|
||||
// Close the prior connection and remove the collected state.
|
||||
$this->getSession()->reset();
|
||||
|
||||
// Edge case: route with '_no_big_pipe' option.
|
||||
$this->drupalGet(Url::fromRoute('no_big_pipe'));
|
||||
$this->assertSessionCookieExists(FALSE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=');
|
||||
$this->assertNoRaw($no_js_to_js_markup);
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet(Url::fromRoute('no_big_pipe'));
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=');
|
||||
$this->assertNoRaw($no_js_to_js_markup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigPipe-delivered HTML responses when JavaScript is enabled.
|
||||
*
|
||||
* Covers:
|
||||
* - \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber
|
||||
* - \Drupal\big_pipe\Render\BigPipe
|
||||
* - \Drupal\big_pipe\Render\BigPipe::sendPlaceholders()
|
||||
*
|
||||
* @see \Drupal\big_pipe_test\BigPipePlaceholderTestCases
|
||||
*/
|
||||
public function testBigPipe() {
|
||||
// Simulate production.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_HIDE)->save();
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
|
||||
$log_count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
|
||||
|
||||
// By not calling performMetaRefresh() here, we simulate JavaScript being
|
||||
// enabled, because as far as the BigPipe module is concerned, JavaScript is
|
||||
// enabled in the browser as long as the BigPipe no-JS cookie is *not* set.
|
||||
// @see setUp()
|
||||
// @see performMetaRefresh()
|
||||
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
$this->assertBigPipeResponseHeadersPresent();
|
||||
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'cache_tag_set_in_lazy_builder');
|
||||
|
||||
$this->setCsrfTokenSeedInTestEnvironment();
|
||||
$cases = $this->getTestCases();
|
||||
$this->assertBigPipeNoJsPlaceholders([
|
||||
$cases['edge_case__invalid_html']->bigPipeNoJsPlaceholder => $cases['edge_case__invalid_html']->embeddedHtmlResponse,
|
||||
$cases['html_attribute_value']->bigPipeNoJsPlaceholder => $cases['html_attribute_value']->embeddedHtmlResponse,
|
||||
$cases['html_attribute_value_subset']->bigPipeNoJsPlaceholder => $cases['html_attribute_value_subset']->embeddedHtmlResponse,
|
||||
]);
|
||||
$this->assertBigPipePlaceholders([
|
||||
$cases['html']->bigPipePlaceholderId => Json::encode($cases['html']->embeddedAjaxResponseCommands),
|
||||
$cases['edge_case__html_non_lazy_builder']->bigPipePlaceholderId => Json::encode($cases['edge_case__html_non_lazy_builder']->embeddedAjaxResponseCommands),
|
||||
$cases['exception__lazy_builder']->bigPipePlaceholderId => NULL,
|
||||
$cases['exception__embedded_response']->bigPipePlaceholderId => NULL,
|
||||
], [
|
||||
0 => $cases['edge_case__html_non_lazy_builder']->bigPipePlaceholderId,
|
||||
// The 'html' case contains the 'status messages' placeholder, which is
|
||||
// always rendered last.
|
||||
1 => $cases['html']->bigPipePlaceholderId,
|
||||
]);
|
||||
|
||||
$this->assertRaw('</body>', 'Closing body tag present.');
|
||||
|
||||
$this->pass('Verifying BigPipe assets are present…', 'Debug');
|
||||
$this->assertFalse(empty($this->getDrupalSettings()), 'drupalSettings present.');
|
||||
$this->assertTrue(in_array('big_pipe/big_pipe', explode(',', $this->getDrupalSettings()['ajaxPageState']['libraries'])), 'BigPipe asset library is present.');
|
||||
|
||||
// Verify that the two expected exceptions are logged as errors.
|
||||
$this->assertEqual($log_count + 2, db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), 'Two new watchdog entries.');
|
||||
$records = db_query('SELECT * FROM {watchdog} ORDER BY wid DESC LIMIT 2')->fetchAll();
|
||||
$this->assertEqual(RfcLogLevel::ERROR, $records[0]->severity);
|
||||
$this->assertTrue(FALSE !== strpos((string) unserialize($records[0]->variables)['@message'], 'Oh noes!'));
|
||||
$this->assertEqual(RfcLogLevel::ERROR, $records[1]->severity);
|
||||
$this->assertTrue(FALSE !== strpos((string) unserialize($records[1]->variables)['@message'], 'You are not allowed to say llamas are not cool!'));
|
||||
|
||||
// Verify that 4xx responses work fine. (4xx responses are handled by
|
||||
// subrequests to a route pointing to a controller with the desired output.)
|
||||
$this->drupalGet(Url::fromUri('base:non-existing-path'));
|
||||
|
||||
// Simulate development.
|
||||
$this->pass('Verifying BigPipe provides useful error output when an error occurs while rendering a placeholder if verbose error logging is enabled.', 'Debug');
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
// The 'edge_case__html_exception' case throws an exception.
|
||||
$this->assertRaw('The website encountered an unexpected error. Please try again later');
|
||||
$this->assertRaw('You are not allowed to say llamas are not cool!');
|
||||
$this->assertNoRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal absent: error occurred before then.');
|
||||
$this->assertNoRaw('</body>', 'Closing body tag absent: error occurred before then.');
|
||||
// The exception is expected. Do not interpret it as a test failure.
|
||||
unlink($this->root . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigPipe-delivered HTML responses when JavaScript is disabled.
|
||||
*
|
||||
* Covers:
|
||||
* - \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber
|
||||
* - \Drupal\big_pipe\Render\BigPipe
|
||||
* - \Drupal\big_pipe\Render\BigPipe::sendNoJsPlaceholders()
|
||||
*
|
||||
* @see \Drupal\big_pipe_test\BigPipePlaceholderTestCases
|
||||
*/
|
||||
public function testBigPipeNoJs() {
|
||||
// Simulate production.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_HIDE)->save();
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
|
||||
// By calling performMetaRefresh() here, we simulate JavaScript being
|
||||
// disabled, because as far as the BigPipe module is concerned, it is
|
||||
// enabled in the browser when the BigPipe no-JS cookie is set.
|
||||
// @see setUp()
|
||||
// @see performMetaRefresh()
|
||||
$this->performMetaRefresh();
|
||||
$this->assertBigPipeNoJsCookieExists(TRUE);
|
||||
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
$this->assertBigPipeResponseHeadersPresent();
|
||||
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'cache_tag_set_in_lazy_builder');
|
||||
|
||||
$this->setCsrfTokenSeedInTestEnvironment();
|
||||
$cases = $this->getTestCases();
|
||||
$this->assertBigPipeNoJsPlaceholders([
|
||||
$cases['edge_case__invalid_html']->bigPipeNoJsPlaceholder => $cases['edge_case__invalid_html']->embeddedHtmlResponse,
|
||||
$cases['html_attribute_value']->bigPipeNoJsPlaceholder => $cases['html_attribute_value']->embeddedHtmlResponse,
|
||||
$cases['html_attribute_value_subset']->bigPipeNoJsPlaceholder => $cases['html_attribute_value_subset']->embeddedHtmlResponse,
|
||||
$cases['html']->bigPipeNoJsPlaceholder => $cases['html']->embeddedHtmlResponse,
|
||||
$cases['edge_case__html_non_lazy_builder']->bigPipeNoJsPlaceholder => $cases['edge_case__html_non_lazy_builder']->embeddedHtmlResponse,
|
||||
$cases['exception__lazy_builder']->bigPipePlaceholderId => NULL,
|
||||
$cases['exception__embedded_response']->bigPipePlaceholderId => NULL,
|
||||
]);
|
||||
|
||||
$this->pass('Verifying there are no BigPipe placeholders & replacements…', 'Debug');
|
||||
$this->assertEqual('<none>', $this->drupalGetHeader('BigPipe-Test-Placeholders'));
|
||||
$this->pass('Verifying BigPipe start/stop signals are absent…', 'Debug');
|
||||
$this->assertNoRaw(BigPipe::START_SIGNAL, 'BigPipe start signal absent.');
|
||||
$this->assertNoRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal absent.');
|
||||
|
||||
$this->pass('Verifying BigPipe assets are absent…', 'Debug');
|
||||
$this->assertTrue(!isset($this->getDrupalSettings()['bigPipePlaceholderIds']) && empty($this->getDrupalSettings()['ajaxPageState']), 'BigPipe drupalSettings and BigPipe asset library absent.');
|
||||
$this->assertRaw('</body>', 'Closing body tag present.');
|
||||
|
||||
// Verify that 4xx responses work fine. (4xx responses are handled by
|
||||
// subrequests to a route pointing to a controller with the desired output.)
|
||||
$this->drupalGet(Url::fromUri('base:non-existing-path'));
|
||||
|
||||
// Simulate development.
|
||||
$this->pass('Verifying BigPipe provides useful error output when an error occurs while rendering a placeholder if verbose error logging is enabled.', 'Debug');
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
// The 'edge_case__html_exception' case throws an exception.
|
||||
$this->assertRaw('The website encountered an unexpected error. Please try again later');
|
||||
$this->assertRaw('You are not allowed to say llamas are not cool!');
|
||||
$this->assertNoRaw('</body>', 'Closing body tag absent: error occurred before then.');
|
||||
// The exception is expected. Do not interpret it as a test failure.
|
||||
unlink($this->root . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigPipe with a multi-occurrence placeholder.
|
||||
*/
|
||||
public function testBigPipeMultiOccurrencePlaceholders() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->assertSessionCookieExists(TRUE);
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
|
||||
// By not calling performMetaRefresh() here, we simulate JavaScript being
|
||||
// enabled, because as far as the BigPipe module is concerned, JavaScript is
|
||||
// enabled in the browser as long as the BigPipe no-JS cookie is *not* set.
|
||||
// @see setUp()
|
||||
// @see performMetaRefresh()
|
||||
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test_multi_occurrence'));
|
||||
$big_pipe_placeholder_id = 'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA';
|
||||
$expected_placeholder_replacement = '<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="' . $big_pipe_placeholder_id . '">';
|
||||
$this->assertRaw('The count is 1.');
|
||||
$this->assertNoRaw('The count is 2.');
|
||||
$this->assertNoRaw('The count is 3.');
|
||||
$raw_content = $this->getSession()->getPage()->getContent();
|
||||
$this->assertTrue(substr_count($raw_content, $expected_placeholder_replacement) == 1, 'Only one placeholder replacement was found for the duplicate #lazy_builder arrays.');
|
||||
|
||||
// By calling performMetaRefresh() here, we simulate JavaScript being
|
||||
// disabled, because as far as the BigPipe module is concerned, it is
|
||||
// enabled in the browser when the BigPipe no-JS cookie is set.
|
||||
// @see setUp()
|
||||
// @see performMetaRefresh()
|
||||
$this->performMetaRefresh();
|
||||
$this->assertBigPipeNoJsCookieExists(TRUE);
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test_multi_occurrence'));
|
||||
$this->assertRaw('The count is 1.');
|
||||
$this->assertNoRaw('The count is 2.');
|
||||
$this->assertNoRaw('The count is 3.');
|
||||
}
|
||||
|
||||
protected function assertBigPipeResponseHeadersPresent() {
|
||||
$this->pass('Verifying BigPipe response headers…', 'Debug');
|
||||
$this->assertTrue(FALSE !== strpos($this->drupalGetHeader('Cache-Control'), 'private'), 'Cache-Control header set to "private".');
|
||||
$this->assertEqual('no-store, content="BigPipe/1.0"', $this->drupalGetHeader('Surrogate-Control'));
|
||||
$this->assertEqual('no', $this->drupalGetHeader('X-Accel-Buffering'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts expected BigPipe no-JS placeholders are present and replaced.
|
||||
*
|
||||
* @param array $expected_big_pipe_nojs_placeholders
|
||||
* Keys: BigPipe no-JS placeholder markup. Values: expected replacement
|
||||
* markup.
|
||||
*/
|
||||
protected function assertBigPipeNoJsPlaceholders(array $expected_big_pipe_nojs_placeholders) {
|
||||
$this->pass('Verifying BigPipe no-JS placeholders & replacements…', 'Debug');
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_nojs_placeholders), array_map('rawurldecode', explode(' ', $this->drupalGetHeader('BigPipe-Test-No-Js-Placeholders'))));
|
||||
foreach ($expected_big_pipe_nojs_placeholders as $big_pipe_nojs_placeholder => $expected_replacement) {
|
||||
$this->pass('Checking whether the replacement for the BigPipe no-JS placeholder "' . $big_pipe_nojs_placeholder . '" is present:');
|
||||
$this->assertNoRaw($big_pipe_nojs_placeholder);
|
||||
if ($expected_replacement !== NULL) {
|
||||
$this->assertRaw($expected_replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts expected BigPipe placeholders are present and replaced.
|
||||
*
|
||||
* @param array $expected_big_pipe_placeholders
|
||||
* Keys: BigPipe placeholder IDs. Values: expected AJAX response.
|
||||
* @param array $expected_big_pipe_placeholder_stream_order
|
||||
* Keys: BigPipe placeholder IDs. Values: expected AJAX response. Keys are
|
||||
* defined in the order that they are expected to be rendered & streamed.
|
||||
*/
|
||||
protected function assertBigPipePlaceholders(array $expected_big_pipe_placeholders, array $expected_big_pipe_placeholder_stream_order) {
|
||||
$this->pass('Verifying BigPipe placeholders & replacements…', 'Debug');
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_placeholders), explode(' ', $this->drupalGetHeader('BigPipe-Test-Placeholders')));
|
||||
$placeholder_positions = [];
|
||||
$placeholder_replacement_positions = [];
|
||||
foreach ($expected_big_pipe_placeholders as $big_pipe_placeholder_id => $expected_ajax_response) {
|
||||
$this->pass('BigPipe placeholder: ' . $big_pipe_placeholder_id, 'Debug');
|
||||
// Verify expected placeholder.
|
||||
$expected_placeholder_html = '<span data-big-pipe-placeholder-id="' . $big_pipe_placeholder_id . '"></span>';
|
||||
$this->assertRaw($expected_placeholder_html, 'BigPipe placeholder for placeholder ID "' . $big_pipe_placeholder_id . '" found.');
|
||||
$pos = strpos($this->getSession()->getPage()->getContent(), $expected_placeholder_html);
|
||||
$placeholder_positions[$pos] = $big_pipe_placeholder_id;
|
||||
// Verify expected placeholder replacement.
|
||||
$expected_placeholder_replacement = '<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="' . $big_pipe_placeholder_id . '">';
|
||||
$result = $this->xpath('//script[@data-big-pipe-replacement-for-placeholder-with-id=:id]', [':id' => Html::decodeEntities($big_pipe_placeholder_id)]);
|
||||
if ($expected_ajax_response === NULL) {
|
||||
$this->assertEqual(0, count($result));
|
||||
$this->assertNoRaw($expected_placeholder_replacement);
|
||||
continue;
|
||||
}
|
||||
$this->assertEqual($expected_ajax_response, trim($result[0]->getText()));
|
||||
$this->assertRaw($expected_placeholder_replacement);
|
||||
$pos = strpos($this->getSession()->getPage()->getContent(), $expected_placeholder_replacement);
|
||||
$placeholder_replacement_positions[$pos] = $big_pipe_placeholder_id;
|
||||
}
|
||||
ksort($placeholder_positions, SORT_NUMERIC);
|
||||
$this->assertEqual(array_keys($expected_big_pipe_placeholders), array_values($placeholder_positions));
|
||||
$placeholders = array_map(function (NodeElement $element) {
|
||||
return $element->getAttribute('data-big-pipe-placeholder-id');
|
||||
}, $this->cssSelect('[data-big-pipe-placeholder-id]'));
|
||||
$this->assertEqual(count($expected_big_pipe_placeholders), count(array_unique($placeholders)));
|
||||
$expected_big_pipe_placeholders_with_replacements = [];
|
||||
foreach ($expected_big_pipe_placeholder_stream_order as $big_pipe_placeholder_id) {
|
||||
$expected_big_pipe_placeholders_with_replacements[$big_pipe_placeholder_id] = $expected_big_pipe_placeholders[$big_pipe_placeholder_id];
|
||||
}
|
||||
$this->assertEqual($expected_big_pipe_placeholders_with_replacements, array_filter($expected_big_pipe_placeholders));
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_placeholders_with_replacements), array_values($placeholder_replacement_positions));
|
||||
$this->assertEqual(count($expected_big_pipe_placeholders_with_replacements), preg_match_all('/' . preg_quote('<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="', '/') . '/', $this->getSession()->getPage()->getContent()));
|
||||
|
||||
$this->pass('Verifying BigPipe start/stop signals…', 'Debug');
|
||||
$this->assertRaw(BigPipe::START_SIGNAL, 'BigPipe start signal present.');
|
||||
$this->assertRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal present.');
|
||||
$start_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::START_SIGNAL);
|
||||
$stop_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::STOP_SIGNAL);
|
||||
$this->assertTrue($start_signal_position < $stop_signal_position, 'BigPipe start signal appears before stop signal.');
|
||||
|
||||
$this->pass('Verifying BigPipe placeholder replacements and start/stop signals were streamed in the correct order…', 'Debug');
|
||||
$expected_stream_order = array_keys($expected_big_pipe_placeholders_with_replacements);
|
||||
array_unshift($expected_stream_order, BigPipe::START_SIGNAL);
|
||||
array_push($expected_stream_order, BigPipe::STOP_SIGNAL);
|
||||
$actual_stream_order = $placeholder_replacement_positions + [
|
||||
$start_signal_position => BigPipe::START_SIGNAL,
|
||||
$stop_signal_position => BigPipe::STOP_SIGNAL,
|
||||
];
|
||||
ksort($actual_stream_order, SORT_NUMERIC);
|
||||
$this->assertEqual($expected_stream_order, array_values($actual_stream_order));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures CSRF tokens can be generated for the current user's session.
|
||||
*/
|
||||
protected function setCsrfTokenSeedInTestEnvironment() {
|
||||
$session_data = $this->container->get('session_handler.write_safe')->read($this->getSession()->getCookie($this->getSessionName()));
|
||||
$csrf_token_seed = unserialize(explode('_sf2_meta|', $session_data)[1])['s'];
|
||||
$this->container->get('session_manager.metadata_bag')->setCsrfTokenSeed($csrf_token_seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\big_pipe_test\BigPipePlaceholderTestCase[]
|
||||
*/
|
||||
protected function getTestCases($has_session = TRUE) {
|
||||
return BigPipePlaceholderTestCases::cases($this->container, $this->rootUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether arrays A and B are equal, when treated as sets.
|
||||
*/
|
||||
protected function assertSetsEqual(array $a, array $b) {
|
||||
return count($a) == count($b) && !array_diff_assoc($a, $b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether a BigPipe no-JS cookie exists or not.
|
||||
*/
|
||||
protected function assertBigPipeNoJsCookieExists($expected) {
|
||||
$this->assertCookieExists('big_pipe_nojs', $expected, 'BigPipe no-JS');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether a session cookie exists or not.
|
||||
*/
|
||||
protected function assertSessionCookieExists($expected) {
|
||||
$this->assertCookieExists($this->getSessionName(), $expected, 'Session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether a cookie exists on the client or not.
|
||||
*/
|
||||
protected function assertCookieExists($cookie_name, $expected, $cookie_label) {
|
||||
$this->assertEqual($expected, !empty($this->getSession()->getCookie($cookie_name)), $expected ? "$cookie_label cookie exists." : "$cookie_label cookie does not exist.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls ::performMetaRefresh() and asserts the responses.
|
||||
*/
|
||||
protected function assertBigPipeNoJsMetaRefreshRedirect() {
|
||||
$original_url = $this->getSession()->getCurrentUrl();
|
||||
|
||||
// Disable automatic following of redirects by the HTTP client, so that this
|
||||
// test can analyze the response headers of each redirect response.
|
||||
$this->getSession()->getDriver()->getClient()->followRedirects(FALSE);
|
||||
$this->performMetaRefresh();
|
||||
$headers[0] = $this->getSession()->getResponseHeaders();
|
||||
$statuses[0] = $this->getSession()->getStatusCode();
|
||||
$this->performMetaRefresh();
|
||||
$headers[1] = $this->getSession()->getResponseHeaders();
|
||||
$statuses[1] = $this->getSession()->getStatusCode();
|
||||
$this->getSession()->getDriver()->getClient()->followRedirects(TRUE);
|
||||
|
||||
$this->assertEqual($original_url, $this->getSession()->getCurrentUrl(), 'Redirected back to the original location.');
|
||||
|
||||
// First response: redirect.
|
||||
$this->assertEqual(302, $statuses[0], 'The first response was a 302 (redirect).');
|
||||
$this->assertIdentical(0, strpos($headers[0]['Set-Cookie'][0], 'big_pipe_nojs=1'), 'The first response sets the big_pipe_nojs cookie.');
|
||||
$this->assertEqual($original_url, $headers[0]['Location'][0], 'The first response redirected back to the original page.');
|
||||
$this->assertTrue(empty(array_diff(['cookies:big_pipe_nojs', 'session.exists'], explode(' ', $headers[0]['X-Drupal-Cache-Contexts'][0]))), 'The first response varies by the "cookies:big_pipe_nojs" and "session.exists" cache contexts.');
|
||||
$this->assertFalse(isset($headers[0]['Surrogate-Control']), 'The first response has no "Surrogate-Control" header.');
|
||||
|
||||
// Second response: redirect followed.
|
||||
$this->assertEqual(200, $statuses[1], 'The second response was a 200.');
|
||||
$this->assertTrue(empty(array_diff(['cookies:big_pipe_nojs', 'session.exists'], explode(' ', $headers[0]['X-Drupal-Cache-Contexts'][0]))), 'The first response varies by the "cookies:big_pipe_nojs" and "session.exists" cache contexts.');
|
||||
$this->assertEqual('no-store, content="BigPipe/1.0"', $headers[1]['Surrogate-Control'][0], 'The second response has a "Surrogate-Control" header.');
|
||||
|
||||
$this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL=', 'Once the BigPipe no-JS cookie is set, the <meta> refresh is absent: only one redirect ever happens.');
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ use Drupal\comment\Tests\CommentTestTrait;
|
|||
use Drupal\Core\Url;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\simpletest\ContentTypeCreationTrait;
|
||||
use Drupal\simpletest\NodeCreationTrait;
|
||||
|
||||
|
@ -20,7 +20,7 @@ use Drupal\simpletest\NodeCreationTrait;
|
|||
*
|
||||
* @group big_pipe
|
||||
*/
|
||||
class BigPipeRegressionTest extends JavascriptTestBase {
|
||||
class BigPipeRegressionTest extends WebDriverTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
use ContentTypeCreationTrait;
|
||||
|
|
|
@ -101,8 +101,8 @@ class BigPipeResponseAttachmentsProcessorTest extends UnitTestCase {
|
|||
'random attachment type (unofficial), with random assigned value, to prove BigPipeResponseAttachmentsProcessor is a perfect decorator' => [$random_attachments],
|
||||
];
|
||||
|
||||
$big_pipe_placeholder_attachments = ['big_pipe_placeholders' => $this->randomMachineName()];
|
||||
$big_pipe_nojs_placeholder_attachments = ['big_pipe_nojs_placeholders' => $this->randomMachineName()];
|
||||
$big_pipe_placeholder_attachments = ['big_pipe_placeholders' => [$this->randomMachineName()]];
|
||||
$big_pipe_nojs_placeholder_attachments = ['big_pipe_nojs_placeholders' => [$this->randomMachineName()]];
|
||||
$big_pipe_cases = [
|
||||
'only big_pipe_placeholders' => [$big_pipe_placeholder_attachments],
|
||||
'only big_pipe_nojs_placeholders' => [$big_pipe_nojs_placeholder_attachments],
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Drupal\Tests\big_pipe\Unit\Render\Placeholder;
|
||||
|
||||
use Drupal\big_pipe\Render\Placeholder\BigPipeStrategy;
|
||||
use Drupal\big_pipe\Tests\BigPipePlaceholderTestCases;
|
||||
use Drupal\big_pipe_test\BigPipePlaceholderTestCases;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\SessionConfigurationInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
@ -47,7 +47,7 @@ class BigPipeStrategyTest extends UnitTestCase {
|
|||
$big_pipe_strategy = new BigPipeStrategy($session_configuration->reveal(), $request_stack->reveal(), $route_match->reveal());
|
||||
$processed_placeholders = $big_pipe_strategy->processPlaceholders($placeholders);
|
||||
|
||||
if ($request->isMethodSafe() && !$route_match_has_no_big_pipe_option && $request_has_session) {
|
||||
if ($request->isMethodCacheable() && !$route_match_has_no_big_pipe_option && $request_has_session) {
|
||||
$this->assertSameSize($expected_big_pipe_placeholders, $processed_placeholders, 'BigPipe is able to deliver all placeholders.');
|
||||
foreach (array_keys($placeholders) as $placeholder) {
|
||||
$this->assertSame($expected_big_pipe_placeholders[$placeholder], $processed_placeholders[$placeholder], "Verifying how BigPipeStrategy handles the placeholder '$placeholder'");
|
||||
|
@ -59,7 +59,7 @@ class BigPipeStrategyTest extends UnitTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\big_pipe\Tests\BigPipePlaceholderTestCases
|
||||
* @see \Drupal\big_pipe_test\BigPipePlaceholderTestCases
|
||||
*/
|
||||
public function placeholdersProvider() {
|
||||
$cases = BigPipePlaceholderTestCases::cases();
|
||||
|
@ -83,25 +83,29 @@ class BigPipeStrategyTest extends UnitTestCase {
|
|||
'_no_big_pipe present, no session, no-JS cookie present' => [$placeholders, 'GET', TRUE, FALSE, TRUE, []],
|
||||
'_no_big_pipe present, session, no-JS cookie absent' => [$placeholders, 'GET', TRUE, TRUE, FALSE, []],
|
||||
'_no_big_pipe present, session, no-JS cookie present' => [$placeholders, 'GET', TRUE, TRUE, TRUE, []],
|
||||
'_no_big_pipe absent, session, no-JS cookie absent: (JS-powered) BigPipe placeholder used for HTML placeholders' => [$placeholders, 'GET', FALSE, TRUE, FALSE, [
|
||||
$cases['html']->placeholder => $cases['html']->bigPipePlaceholderRenderArray,
|
||||
$cases['html_attribute_value']->placeholder => $cases['html_attribute_value']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value_subset']->placeholder => $cases['html_attribute_value_subset']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__invalid_html']->placeholder => $cases['edge_case__invalid_html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__html_non_lazy_builder']->placeholder => $cases['edge_case__html_non_lazy_builder']->bigPipePlaceholderRenderArray,
|
||||
$cases['exception__lazy_builder']->placeholder => $cases['exception__lazy_builder']->bigPipePlaceholderRenderArray,
|
||||
$cases['exception__embedded_response']->placeholder => $cases['exception__embedded_response']->bigPipePlaceholderRenderArray,
|
||||
]],
|
||||
'_no_big_pipe absent, session, no-JS cookie absent: (JS-powered) BigPipe placeholder used for HTML placeholders' => [
|
||||
$placeholders, 'GET', FALSE, TRUE, FALSE, [
|
||||
$cases['html']->placeholder => $cases['html']->bigPipePlaceholderRenderArray,
|
||||
$cases['html_attribute_value']->placeholder => $cases['html_attribute_value']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value_subset']->placeholder => $cases['html_attribute_value_subset']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__invalid_html']->placeholder => $cases['edge_case__invalid_html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__html_non_lazy_builder']->placeholder => $cases['edge_case__html_non_lazy_builder']->bigPipePlaceholderRenderArray,
|
||||
$cases['exception__lazy_builder']->placeholder => $cases['exception__lazy_builder']->bigPipePlaceholderRenderArray,
|
||||
$cases['exception__embedded_response']->placeholder => $cases['exception__embedded_response']->bigPipePlaceholderRenderArray,
|
||||
],
|
||||
],
|
||||
'_no_big_pipe absent, session, no-JS cookie absent: (JS-powered) BigPipe placeholder used for HTML placeholders — but unsafe method' => [$placeholders, 'POST', FALSE, TRUE, FALSE, []],
|
||||
'_no_big_pipe absent, session, no-JS cookie present: no-JS BigPipe placeholder used for HTML placeholders' => [$placeholders, 'GET', FALSE, TRUE, TRUE, [
|
||||
$cases['html']->placeholder => $cases['html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value']->placeholder => $cases['html_attribute_value']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value_subset']->placeholder => $cases['html_attribute_value_subset']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__invalid_html']->placeholder => $cases['edge_case__invalid_html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__html_non_lazy_builder']->placeholder => $cases['edge_case__html_non_lazy_builder']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['exception__lazy_builder']->placeholder => $cases['exception__lazy_builder']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['exception__embedded_response']->placeholder => $cases['exception__embedded_response']->bigPipeNoJsPlaceholderRenderArray,
|
||||
]],
|
||||
'_no_big_pipe absent, session, no-JS cookie present: no-JS BigPipe placeholder used for HTML placeholders' => [
|
||||
$placeholders, 'GET', FALSE, TRUE, TRUE, [
|
||||
$cases['html']->placeholder => $cases['html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value']->placeholder => $cases['html_attribute_value']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['html_attribute_value_subset']->placeholder => $cases['html_attribute_value_subset']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__invalid_html']->placeholder => $cases['edge_case__invalid_html']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['edge_case__html_non_lazy_builder']->placeholder => $cases['edge_case__html_non_lazy_builder']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['exception__lazy_builder']->placeholder => $cases['exception__lazy_builder']->bigPipeNoJsPlaceholderRenderArray,
|
||||
$cases['exception__embedded_response']->placeholder => $cases['exception__embedded_response']->bigPipeNoJsPlaceholderRenderArray,
|
||||
],
|
||||
],
|
||||
'_no_big_pipe absent, session, no-JS cookie present: no-JS BigPipe placeholder used for HTML placeholders — but unsafe method' => [$placeholders, 'POST', FALSE, TRUE, TRUE, []],
|
||||
];
|
||||
}
|
||||
|
|
Reference in a new issue