Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / big_pipe / tests / src / Unit / Render / BigPipeResponseAttachmentsProcessorTest.php
1 <?php
2
3 namespace Drupal\Tests\big_pipe\Unit\Render;
4
5 use Drupal\big_pipe\Render\BigPipeResponse;
6 use Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor;
7 use Drupal\Core\Ajax\AjaxResponse;
8 use Drupal\Core\Asset\AssetCollectionRendererInterface;
9 use Drupal\Core\Asset\AssetResolverInterface;
10 use Drupal\Core\Config\ConfigFactoryInterface;
11 use Drupal\Core\Extension\ModuleHandlerInterface;
12 use Drupal\Core\Render\AttachmentsInterface;
13 use Drupal\Core\Render\AttachmentsResponseProcessorInterface;
14 use Drupal\Core\Render\HtmlResponse;
15 use Drupal\Core\Render\RendererInterface;
16 use Drupal\Tests\UnitTestCase;
17 use Prophecy\Argument;
18 use Prophecy\Prophecy\ObjectProphecy;
19 use Symfony\Component\HttpFoundation\RequestStack;
20
21 /**
22  * @coversDefaultClass \Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor
23  * @group big_pipe
24  */
25 class BigPipeResponseAttachmentsProcessorTest extends UnitTestCase {
26
27   /**
28    * @covers ::processAttachments
29    *
30    * @dataProvider nonHtmlResponseProvider
31    */
32   public function testNonHtmlResponse($response_class) {
33     $big_pipe_response_attachments_processor = $this->createBigPipeResponseAttachmentsProcessor($this->prophesize(AttachmentsResponseProcessorInterface::class));
34
35     $non_html_response = new $response_class();
36     $this->setExpectedException(\AssertionError::class);
37     $big_pipe_response_attachments_processor->processAttachments($non_html_response);
38   }
39
40   public function nonHtmlResponseProvider() {
41     return [
42       'AjaxResponse, which implements AttachmentsInterface' => [AjaxResponse::class],
43       'A dummy that implements AttachmentsInterface' => [get_class($this->prophesize(AttachmentsInterface::class)->reveal())],
44     ];
45   }
46
47   /**
48    * @covers ::processAttachments
49    *
50    * @dataProvider attachmentsProvider
51    */
52   public function testHtmlResponse(array $attachments) {
53     $big_pipe_response = new BigPipeResponse(new HtmlResponse('original'));
54     $big_pipe_response->setAttachments($attachments);
55
56     // This mock is the main expectation of this test: verify that the decorated
57     // service (that is this mock) never receives BigPipe placeholder
58     // attachments, because it doesn't know (nor should it) how to handle them.
59     $html_response_attachments_processor = $this->prophesize(AttachmentsResponseProcessorInterface::class);
60     $html_response_attachments_processor->processAttachments(Argument::that(function ($response) {
61       return $response instanceof HtmlResponse && empty(array_intersect(['big_pipe_placeholders', 'big_pipe_nojs_placeholders'], array_keys($response->getAttachments())));
62     }))
63       ->will(function ($args) {
64         /** @var \Symfony\Component\HttpFoundation\Response|\Drupal\Core\Render\AttachmentsInterface $response */
65         $response = $args[0];
66         // Simulate its actual behavior.
67         $attachments = array_diff_key($response->getAttachments(), ['html_response_attachment_placeholders' => TRUE]);
68         $response->setContent('processed');
69         $response->setAttachments($attachments);
70         return $response;
71       })
72       ->shouldBeCalled();
73
74     $big_pipe_response_attachments_processor = $this->createBigPipeResponseAttachmentsProcessor($html_response_attachments_processor);
75     $processed_big_pipe_response = $big_pipe_response_attachments_processor->processAttachments($big_pipe_response);
76
77     // The secondary expectation of this test: the original (passed in) response
78     // object remains unchanged, the processed (returned) response object has
79     // the expected values.
80     $this->assertSame($attachments, $big_pipe_response->getAttachments(), 'Attachments of original response object MUST NOT be changed.');
81     $this->assertEquals('original', $big_pipe_response->getContent(), 'Content of original response object MUST NOT be changed.');
82     $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.');
83     $this->assertEquals('processed', $processed_big_pipe_response->getContent(), 'Content of returned (processed) response object MUST be changed.');
84   }
85
86   public function attachmentsProvider() {
87     $typical_cases = [
88       'no attachments' => [[]],
89       'libraries' => [['library' => ['core/drupal']]],
90       'libraries + drupalSettings' => [['library' => ['core/drupal'], 'drupalSettings' => ['foo' => 'bar']]],
91     ];
92
93     $official_attachment_types = ['html_head', 'feed', 'html_head_link', 'http_header', 'library', 'placeholders', 'drupalSettings', 'html_response_attachment_placeholders'];
94     $official_attachments_with_random_values = [];
95     foreach ($official_attachment_types as $type) {
96       $official_attachments_with_random_values[$type] = $this->randomMachineName();
97     }
98     $random_attachments = ['random' . $this->randomMachineName() => $this->randomMachineName()];
99     $edge_cases = [
100       '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],
101       'random attachment type (unofficial), with random assigned value, to prove BigPipeResponseAttachmentsProcessor is a perfect decorator' => [$random_attachments],
102     ];
103
104     $big_pipe_placeholder_attachments = ['big_pipe_placeholders' => [$this->randomMachineName()]];
105     $big_pipe_nojs_placeholder_attachments = ['big_pipe_nojs_placeholders' => [$this->randomMachineName()]];
106     $big_pipe_cases = [
107       'only big_pipe_placeholders' => [$big_pipe_placeholder_attachments],
108       'only big_pipe_nojs_placeholders' => [$big_pipe_nojs_placeholder_attachments],
109       'big_pipe_placeholders + big_pipe_nojs_placeholders' => [$big_pipe_placeholder_attachments + $big_pipe_nojs_placeholder_attachments],
110     ];
111
112     $combined_cases = [
113       '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],
114       'random attachment types + big_pipe_placeholders + big_pipe_nojs_placeholders' => [$random_attachments + $big_pipe_placeholder_attachments + $big_pipe_nojs_placeholder_attachments],
115     ];
116
117     return $typical_cases + $edge_cases + $big_pipe_cases + $combined_cases;
118   }
119
120   /**
121    * Creates a BigPipeResponseAttachmentsProcessor with mostly dummies.
122    *
123    * @param \Prophecy\Prophecy\ObjectProphecy $decorated_html_response_attachments_processor
124    *   An object prophecy implementing AttachmentsResponseProcessorInterface.
125    *
126    * @return \Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor
127    *   The BigPipeResponseAttachmentsProcessor to test.
128    */
129   protected function createBigPipeResponseAttachmentsProcessor(ObjectProphecy $decorated_html_response_attachments_processor) {
130     return new BigPipeResponseAttachmentsProcessor(
131       $decorated_html_response_attachments_processor->reveal(),
132       $this->prophesize(AssetResolverInterface::class)->reveal(),
133       $this->prophesize(ConfigFactoryInterface::class)->reveal(),
134       $this->prophesize(AssetCollectionRendererInterface::class)->reveal(),
135       $this->prophesize(AssetCollectionRendererInterface::class)->reveal(),
136       $this->prophesize(RequestStack::class)->reveal(),
137       $this->prophesize(RendererInterface::class)->reveal(),
138       $this->prophesize(ModuleHandlerInterface::class)->reveal()
139     );
140   }
141
142 }