Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,6 @@
name: 'BigPipe regression test'
type: module
description: 'Support module for BigPipe regression testing.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,6 @@
big_pipe_regression_test.2678662:
path: '/big_pipe_regression_test/2678662'
defaults:
_controller: '\Drupal\big_pipe_regression_test\BigPipeRegressionTestController::regression2678662'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,20 @@
<?php
namespace Drupal\big_pipe_regression_test;
use Drupal\big_pipe\Render\BigPipeMarkup;
class BigPipeRegressionTestController {
const MARKER_2678662 = '<script>var hitsTheFloor = "</body>";</script>';
/**
* @see \Drupal\Tests\big_pipe\FunctionalJavascript\BigPipeRegressionTest::testMultipleBodies_2678662()
*/
public function regression2678662() {
return [
'#markup' => BigPipeMarkup::create(self::MARKER_2678662),
];
}
}

View file

@ -0,0 +1,6 @@
name: 'BigPipe test'
type: module
description: 'Support module for BigPipe testing.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,18 @@
<?php
/**
* @file
* Support module for BigPipe testing.
*/
/**
* Implements hook_page_top().
*/
function big_pipe_test_page_top(array &$page_top) {
// Ensure this hook is invoked on every page load.
$page_top['#cache']['max-age'] = 0;
if (\Drupal::request()->query->get('trigger_session')) {
$_SESSION['big_pipe_test'] = TRUE;
}
}

View file

@ -0,0 +1,26 @@
big_pipe_test:
path: '/big_pipe_test'
defaults:
_controller: '\Drupal\big_pipe_test\BigPipeTestController::test'
_title: 'BigPipe test'
requirements:
_access: 'TRUE'
no_big_pipe:
path: '/no_big_pipe'
defaults:
_controller: '\Drupal\big_pipe_test\BigPipeTestController::nope'
_title: '_no_big_pipe route option test'
options:
_no_big_pipe: TRUE
requirements:
_access: 'TRUE'
big_pipe_test_multi_occurrence:
path: '/big_pipe_test_multi_occurrence'
defaults:
_controller: '\Drupal\big_pipe_test\BigPipeTestController::multiOccurrence'
_title: 'BigPipe test multiple occurrences of the same placeholder'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,5 @@
services:
big_pipe_test_subscriber:
class: Drupal\big_pipe_test\EventSubscriber\BigPipeTestSubscriber
tags:
- { name: event_subscriber }

View file

