You are here

protected function ResponsiveImageFieldDisplayTest::doTestResponsiveImageFieldFormatters in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php \Drupal\Tests\responsive_image\Functional\ResponsiveImageFieldDisplayTest::doTestResponsiveImageFieldFormatters()

Tests responsive image formatters on node display.

If the empty styles param is set, then the function only tests for the fallback image style (large).

Parameters

string $scheme: File scheme to use.

bool $empty_styles: If true, use an empty string for image style names. Defaults to false.

3 calls to ResponsiveImageFieldDisplayTest::doTestResponsiveImageFieldFormatters()
ResponsiveImageFieldDisplayTest::testResponsiveImageFieldFormattersEmptyStyle in core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php
Tests responsive image formatters when image style is empty.
ResponsiveImageFieldDisplayTest::testResponsiveImageFieldFormattersPrivate in core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php
Tests responsive image formatters on node display for private files.
ResponsiveImageFieldDisplayTest::testResponsiveImageFieldFormattersPublic in core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php
Tests responsive image formatters on node display for public files.

File

core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php, line 189

Class

ResponsiveImageFieldDisplayTest
Tests responsive image display formatter.

Namespace

Drupal\Tests\responsive_image\Functional

Code

protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles = FALSE) {

  /** @var \Drupal\Core\Render\RendererInterface $renderer */
  $renderer = $this->container
    ->get('renderer');
  $node_storage = $this->container
    ->get('entity_type.manager')
    ->getStorage('node');
  $field_name = mb_strtolower($this
    ->randomMachineName());
  $this
    ->createImageField($field_name, 'article', [
    'uri_scheme' => $scheme,
  ]);

  // Create a new node with an image attached. Make sure we use a large image
  // so the scale effects of the image styles always have an effect.
  $test_image = current($this
    ->getTestFiles('image', 39325));

  // Create alt text for the image.
  $alt = $this
    ->randomMachineName();
  $nid = $this
    ->uploadNodeImage($test_image, $field_name, 'article', $alt);
  $node_storage
    ->resetCache([
    $nid,
  ]);
  $node = $node_storage
    ->load($nid);

  // Test that the default formatter is being used.
  $image_uri = File::load($node->{$field_name}->target_id)
    ->getFileUri();
  $image = [
    '#theme' => 'image',
    '#uri' => $image_uri,
    '#width' => 360,
    '#height' => 240,
    '#alt' => $alt,
  ];
  $default_output = str_replace("\n", NULL, $renderer
    ->renderRoot($image));
  $this
    ->assertSession()
    ->responseContains($default_output);

  // Test field not being configured. This should not cause a fatal error.
  $display_options = [
    'type' => 'responsive_image_test',
    'settings' => ResponsiveImageFormatter::defaultSettings(),
  ];
  $display = $this->container
    ->get('entity_type.manager')
    ->getStorage('entity_view_display')
    ->load('node.article.default');
  if (!$display) {
    $values = [
      'targetEntityType' => 'node',
      'bundle' => 'article',
      'mode' => 'default',
      'status' => TRUE,
    ];
    $display = $this->container
      ->get('entity_type.manager')
      ->getStorage('entity_view_display')
      ->create($values);
  }
  $display
    ->setComponent($field_name, $display_options)
    ->save();
  $this
    ->drupalGet('node/' . $nid);

  // Test theme function for responsive image, but using the test formatter.
  $display_options = [
    'type' => 'responsive_image_test',
    'settings' => [
      'image_link' => 'file',
      'responsive_image_style' => 'style_one',
    ],
  ];

  /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
  $display_repository = \Drupal::service('entity_display.repository');
  $display = $display_repository
    ->getViewDisplay('node', 'article');
  $display
    ->setComponent($field_name, $display_options)
    ->save();
  $this
    ->drupalGet('node/' . $nid);

  // Use the responsive image formatter linked to file formatter.
  $display_options = [
    'type' => 'responsive_image',
    'settings' => [
      'image_link' => 'file',
      'responsive_image_style' => 'style_one',
    ],
  ];
  $display = $display_repository
    ->getViewDisplay('node', 'article');
  $display
    ->setComponent($field_name, $display_options)
    ->save();
  $this
    ->drupalGet('node/' . $nid);

  // No image style cache tag should be found.
  $this
    ->assertSession()
    ->responseHeaderNotContains('X-Drupal-Cache-Tags', 'image_style:');
  $this
    ->assertSession()
    ->responseMatches('/<a(.*?)href="' . preg_quote($this->fileUrlGenerator
    ->generateString($image_uri), '/') . '"(.*?)>\\s*<picture/');

  // Verify that the image can be downloaded.
  $this
    ->assertEquals(file_get_contents($test_image->uri), $this
    ->drupalGet($this->fileUrlGenerator
    ->generateAbsoluteString($image_uri)), 'File was downloaded successfully.');
  if ($scheme == 'private') {

    // Only verify HTTP headers when using private scheme and the headers are
    // sent by Drupal.
    $this
      ->assertSession()
      ->responseHeaderEquals('Content-Type', 'image/png');
    $this
      ->assertSession()
      ->responseHeaderContains('Cache-Control', 'private');

    // Log out and ensure the file cannot be accessed.
    $this
      ->drupalLogout();
    $this
      ->drupalGet($this->fileUrlGenerator
      ->generateAbsoluteString($image_uri));
    $this
      ->assertSession()
      ->statusCodeEquals(403);

    // Log in again.
    $this
      ->drupalLogin($this->adminUser);
  }

  // Use the responsive image formatter with a responsive image style.
  $display_options['settings']['responsive_image_style'] = 'style_one';
  $display_options['settings']['image_link'] = '';
  $display
    ->setComponent($field_name, $display_options)
    ->save();

  // Create a derivative so at least one MIME type will be known.
  $large_style = ImageStyle::load('large');
  $large_style
    ->createDerivative($image_uri, $large_style
    ->buildUri($image_uri));

  // Output should contain all image styles and all breakpoints.
  $this
    ->drupalGet('node/' . $nid);
  if (!$empty_styles) {
    $this
      ->assertSession()
      ->responseContains('/styles/medium/');

    // Assert the empty image is present.
    $this
      ->assertSession()
      ->responseContains('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');
    $thumbnail_style = ImageStyle::load('thumbnail');

    // Assert the output of the 'srcset' attribute (small multipliers first).
    $this
      ->assertSession()
      ->responseContains('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x, ' . $this->fileUrlGenerator
      ->transformRelative($thumbnail_style
      ->buildUrl($image_uri)) . ' 1.5x');
    $this
      ->assertSession()
      ->responseContains('/styles/medium/');

    // Assert the output of the original image.
    $this
      ->assertSession()
      ->responseContains($this->fileUrlGenerator
      ->generateString($image_uri) . ' 3x');

    // Assert the output of the breakpoints.
    $this
      ->assertSession()
      ->responseContains('media="(min-width: 0px)"');
    $this
      ->assertSession()
      ->responseContains('media="(min-width: 560px)"');

    // Assert the output of the 'sizes' attribute.
    $this
      ->assertSession()
      ->responseContains('sizes="(min-width: 700px) 700px, 100vw"');
    $this
      ->assertSession()
      ->responseMatches('/media="\\(min-width: 560px\\)".+?sizes="\\(min-width: 700px\\) 700px, 100vw"/');

    // Assert the output of the 'srcset' attribute (small images first).
    $medium_style = ImageStyle::load('medium');
    $this
      ->assertSession()
      ->responseContains($this->fileUrlGenerator
      ->transformRelative($medium_style
      ->buildUrl($image_uri)) . ' 220w, ' . $this->fileUrlGenerator
      ->transformRelative($large_style
      ->buildUrl($image_uri)) . ' 360w');
    $this
      ->assertSession()
      ->responseContains('media="(min-width: 851px)"');
  }
  $this
    ->assertSession()
    ->responseContains('/styles/large/');
  $this
    ->assertSession()
    ->responseHeaderContains('X-Drupal-Cache-Tags', 'config:responsive_image.styles.style_one');
  if (!$empty_styles) {
    $this
      ->assertSession()
      ->responseHeaderContains('X-Drupal-Cache-Tags', 'config:image.style.medium');
    $this
      ->assertSession()
      ->responseHeaderContains('X-Drupal-Cache-Tags', 'config:image.style.thumbnail');
    $this
      ->assertSession()
      ->responseContains('type="image/png"');
  }
  $this
    ->assertSession()
    ->responseHeaderContains('X-Drupal-Cache-Tags', 'config:image.style.large');

  // Test the fallback image style.
  $image = \Drupal::service('image.factory')
    ->get($image_uri);
  $fallback_image = [
    '#theme' => 'image',
    '#alt' => $alt,
    '#uri' => $this->fileUrlGenerator
      ->transformRelative($large_style
      ->buildUrl($image
      ->getSource())),
  ];

  // The image.html.twig template has a newline after the <img> tag but
  // responsive-image.html.twig doesn't have one after the fallback image, so
  // we remove it here.
  $default_output = trim($renderer
    ->renderRoot($fallback_image));
  $this
    ->assertSession()
    ->responseContains($default_output);
  if ($scheme == 'private') {

    // Log out and ensure the file cannot be accessed.
    $this
      ->drupalLogout();
    $this
      ->drupalGet($large_style
      ->buildUrl($image_uri));
    $this
      ->assertSession()
      ->statusCodeEquals(403);
    $this
      ->assertSession()
      ->responseHeaderNotMatches('X-Drupal-Cache-Tags', '/ image_style\\:/');
  }
}