 .../Render/Placeholder/BigPipeStrategyTest.php     | 160 +++++++++++++++++++++
 1 file changed, 160 insertions(+)

diff --git a/tests/src/Unit/Render/Placeholder/BigPipeStrategyTest.php b/tests/src/Unit/Render/Placeholder/BigPipeStrategyTest.php
new file mode 100644
index 0000000..8409bc7
--- /dev/null
+++ b/tests/src/Unit/Render/Placeholder/BigPipeStrategyTest.php
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\big_pipe\Unit\Render\Placeholder\BigPipeStrategyTest.
+ */
+
+namespace Drupal\Tests\big_pipe\Unit\Render\Placeholder;
+
+use Drupal\big_pipe\Render\Placeholder\BigPipeStrategy;
+use Drupal\Core\Session\SessionConfigurationInterface;
+use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * @coversDefaultClass \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
+ * @group big_pipe
+ */
+class BigPipeStrategyTest extends UnitTestCase {
+
+  /**
+   * @covers ::processPlaceholders
+   *
+   * @dataProvider placeholdersProvider
+   */
+  public function testProcessPlaceholders(array $placeholders, $request_has_session, $request_has_big_pipe_nojs_cookie, array $expected_big_pipe_placeholders) {
+    $request = new Request();
+    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)
+      ->shouldBeCalled();
+
+    $session_configuration = $this->prophesize(SessionConfigurationInterface::class);
+    $session_configuration->hasSession(Argument::type(Request::class))
+      ->willReturn($request_has_session)
+      ->shouldBeCalled();
+
+    $big_pipe_strategy = new BigPipeStrategy($session_configuration->reveal(), $request_stack->reveal());
+    $processed_placeholders = $big_pipe_strategy->processPlaceholders($placeholders);
+    $this->assertSame($expected_big_pipe_placeholders, $processed_placeholders);
+  }
+
+  public function placeholdersProvider() {
+    // 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'],
+    ];
+
+    // Real-world example of HTML placeholder.
+    $messages_placeholder_markup = '<drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="a8c34b5e"></drupal-render-placeholder>';
+    $placeholders[$messages_placeholder_markup] = [
+      '#lazy_builder' => [
+        'Drupal\Core\Render\Element\StatusMessages::renderMessages',
+        [NULL]
+      ],
+    ];
+    $messages_big_pipe_placeholder = [
+      '#markup' => '<div data-big-pipe-selector="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&amp;args[0]&amp;token=a8c34b5e"></div>',
+      '#cache' => $cacheability_depends_on_session_and_nojs_cookie,
+      '#attached' => [
+        'library' => ['big_pipe/big_pipe'],
+        'drupalSettings' => [
+          'bigPipePlaceholders' => [
+            'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args[0]&token=a8c34b5e' => TRUE,
+          ],
+        ],
+        'big_pipe_placeholders' => [
+          'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&amp;args[0]&amp;token=a8c34b5e' => $placeholders[$messages_placeholder_markup],
+        ],
+      ],
+    ];
+    $messages_big_pipe_nojs_placeholder = [
+      '#markup' => '<div data-big-pipe-selector-nojs="drupal-render-placeholder-callbackdrupalcorerenderelementstatusmessagesrendermessages-arguments0-tokena8c34b5edrupal-render-placeholder"></div>',
+      '#cache' => $cacheability_depends_on_session_and_nojs_cookie,
+      '#attached' => [
+        'big_pipe_nojs_placeholders' => [
+          'drupal-render-placeholder-callbackdrupalcorerenderelementstatusmessagesrendermessages-arguments0-tokena8c34b5edrupal-render-placeholder' => $placeholders[$messages_placeholder_markup],
+        ],
+      ],
+    ];
+
+    // Real-world example of HTML attribute value placeholder.
+    $placeholders['form_action_cc611e1d'] = [
+      '#lazy_builder' => ['form_builder:renderPlaceholderFormAction', []],
+    ];
+    $form_action_big_pipe_nojs_placeholder = [
+      '#markup' => '<div data-big-pipe-selector-nojs="form-action-cc611e1d"></div>',
+      '#cache' => $cacheability_depends_on_session_only,
+      '#attached' => [
+        'big_pipe_nojs_placeholders' => [
+          'form-action-cc611e1d' => $placeholders['form_action_cc611e1d'],
+        ],
+      ],
+    ];
+
+    // Real-world example of HTML attribute value subset placeholder.
+    $placeholders['22dcc695f4a22e809a62d8eb7addd6fccecfbf31'] = [
+      '#lazy_builder' => [
+        'route_processor_csrf:renderPlaceholderCsrfToken',
+        ['admin/config/user-interface/shortcut/manage/default/add-link-inline']
+      ],
+    ];
+    $csrf_token_big_pipe_nojs_placeholder = [
+      '#markup' => '<div data-big-pipe-selector-nojs="22dcc695f4a22e809a62d8eb7addd6fccecfbf31"></div>',
+      '#cache' => $cacheability_depends_on_session_only,
+      '#attached' => [
+        'big_pipe_nojs_placeholders' => [
+          '22dcc695f4a22e809a62d8eb7addd6fccecfbf31' => $placeholders['22dcc695f4a22e809a62d8eb7addd6fccecfbf31'],
+        ],
+      ],
+    ];
+
+    // Edge case: custom string to be considered as a placeholder that happens
+    // to not be valid HTML.
+    $placeholders['<hello'] = [
+      '#lazy_builder' => [
+        'hello_or_yarhar',
+        []
+      ],
+    ];
+    $hello_big_pipe_nojs_placeholder = [
+      '#markup' => '<div data-big-pipe-selector-nojs="hello"></div>',
+      '#cache' => $cacheability_depends_on_session_only,
+      '#attached' => [
+        'big_pipe_nojs_placeholders' => [
+          'hello' => $placeholders['<hello'],
+        ],
+      ],
+    ];
+
+    return [
+      'no session, no-JS cookie absent' => [$placeholders, FALSE, FALSE, []],
+      'no session, no-JS cookie present' => [$placeholders, FALSE, TRUE, []],
+      'session, no-JS cookie absent: (JS-powered) BigPipe placeholder used for HTML placeholders' => [$placeholders, TRUE, FALSE, [
+        $messages_placeholder_markup => $messages_big_pipe_placeholder,
+        'form_action_cc611e1d' => $form_action_big_pipe_nojs_placeholder,
+        '22dcc695f4a22e809a62d8eb7addd6fccecfbf31' => $csrf_token_big_pipe_nojs_placeholder,
+        '<hello' => $hello_big_pipe_nojs_placeholder,
+      ]],
+      'session, no-JS cookie present: no-JS BigPipe placeholder used for HTML placeholders' => [$placeholders, TRUE, TRUE, [
+        $messages_placeholder_markup => $messages_big_pipe_nojs_placeholder,
+        'form_action_cc611e1d' => $form_action_big_pipe_nojs_placeholder,
+        '22dcc695f4a22e809a62d8eb7addd6fccecfbf31' => $csrf_token_big_pipe_nojs_placeholder,
+        '<hello' => $hello_big_pipe_nojs_placeholder,
+      ]],
+    ];
+  }
+
+}