@ -0,0 +1,152 @@
<?php
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 {
/**
* Returns a all BigPipe placeholder test case render arrays.
*
* @return array
*/
public function test() {
$build = [];
$cases = BigPipePlaceholderTestCases::cases(\Drupal::getContainer());
// 1. HTML placeholder: status messages. Drupal renders those automatically,
// so all that we need to do in this controller is set a message.
drupal_set_message('Hello from BigPipe!');
$build['html'] = $cases['html']->renderArray;
// 2. HTML attribute value placeholder: form action.
$build['html_attribute_value'] = $cases['html_attribute_value']->renderArray;
// 3. HTML attribute value subset placeholder: CSRF token in link.
$build['html_attribute_value_subset'] = $cases['html_attribute_value_subset']->renderArray;
// 4. Edge case: custom string to be considered as a placeholder that
// happens to not be valid HTML.
$build['edge_case__invalid_html'] = $cases['edge_case__invalid_html']->renderArray;
// 5. Edge case: non-#lazy_builder placeholder.
$build['edge_case__html_non_lazy_builder'] = $cases['edge_case__html_non_lazy_builder']->renderArray;
// 6. Exception: #lazy_builder that throws an exception.
$build['exception__lazy_builder'] = $cases['exception__lazy_builder']->renderArray;
// 7. Exception: placeholder that causes response filter to throw exception.
$build['exception__embedded_response'] = $cases['exception__embedded_response']->renderArray;
return $build;
}
/**
* @return array
*/
public static function nope() {
return ['#markup' => '<p>Nope.</p>'];
}
/**
* A page with multiple occurrences of the same placeholder.
*
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
*
* @return array
*/
public function multiOccurrence() {
return [
'item1' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
'item2' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
'item3' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
];
}
/**
* #lazy_builder callback; builds <time> markup with current time.
*
* Note: does not actually use current time, that would complicate testing.
*
* @return array
*/
public static function currentTime() {
return [
'#markup' => '<time datetime="' . date('Y-m-d', 668948400) . '"></time>',
'#cache' => ['max-age' => 0]
];
}
/**
* #lazy_builder callback; says "hello" or "yarhar".
*
* @return array
*/
public static function helloOrYarhar() {
return [
'#markup' => BigPipeMarkup::create('<marquee>Yarhar llamas forever!</marquee>'),
'#cache' => ['max-age' => 0],
];
}
/**
* #lazy_builder callback; throws exception.
*
* @throws \Exception
*/
public static function exception() {
throw new \Exception('You are not allowed to say llamas are not cool!');
}
/**
* #lazy_builder callback; returns content that will trigger an exception.
*
* @see \Drupal\big_pipe_test\EventSubscriber\BigPipeTestSubscriber::onRespondTriggerException()
*
* @return array
*/
public static function responseException() {
return ['#plain_text' => BigPipeTestSubscriber::CONTENT_TRIGGER_EXCEPTION];
}
/**
* #lazy_builder callback; returns the current count.
*
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
*
* @return array
* The render array.
*/
public static function counter() {
// Lazy builders are not allowed to build their own state like this function
// does, but in this case we're intentionally doing that for testing
// purposes: so we can ensure that each lazy builder is only ever called
// once with the same parameters.
static $count;
if (!isset($count)) {
$count = 0;
}
$count++;
return [
'#markup' => BigPipeMarkup::create("<p>The count is $count.</p>"),
'#cache' => ['max-age' => 0],
];
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Drupal\big_pipe_test\EventSubscriber;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\HtmlResponse;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class BigPipeTestSubscriber implements EventSubscriberInterface {
/**
* @see \Drupal\big_pipe_test\BigPipeTestController::responseException()
*
* @var string
*/
const CONTENT_TRIGGER_EXCEPTION = 'NOPE!NOPE!NOPE!';
/**
* Triggers exception for embedded HTML/AJAX responses with certain content.
*
* @see \Drupal\big_pipe_test\BigPipeTestController::responseException()
*
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
* The event to process.
*
* @throws \Exception
*/
public function onRespondTriggerException(FilterResponseEvent $event) {
$response = $event->getResponse();
if (!$response instanceof AttachmentsInterface) {
return;
}
$attachments = $response->getAttachments();
if (!isset($attachments['big_pipe_placeholders']) && !isset($attachments['big_pipe_nojs_placeholders'])) {
if (strpos($response->getContent(), static::CONTENT_TRIGGER_EXCEPTION) !== FALSE) {
throw new \Exception('Oh noes!');
}
}
}
/**
* Exposes all BigPipe placeholders (JS and no-JS) via headers for testing.
*
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
* The event to process.
*/
public function onRespondSetBigPipeDebugPlaceholderHeaders(FilterResponseEvent $event) {
$response = $event->getResponse();
if (!$response instanceof HtmlResponse) {
return;
}
$attachments = $response->getAttachments();
$response->headers->set('BigPipe-Test-Placeholders', '<none>');
$response->headers->set('BigPipe-Test-No-Js-Placeholders', '<none>');
if (!empty($attachments['big_pipe_placeholders'])) {
$response->headers->set('BigPipe-Test-Placeholders', implode(' ', array_keys($attachments['big_pipe_placeholders'])));
}
if (!empty($attachments['big_pipe_nojs_placeholders'])) {
$response->headers->set('BigPipe-Test-No-Js-Placeholders', implode(' ', array_map('rawurlencode', array_keys($attachments['big_pipe_nojs_placeholders']))));
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Run just before \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber::onRespond().
$events[KernelEvents::RESPONSE][] = ['onRespondSetBigPipeDebugPlaceholderHeaders', -9999];
// Run just after \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber::onRespond().
$events[KernelEvents::RESPONSE][] = ['onRespondTriggerException', -10001];
return $events;
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Drupal\big_pipe_test\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class BigPipeTestForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'big_pipe_test_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#token'] = FALSE;
$form['big_pipe'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('BigPipe works…'),
'#options' => [
'js' => $this->t('… with JavaScript'),
'nojs' => $this->t('… without JavaScript'),
],
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) { }
}

View file

@ -0,0 +1,187 @@
<?php
namespace Drupal\Tests\big_pipe\FunctionalJavascript;
use Drupal\big_pipe\Render\BigPipe;
use Drupal\big_pipe_regression_test\BigPipeRegressionTestController;
use Drupal\comment\CommentInterface;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
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\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\NodeCreationTrait;
/**
* BigPipe regression tests.
*
* @group big_pipe
*/
class BigPipeRegressionTest extends JavascriptTestBase {
use CommentTestTrait;
use ContentTypeCreationTrait;
use NodeCreationTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'big_pipe',
'big_pipe_regression_test',
];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Use the big_pipe_test_theme theme.
$this->container->get('theme_installer')->install(['big_pipe_test_theme']);
$this->container->get('config.factory')->getEditable('system.theme')->set('default', 'big_pipe_test_theme')->save();
}
/**
* Ensure comment form works with history and big_pipe modules.
*
* @see https://www.drupal.org/node/2698811
*/
public function testCommentForm_2698811() {
$this->assertTrue($this->container->get('module_installer')->install(['comment', 'history', 'ckeditor'], TRUE), 'Installed modules.');
// Ensure an `article` node type exists.
$this->createContentType(['type' => 'article']);
$this->addDefaultCommentField('node', 'article');
// Enable CKEditor.
$format = $this->randomMachineName();
FilterFormat::create([
'format' => $format,
'name' => $this->randomString(),
'weight' => 1,
'filters' => [],
])->save();
$settings['toolbar']['rows'] = [
[
[
'name' => 'Links',
'items' => [
'DrupalLink',
'DrupalUnlink',
],
],
],
];
$editor = Editor::create([
'format' => $format,
'editor' => 'ckeditor',
]);
$editor->setSettings($settings);
$editor->save();
$admin_user = $this->drupalCreateUser([
'access comments',
'post comments',
'use text format ' . $format,
]);
$this->drupalLogin($admin_user);
$node = $this->createNode([
'type' => 'article',
'comment' => CommentItemInterface::OPEN,
]);
// Create some comments.
foreach (range(1, 5) as $i) {
$comment = Comment::create([
'status' => CommentInterface::PUBLISHED,
'field_name' => 'comment',
'entity_type' => 'node',
'entity_id' => $node->id(),
]);
$comment->save();
}
$this->drupalGet($node->toUrl()->toString());
// Confirm that CKEditor loaded.
$javascript = <<<JS
(function(){
return Object.keys(CKEDITOR.instances).length > 0;
}());
JS;
$this->assertJsCondition($javascript);
}
/**
* Ensure BigPipe works despite inline JS containing the string "</body>".
*
* @see https://www.drupal.org/node/2678662
*/
public function testMultipleClosingBodies_2678662() {
$this->assertTrue($this->container->get('module_installer')->install(['render_placeholder_message_test'], TRUE), 'Installed modules.');
$this->drupalLogin($this->drupalCreateUser());
$this->drupalGet(Url::fromRoute('big_pipe_regression_test.2678662'));
// Confirm that AJAX behaviors were instantiated, if not, this points to a
// JavaScript syntax error.
$javascript = <<<JS
(function(){
return Object.keys(Drupal.ajax.instances).length > 0;
}());
JS;
$this->assertJsCondition($javascript);
// Besides verifying there is no JavaScript syntax error, also verify the
// HTML structure.
$this->assertSession()
->responseContains(BigPipe::STOP_SIGNAL . "\n\n\n</body></html>", 'The BigPipe stop signal is present just before the closing </body> and </html> tags.');
$js_code_until_closing_body_tag = substr(BigPipeRegressionTestController::MARKER_2678662, 0, strpos(BigPipeRegressionTestController::MARKER_2678662, '</body>'));
$this->assertSession()
->responseNotContains($js_code_until_closing_body_tag . "\n" . BigPipe::START_SIGNAL, 'The BigPipe start signal does NOT start at the closing </body> tag string in an inline script.');
}
/**
* Ensure messages set in placeholders always appear.
*
* @see https://www.drupal.org/node/2712935
*/
public function testMessages_2712935() {
$this->assertTrue($this->container->get('module_installer')->install(['render_placeholder_message_test'], TRUE), 'Installed modules.');
$this->drupalLogin($this->drupalCreateUser());
$messages_markup = '<div role="contentinfo" aria-label="Status message"';
$test_routes = [
// Messages placeholder rendered first.
'render_placeholder_message_test.first',
// Messages placeholder rendered after one, before another.
'render_placeholder_message_test.middle',
// Messages placeholder rendered last.
'render_placeholder_message_test.last',
];
$assert = $this->assertSession();
foreach ($test_routes as $route) {
// Verify that we start off with zero messages queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
// Verify the test case at this route behaves as expected.
$this->drupalGet(Url::fromRoute($route));
$assert->elementContains('css', 'p.logged-message:nth-of-type(1)', 'Message: P1');
$assert->elementContains('css', 'p.logged-message:nth-of-type(2)', 'Message: P2');
$assert->responseContains($messages_markup);
$assert->elementExists('css', 'div[aria-label="Status message"] ul');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(1)', 'P1');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(2)', 'P2');
// Verify that we end with all messages printed, hence again zero queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
}
}
}

