BigPipeResponseAttachmentsProcessorTest.php 7.32 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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
   */
  public function testNonHtmlResponse($response_class) {
    $big_pipe_response_attachments_processor = $this->createBigPipeResponseAttachmentsProcessor($this->prophesize(AttachmentsResponseProcessorInterface::class));

    $non_html_response = new $response_class();
36
    $this->setExpectedException(\AssertionError::class);
37
38
39
    $big_pipe_response_attachments_processor->processAttachments($non_html_response);
  }

40
  public function nonHtmlResponseProvider() {
41
42
43
44
45
46
47
48
49
50
51
52
    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) {
53
    $big_pipe_response = new BigPipeResponse(new HtmlResponse('original'));
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    $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],
    ];

104
105
    $big_pipe_placeholder_attachments = ['big_pipe_placeholders' => [$this->randomMachineName()]];
    $big_pipe_nojs_placeholder_attachments = ['big_pipe_nojs_placeholders' => [$this->randomMachineName()]];
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    $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()
    );
  }

}