View file

@ -0,0 +1,143 @@
<?php
namespace Drupal\Tests\big_pipe\Unit\Render;
use Drupal\big_pipe\Render\BigPipeResponse;
use Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Asset\AssetCollectionRendererInterface;
use Drupal\Core\Asset\AssetResolverInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\AttachmentsResponseProcessorInterface;
use Drupal\Core\Render\HtmlResponse;
use Drupal\Core\Render\RendererInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* @coversDefaultClass \Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor
* @group big_pipe
*/
class BigPipeResponseAttachmentsProcessorTest extends UnitTestCase {
/**
* @covers ::processAttachments
*
* @dataProvider nonHtmlResponseProvider
*
* @expectedException \AssertionError
*/
public function testNonHtmlResponse($response_class) {
$big_pipe_response_attachments_processor = $this->createBigPipeResponseAttachmentsProcessor($this->prophesize(AttachmentsResponseProcessorInterface::class));
$non_html_response = new $response_class();
$big_pipe_response_attachments_processor->processAttachments($non_html_response);
}
function nonHtmlResponseProvider() {
return [
'AjaxResponse, which implements AttachmentsInterface' => [AjaxResponse::class],
'A dummy that implements AttachmentsInterface' => [get_class($this->prophesize(AttachmentsInterface::class)->reveal())],
];
}
/**
* @covers ::processAttachments
*
* @dataProvider attachmentsProvider
*/
public function testHtmlResponse(array $attachments) {
$big_pipe_response = new BigPipeResponse('original');
$big_pipe_response->setAttachments($attachments);
// This mock is the main expectation of this test: verify that the decorated
// service (that is this mock) never receives BigPipe placeholder
// attachments, because it doesn't know (nor should it) how to handle them.
$html_response_attachments_processor = $this->prophesize(AttachmentsResponseProcessorInterface::class);
$html_response_attachments_processor->processAttachments(Argument::that(function ($response) {
return $response instanceof HtmlResponse && empty(array_intersect(['big_pipe_placeholders', 'big_pipe_nojs_placeholders'], array_keys($response->getAttachments())));
}))
->will(function ($args) {
/** @var \Symfony\Component\HttpFoundation\Response|\Drupal\Core\Render\AttachmentsInterface $response */
$response = $args[0];
// Simulate its actual behavior.
$attachments = array_diff_key($response->getAttachments(), ['html_response_attachment_placeholders' => TRUE]);
$response->setContent('processed');
$response->setAttachments($attachments);
return $response;
})
->shouldBeCalled();
$big_pipe_response_attachments_processor = $this->createBigPipeResponseAttachmentsProcessor($html_response_attachments_processor);
$processed_big_pipe_response = $big_pipe_response_attachments_processor->processAttachments($big_pipe_response);
// The secondary expectation of this test: the original (passed in) response
// object remains unchanged, the processed (returned) response object has
// the expected values.
$this->assertSame($attachments, $big_pipe_response->getAttachments(), 'Attachments of original response object MUST NOT be changed.');
$this->assertEquals('original', $big_pipe_response->getContent(), 'Content of original response object MUST NOT be changed.');
$this->assertEquals(array_diff_key($attachments, ['html_response_attachment_placeholders' => TRUE]), $processed_big_pipe_response->getAttachments(), 'Attachments of returned (processed) response object MUST be changed.');
$this->assertEquals('processed', $processed_big_pipe_response->getContent(), 'Content of returned (processed) response object MUST be changed.');
}
public function attachmentsProvider() {
$typical_cases = [
'no attachments' => [[]],
'libraries' => [['library' => ['core/drupal']]],
'libraries + drupalSettings' => [['library' => ['core/drupal'], 'drupalSettings' => ['foo' => 'bar']]],
];
$official_attachment_types = ['html_head', 'feed', 'html_head_link', 'http_header', 'library', 'placeholders', 'drupalSettings', 'html_response_attachment_placeholders'];
$official_attachments_with_random_values = [];
foreach ($official_attachment_types as $type) {
$official_attachments_with_random_values[$type] = $this->randomMachineName();
}
$random_attachments = ['random' . $this->randomMachineName() => $this->randomMachineName()];
$edge_cases = [
'all official attachment types, with random assigned values, even if technically not valid, to prove BigPipeResponseAttachmentsProcessor is a perfect decorator' => [$official_attachments_with_random_values],
'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_cases = [
'only big_pipe_placeholders' => [$big_pipe_placeholder_attachments],
'only big_pipe_nojs_placeholders' => [$big_pipe_nojs_placeholder_attachments],
'big_pipe_placeholders + big_pipe_nojs_placeholders' => [$big_pipe_placeholder_attachments + $big_pipe_nojs_placeholder_attachments],
];
$combined_cases = [
'all official attachment types + big_pipe_placeholders + big_pipe_nojs_placeholders' => [$official_attachments_with_random_values + $big_pipe_placeholder_attachments + $big_pipe_nojs_placeholder_attachments],
'random attachment types + big_pipe_placeholders + big_pipe_nojs_placeholders' => [$random_attachments + $big_pipe_placeholder_attachments + $big_pipe_nojs_placeholder_attachments],
];
return $typical_cases + $edge_cases + $big_pipe_cases + $combined_cases;
}
/**
* Creates a BigPipeResponseAttachmentsProcessor with mostly dummies.
*
* @param \Prophecy\Prophecy\ObjectProphecy $decorated_html_response_attachments_processor
* An object prophecy implementing AttachmentsResponseProcessorInterface.
*
* @return \Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor
* The BigPipeResponseAttachmentsProcessor to test.
*/
protected function createBigPipeResponseAttachmentsProcessor(ObjectProphecy $decorated_html_response_attachments_processor) {
return new BigPipeResponseAttachmentsProcessor(
$decorated_html_response_attachments_processor->reveal(),
$this->prophesize(AssetResolverInterface::class)->reveal(),
$this->prophesize(ConfigFactoryInterface::class)->reveal(),
$this->prophesize(AssetCollectionRendererInterface::class)->reveal(),
$this->prophesize(AssetCollectionRendererInterface::class)->reveal(),
$this->prophesize(RequestStack::class)->reveal(),
$this->prophesize(RendererInterface::class)->reveal(),
$this->prophesize(ModuleHandlerInterface::class)->reveal()
);
}
}

View file

@ -0,0 +1,109 @@
<?php
namespace Drupal\Tests\big_pipe\Unit\Render\Placeholder;
use Drupal\big_pipe\Render\Placeholder\BigPipeStrategy;
use Drupal\big_pipe\Tests\BigPipePlaceholderTestCases;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\SessionConfigurationInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Route;
/**
* @coversDefaultClass \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
* @group big_pipe
*/
class BigPipeStrategyTest extends UnitTestCase {
/**
* @covers ::processPlaceholders
*
* @dataProvider placeholdersProvider
*/
public function testProcessPlaceholders(array $placeholders, $method, $route_match_has_no_big_pipe_option, $request_has_session, $request_has_big_pipe_nojs_cookie, array $expected_big_pipe_placeholders) {
$request = new Request();
$request->setMethod($method);
if ($request_has_big_pipe_nojs_cookie) {
$request->cookies->set(BigPipeStrategy::NOJS_COOKIE, 1);
}
$request_stack = $this->prophesize(RequestStack::class);
$request_stack->getCurrentRequest()
->willReturn($request);
$session_configuration = $this->prophesize(SessionConfigurationInterface::class);
$session_configuration->hasSession(Argument::type(Request::class))
->willReturn($request_has_session);
$route = $this->prophesize(Route::class);
$route->getOption('_no_big_pipe')
->willReturn($route_match_has_no_big_pipe_option);
$route_match = $this->prophesize(RouteMatchInterface::class);
$route_match->getRouteObject()
->willReturn($route);
$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) {
$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'");
}
}
else {
$this->assertSame(0, count($processed_placeholders));
}
}
/**
* @see \Drupal\big_pipe\Tests\BigPipePlaceholderTestCases
*/
public function placeholdersProvider() {
$cases = BigPipePlaceholderTestCases::cases();
// Generate $placeholders variable as expected by
// \Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface::processPlaceholders().
$placeholders = [
$cases['html']->placeholder => $cases['html']->placeholderRenderArray,
$cases['html_attribute_value']->placeholder => $cases['html_attribute_value']->placeholderRenderArray,
$cases['html_attribute_value_subset']->placeholder => $cases['html_attribute_value_subset']->placeholderRenderArray,
$cases['edge_case__invalid_html']->placeholder => $cases['edge_case__invalid_html']->placeholderRenderArray,
$cases['edge_case__html_non_lazy_builder']->placeholder => $cases['edge_case__html_non_lazy_builder']->placeholderRenderArray,
$cases['exception__lazy_builder']->placeholder => $cases['exception__lazy_builder']->placeholderRenderArray,
$cases['exception__embedded_response']->placeholder => $cases['exception__embedded_response']->placeholderRenderArray,
];
return [
'_no_big_pipe absent, no session, no-JS cookie absent' => [$placeholders, 'GET', FALSE, FALSE, FALSE, []],
'_no_big_pipe absent, no session, no-JS cookie present' => [$placeholders, 'GET', FALSE, FALSE, TRUE, []],
'_no_big_pipe present, no session, no-JS cookie absent' => [$placeholders, 'GET', TRUE, FALSE, FALSE, []],
'_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 — 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 — but unsafe method' => [$placeholders, 'POST', FALSE, TRUE, TRUE, []],
];
}
}

View file

@ -0,0 +1,5 @@
name: 'BigPipe test theme'
type: theme
description: 'Theme for testing BigPipe edge cases.'
version: VERSION
core: 8.x

View file

@ -0,0 +1,13 @@
{#
/**
* @file
* Test that comments still work with the form above instead of below.
*
* @see \Drupal\Tests\big_pipe\FunctionalJavascript\BigPipeRegressionTest::testCommentForm_2698811()
*/
#}
<section{{ attributes }}>
{{ comment_form }}
{{ comments }}
</section>