Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,18 @@
|
||||
# Schema for the configuration files of the Responsive image test theme module.
|
||||
field.formatter.settings.responsive_image_test:
|
||||
type: mapping
|
||||
label: 'Responsive image list format settings'
|
||||
mapping:
|
||||
responsive_image_style:
|
||||
type: string
|
||||
label: 'Responsive image style'
|
||||
image_link:
|
||||
type: string
|
||||
label: 'Link image to'
|
||||
image_loading:
|
||||
type: mapping
|
||||
label: 'Image loading settings'
|
||||
mapping:
|
||||
attribute:
|
||||
type: string
|
||||
label: 'Loading attribute'
|
||||
@ -0,0 +1,33 @@
|
||||
responsive_image_test_module.empty:
|
||||
label: empty
|
||||
mediaQuery: ''
|
||||
weight: 0
|
||||
multipliers:
|
||||
- 1x
|
||||
- 1.5x
|
||||
- 2x
|
||||
|
||||
responsive_image_test_module.mobile:
|
||||
label: mobile
|
||||
mediaQuery: '(min-width: 0px)'
|
||||
weight: 1
|
||||
multipliers:
|
||||
- 1x
|
||||
- 1.5x
|
||||
- 2x
|
||||
responsive_image_test_module.narrow:
|
||||
label: narrow
|
||||
mediaQuery: '(min-width: 560px)'
|
||||
weight: 2
|
||||
multipliers:
|
||||
- 1x
|
||||
- 1.5x
|
||||
- 2x
|
||||
responsive_image_test_module.wide:
|
||||
label: wide
|
||||
mediaQuery: '(min-width: 851px)'
|
||||
weight: 3
|
||||
multipliers:
|
||||
- 1x
|
||||
- 1.5x
|
||||
- 2x
|
||||
@ -0,0 +1,5 @@
|
||||
name: 'Responsive image test theme'
|
||||
type: module
|
||||
description: 'Test theme for responsive image.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\responsive_image_test_module\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Field\Attribute\FieldFormatter;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\responsive_image\Plugin\Field\FieldFormatter\ResponsiveImageFormatter;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
|
||||
/**
|
||||
* Plugin to test responsive image formatter.
|
||||
*/
|
||||
#[FieldFormatter(
|
||||
id: 'responsive_image_test',
|
||||
label: new TranslatableMarkup('Responsive image test'),
|
||||
field_types: [
|
||||
'image',
|
||||
],
|
||||
)]
|
||||
class ResponsiveImageTestFormatter extends ResponsiveImageFormatter {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$elements = parent::viewElements($items, $langcode);
|
||||
// Unset #item_attributes to test that the theme function can handle that.
|
||||
foreach ($elements as &$element) {
|
||||
if (isset($element['#item_attributes'])) {
|
||||
unset($element['#item_attributes']);
|
||||
}
|
||||
}
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional;
|
||||
|
||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
|
||||
|
||||
/**
|
||||
* Generic module test for responsive_image.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class GenericTest extends GenericModuleTestBase {}
|
||||
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional;
|
||||
|
||||
use Drupal\responsive_image\ResponsiveImageStyleInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
// cspell:ignore modulenarrow
|
||||
|
||||
/**
|
||||
* Thoroughly test the administrative interface of the Responsive Image module.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageAdminUITest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'responsive_image',
|
||||
'responsive_image_test_module',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer responsive images',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image administration functionality.
|
||||
*/
|
||||
public function testResponsiveImageAdmin(): void {
|
||||
// We start without any default styles.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertSession()->pageTextContains('There are no responsive image styles yet.');
|
||||
|
||||
// Add a responsive image style.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/add');
|
||||
// The 'Responsive Image' breakpoint group should be selected by default.
|
||||
$this->assertSession()->fieldValueEquals('breakpoint_group', 'responsive_image');
|
||||
|
||||
// Create a new group.
|
||||
$edit = [
|
||||
'label' => 'Style One',
|
||||
'id' => 'style_one',
|
||||
'breakpoint_group' => 'responsive_image',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
];
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check if the new group is created.
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertSession()->pageTextNotContains('There are no responsive image styles yet.');
|
||||
$this->assertSession()->pageTextContains('Style One');
|
||||
|
||||
// Edit the breakpoint_group.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
$this->assertSession()->fieldValueEquals('label', 'Style One');
|
||||
$this->assertSession()->fieldValueEquals('breakpoint_group', 'responsive_image');
|
||||
$edit = [
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Edit the group.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
$this->assertSession()->fieldValueEquals('label', 'Style One');
|
||||
$this->assertSession()->fieldValueEquals('breakpoint_group', 'responsive_image_test_module');
|
||||
$this->assertSession()->fieldValueEquals('fallback_image_style', 'thumbnail');
|
||||
|
||||
$cases = [
|
||||
['mobile', '1x'],
|
||||
['mobile', '2x'],
|
||||
['narrow', '1x'],
|
||||
['narrow', '2x'],
|
||||
['wide', '1x'],
|
||||
['wide', '2x'],
|
||||
];
|
||||
$image_styles = array_merge(
|
||||
[ResponsiveImageStyleInterface::EMPTY_IMAGE, ResponsiveImageStyleInterface::ORIGINAL_IMAGE],
|
||||
array_keys(image_style_options(FALSE))
|
||||
);
|
||||
foreach ($cases as $case) {
|
||||
// Check if the radio buttons are present.
|
||||
$this->assertSession()->fieldExists('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_mapping_type]');
|
||||
// Check if the image style dropdowns are present.
|
||||
$this->assertSession()->fieldExists('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_style]');
|
||||
// Check if the sizes textfields are present.
|
||||
$this->assertSession()->fieldExists('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][sizes]');
|
||||
|
||||
foreach ($image_styles as $image_style_name) {
|
||||
// Check if the image styles are available in the dropdowns.
|
||||
$this->assertSession()->optionExists('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_style]', $image_style_name);
|
||||
// Check if the image styles checkboxes are present.
|
||||
$this->assertSession()->fieldExists('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][sizes_image_styles][' . $image_style_name . ']');
|
||||
}
|
||||
}
|
||||
|
||||
// Save styles for 1x variant only.
|
||||
$edit = [
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
'keyed_styles[responsive_image_test_module.mobile][1x][image_mapping_type]' => 'image_style',
|
||||
'keyed_styles[responsive_image_test_module.mobile][1x][image_style]' => 'thumbnail',
|
||||
'keyed_styles[responsive_image_test_module.narrow][1x][image_mapping_type]' => 'sizes',
|
||||
// Ensure the Sizes field allows long values.
|
||||
'keyed_styles[responsive_image_test_module.narrow][1x][sizes]' => '(min-resolution: 192dpi) and (min-width: 170px) 386px, (min-width: 170px) 193px, (min-width: 768px) 18vw, (min-width: 480px) 30vw, 48vw',
|
||||
'keyed_styles[responsive_image_test_module.narrow][1x][sizes_image_styles][large]' => 'large',
|
||||
'keyed_styles[responsive_image_test_module.narrow][1x][sizes_image_styles][medium]' => 'medium',
|
||||
'keyed_styles[responsive_image_test_module.wide][1x][image_mapping_type]' => 'image_style',
|
||||
'keyed_styles[responsive_image_test_module.wide][1x][image_style]' => 'large',
|
||||
];
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
|
||||
// Check the mapping for multipliers 1x and 2x for the mobile breakpoint.
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.mobile][1x][image_style]', 'thumbnail');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.mobile][1x][image_mapping_type]', 'image_style');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.mobile][2x][image_mapping_type]', '_none');
|
||||
|
||||
// Check the mapping for multipliers 1x and 2x for the narrow breakpoint.
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.narrow][1x][image_mapping_type]', 'sizes');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.narrow][1x][sizes]', '(min-resolution: 192dpi) and (min-width: 170px) 386px, (min-width: 170px) 193px, (min-width: 768px) 18vw, (min-width: 480px) 30vw, 48vw');
|
||||
$this->assertSession()->checkboxChecked('edit-keyed-styles-responsive-image-test-modulenarrow-1x-sizes-image-styles-large');
|
||||
$this->assertSession()->checkboxChecked('edit-keyed-styles-responsive-image-test-modulenarrow-1x-sizes-image-styles-medium');
|
||||
$this->assertSession()->checkboxNotChecked('edit-keyed-styles-responsive-image-test-modulenarrow-1x-sizes-image-styles-thumbnail');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.narrow][2x][image_mapping_type]', '_none');
|
||||
|
||||
// Check the mapping for multipliers 1x and 2x for the wide breakpoint.
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.wide][1x][image_style]', 'large');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.wide][1x][image_mapping_type]', 'image_style');
|
||||
$this->assertSession()->fieldValueEquals('keyed_styles[responsive_image_test_module.wide][2x][image_mapping_type]', '_none');
|
||||
|
||||
// Delete the style.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one/delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertSession()->pageTextContains('There are no responsive image styles yet.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\image\ImageStyleInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\responsive_image\Plugin\Field\FieldFormatter\ResponsiveImageFormatter;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\responsive_image\ResponsiveImageStyleInterface;
|
||||
use Drupal\Tests\image\Functional\ImageFieldTestBase;
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests responsive image display formatter.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageFieldDisplayTest extends ImageFieldTestBase {
|
||||
|
||||
use TestFileCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Responsive image style entity instance we test with.
|
||||
*
|
||||
* @var \Drupal\responsive_image\Entity\ResponsiveImageStyle
|
||||
*/
|
||||
protected $responsiveImgStyle;
|
||||
|
||||
/**
|
||||
* The file URL generator.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileUrlGeneratorInterface
|
||||
*/
|
||||
protected $fileUrlGenerator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'field_ui',
|
||||
'responsive_image',
|
||||
'responsive_image_test_module',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->fileUrlGenerator = $this->container->get('file_url_generator');
|
||||
|
||||
// Create user.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer responsive images',
|
||||
'access content',
|
||||
'access administration pages',
|
||||
'administer site configuration',
|
||||
'administer content types',
|
||||
'administer node display',
|
||||
'administer nodes',
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'delete any article content',
|
||||
'administer image styles',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
// Add responsive image style.
|
||||
$this->responsiveImgStyle = ResponsiveImageStyle::create([
|
||||
'id' => 'style_one',
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'large',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display for public files.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersPublic(): void {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->doTestResponsiveImageFieldFormatters('public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display for private files.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersPrivate(): void {
|
||||
$this->addTestImageStyleMappings();
|
||||
// Remove access content permission from anonymous users.
|
||||
user_role_change_permissions(RoleInterface::ANONYMOUS_ID, ['access content' => FALSE]);
|
||||
$this->doTestResponsiveImageFieldFormatters('private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters when image style is empty.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersEmptyStyle(): void {
|
||||
$this->addTestImageStyleMappings(TRUE);
|
||||
$this->doTestResponsiveImageFieldFormatters('public', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add image style mappings to the responsive image style entity.
|
||||
*
|
||||
* @param bool $empty_styles
|
||||
* If true, the image style mappings will get empty image styles.
|
||||
*/
|
||||
protected function addTestImageStyleMappings($empty_styles = FALSE): void {
|
||||
if ($empty_styles) {
|
||||
$this->responsiveImgStyle
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '',
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width: 700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [],
|
||||
],
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
else {
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty image.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => ResponsiveImageStyleInterface::EMPTY_IMAGE,
|
||||
])
|
||||
// Test the output with a 1.5x multiplier.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1.5x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
])
|
||||
// Test the output of the 'sizes' attribute.
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width: 700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large',
|
||||
'medium',
|
||||
],
|
||||
],
|
||||
])
|
||||
// Test the normal output of mapping to an image style.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
])
|
||||
// Test the output of the original image.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '3x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => ResponsiveImageStyleInterface::ORIGINAL_IMAGE,
|
||||
])
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param string $scheme
|
||||
* File scheme to use.
|
||||
* @param bool $empty_styles
|
||||
* If true, use an empty string for image style names.
|
||||
* Defaults to false.
|
||||
*/
|
||||
protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles = FALSE): void {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$node_storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
$field_name = $this->randomMachineName();
|
||||
$this->createImageField($field_name, 'node', '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 = $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,
|
||||
'#attributes' => ['loading' => 'lazy'],
|
||||
];
|
||||
$default_output = str_replace("\n", '', (string) $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)"');
|
||||
// Assert the output of the 'width' attribute.
|
||||
$this->assertSession()->responseContains('width="360"');
|
||||
// Assert the output of the 'height' attribute.
|
||||
$this->assertSession()->responseContains('height="240"');
|
||||
$this->assertSession()->responseContains('loading="lazy"');
|
||||
}
|
||||
$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/avif"');
|
||||
}
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:image.style.large');
|
||||
|
||||
// Test the fallback image style. Copy the source image:
|
||||
$fallback_image = $image;
|
||||
// Set the fallback image style uri:
|
||||
$fallback_image['#uri'] = $this->fileUrlGenerator->transformRelative($large_style->buildUrl($image_uri));
|
||||
// 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((string) $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\:/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display linked to the file.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersLinkToFile(): void {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->assertResponsiveImageFieldFormattersLink('file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display linked to the node.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersLinkToNode(): void {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->assertResponsiveImageFieldFormattersLink('content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatter on node display with an empty media query.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersEmptyMediaQuery(): void {
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty media query.
|
||||
->addImageStyleMapping('responsive_image_test_module.empty', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => ResponsiveImageStyleInterface::EMPTY_IMAGE,
|
||||
])
|
||||
// Test the output with a 1.5x multiplier.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
])
|
||||
->save();
|
||||
$node_storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
$field_name = $this->randomMachineName();
|
||||
$this->createImageField($field_name, 'node', 'article', ['uri_scheme' => 'public']);
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->getTestFiles('image'));
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = [
|
||||
'type' => 'responsive_image',
|
||||
'settings' => [
|
||||
'image_link' => '',
|
||||
'responsive_image_style' => 'style_one',
|
||||
],
|
||||
];
|
||||
$display = \Drupal::service('entity_display.repository')
|
||||
->getViewDisplay('node', 'article');
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// View the node.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
|
||||
// Assert an empty media attribute is not output.
|
||||
$this->assertSession()->responseNotMatches('@srcset="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x".+?media=".+?/><source@');
|
||||
|
||||
// Assert the media attribute is present if it has a value.
|
||||
$thumbnail_style = ImageStyle::load('thumbnail');
|
||||
$node = $node_storage->load($nid);
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$this->assertSession()->responseMatches('/srcset="' . preg_quote($this->fileUrlGenerator->transformRelative($thumbnail_style->buildUrl($image_uri)), '/') . ' 1x".+?media="\(min-width: 0px\)"/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatter on node display with one and two sources.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersMultipleSources(): void {
|
||||
// Setup known image style sizes so the test can assert on known sizes.
|
||||
$large_style = ImageStyle::load('large');
|
||||
assert($large_style instanceof ImageStyleInterface);
|
||||
$large_style->addImageEffect([
|
||||
'id' => 'image_resize',
|
||||
'weight' => 0,
|
||||
'data' => [
|
||||
'width' => '480',
|
||||
'height' => '480',
|
||||
],
|
||||
]);
|
||||
$large_style->save();
|
||||
$medium_style = ImageStyle::load('medium');
|
||||
assert($medium_style instanceof ImageStyleInterface);
|
||||
$medium_style->addImageEffect([
|
||||
'id' => 'image_resize',
|
||||
'weight' => 0,
|
||||
'data' => [
|
||||
'width' => '220',
|
||||
'height' => '220',
|
||||
],
|
||||
]);
|
||||
$medium_style->save();
|
||||
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty media query.
|
||||
->addImageStyleMapping('responsive_image_test_module.empty', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => $medium_style->id(),
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.empty', '1.5x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => $large_style->id(),
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.empty', '2x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => $large_style->id(),
|
||||
])
|
||||
->save();
|
||||
$node_storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
$field_name = $this->randomMachineName();
|
||||
$this->createImageField($field_name, 'node', 'article', ['uri_scheme' => 'public']);
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->getTestFiles('image'));
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = [
|
||||
'type' => 'responsive_image',
|
||||
'settings' => [
|
||||
'image_link' => '',
|
||||
'responsive_image_style' => 'style_one',
|
||||
'image_loading' => [
|
||||
// Test the image loading default option can be overridden.
|
||||
'attribute' => 'eager',
|
||||
],
|
||||
],
|
||||
];
|
||||
$display = \Drupal::service('entity_display.repository')
|
||||
->getViewDisplay('node', 'article');
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// View the node.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
|
||||
// Assert the img tag has medium and large images and fallback dimensions
|
||||
// from the large image style are used.
|
||||
$node = $node_storage->load($nid);
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$medium_transform_url = $this->fileUrlGenerator->transformRelative($medium_style->buildUrl($image_uri));
|
||||
$large_transform_url = $this->fileUrlGenerator->transformRelative($large_style->buildUrl($image_uri));
|
||||
$this->assertSession()->responseMatches('/<img loading="eager" srcset="' . \preg_quote($medium_transform_url, '/') . ' 1x, ' . \preg_quote($large_transform_url, '/') . ' 1.5x, ' . \preg_quote($large_transform_url, '/') . ' 2x" width="480" height="480" src="' . \preg_quote($large_transform_url, '/') . '" alt="\w+" \/>/');
|
||||
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty media query.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => $large_style->id(),
|
||||
])
|
||||
->save();
|
||||
|
||||
// Assert the picture tag has source tags that include dimensions.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertSession()->responseMatches('/<picture>\s+<source srcset="' . \preg_quote($large_transform_url, '/') . ' 1x" media="\(min-width: 851px\)" type="image\/avif" width="480" height="480"\/>\s+<source srcset="' . \preg_quote($medium_transform_url, '/') . ' 1x, ' . \preg_quote($large_transform_url, '/') . ' 1.5x, ' . \preg_quote($large_transform_url, '/') . ' 2x" type="image\/avif" width="220" height="220"\/>\s+<img loading="eager" width="480" height="480" src="' . \preg_quote($large_transform_url, '/') . '" alt="\w+" \/>\s+<\/picture>/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters linked to the file or node.
|
||||
*
|
||||
* @param string $link_type
|
||||
* The link type to test. Either 'file' or 'content'.
|
||||
*/
|
||||
private function assertResponsiveImageFieldFormattersLink(string $link_type): void {
|
||||
$field_name = $this->randomMachineName();
|
||||
$field_settings = ['alt_field_required' => 0];
|
||||
$this->createImageField($field_name, 'node', 'article', ['uri_scheme' => 'public'], $field_settings);
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->getTestFiles('image'));
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
|
||||
// Test the image linked to file formatter.
|
||||
$display_options = [
|
||||
'type' => 'responsive_image',
|
||||
'settings' => [
|
||||
'image_link' => $link_type,
|
||||
'responsive_image_style' => 'style_one',
|
||||
],
|
||||
];
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
// Ensure that preview works.
|
||||
$this->previewNodeImage($test_image, $field_name, 'article');
|
||||
|
||||
// Look for a picture tag in the preview output
|
||||
$this->assertSession()->responseMatches('/picture/');
|
||||
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
|
||||
$this->container->get('entity_type.manager')->getStorage('node')->resetCache([$nid]);
|
||||
$node = Node::load($nid);
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = [
|
||||
'type' => 'responsive_image',
|
||||
'settings' => [
|
||||
'image_link' => $link_type,
|
||||
'responsive_image_style' => 'style_one',
|
||||
],
|
||||
];
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// Create a derivative so at least one MIME type will be known.
|
||||
$large_style = ImageStyle::load('large');
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$large_style->createDerivative($image_uri, $large_style->buildUri($image_uri));
|
||||
|
||||
// Output should contain all image styles and all breakpoints.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
switch ($link_type) {
|
||||
case 'file':
|
||||
// Make sure the link to the file is present.
|
||||
$this->assertSession()->responseMatches('/<a(.*?)href="' . preg_quote($this->fileUrlGenerator->generateString($image_uri), '/') . '"(.*?)>\s*<picture/');
|
||||
break;
|
||||
|
||||
case 'content':
|
||||
// Make sure the link to the node is present.
|
||||
$this->assertSession()->responseMatches('/<a(.*?)href="' . preg_quote($node->toUrl()->toString(), '/') . '"(.*?)>\s*<picture/');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleJsonAnonTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleJsonBasicAuthTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleJsonCookieTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* Resource test base for ResponsiveImageStyle entity.
|
||||
*/
|
||||
abstract class ResponsiveImageStyleResourceTestBase extends ConfigEntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['responsive_image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'responsive_image_style';
|
||||
|
||||
/**
|
||||
* The ResponsiveImageStyle entity.
|
||||
*
|
||||
* @var \Drupal\responsive_image\ResponsiveImageStyleInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The effect UUID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $effectUuid;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer responsive images']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" responsive image style.
|
||||
$camelids = ResponsiveImageStyle::create([
|
||||
'id' => 'camelids',
|
||||
'label' => 'Camelids',
|
||||
]);
|
||||
$camelids->setBreakpointGroup('test_group');
|
||||
$camelids->setFallbackImageStyle('fallback');
|
||||
$camelids->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'small',
|
||||
]);
|
||||
$camelids->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'medium' => 'medium',
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$camelids->save();
|
||||
|
||||
return $camelids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'breakpoint_group' => 'test_group',
|
||||
'dependencies' => [
|
||||
'config' => [
|
||||
'image.style.large',
|
||||
'image.style.medium',
|
||||
],
|
||||
],
|
||||
'fallback_image_style' => 'fallback',
|
||||
'id' => 'camelids',
|
||||
'image_style_mappings' => [
|
||||
0 => [
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'image_mapping' => 'small',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'multiplier' => '1x',
|
||||
],
|
||||
1 => [
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
'medium' => 'medium',
|
||||
],
|
||||
],
|
||||
'image_mapping_type' => 'sizes',
|
||||
'multiplier' => '2x',
|
||||
],
|
||||
],
|
||||
'label' => 'Camelids',
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
return "The 'administer responsive images' permission is required.";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleXmlAnonTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleXmlBasicAuthTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ResponsiveImageStyleXmlCookieTest extends ResponsiveImageStyleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Functional;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the integration of responsive image with Views.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ViewsIntegrationTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* The responsive image style ID to use.
|
||||
*/
|
||||
const RESPONSIVE_IMAGE_STYLE_ID = 'responsive_image_style_id';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'views',
|
||||
'views_ui',
|
||||
'responsive_image',
|
||||
'field',
|
||||
'image',
|
||||
'file',
|
||||
'entity_test',
|
||||
'breakpoint',
|
||||
'responsive_image_test_module',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The test views to enable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $testViews = ['entity_test_row'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = ['views_test_config']): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
// Create a responsive image style.
|
||||
$responsive_image_style = ResponsiveImageStyle::create([
|
||||
'id' => self::RESPONSIVE_IMAGE_STYLE_ID,
|
||||
'label' => 'Foo',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
]);
|
||||
// Create an image field to be used with a responsive image formatter.
|
||||
FieldStorageConfig::create([
|
||||
'type' => 'image',
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'bar',
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'field_name' => 'bar',
|
||||
])->save();
|
||||
|
||||
$responsive_image_style
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'medium',
|
||||
])
|
||||
// Test the normal output of mapping to an image style.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
])
|
||||
->save();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer views']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests integration with Views.
|
||||
*/
|
||||
public function testViewsAddResponsiveImageField(): void {
|
||||
// Add the image field to the View.
|
||||
$this->drupalGet('admin/structure/views/nojs/add-handler/entity_test_row/default/field');
|
||||
$this->drupalGet('admin/structure/views/nojs/add-handler/entity_test_row/default/field');
|
||||
$this->submitForm(['name[entity_test__bar.bar]' => TRUE], 'Add and configure field');
|
||||
// Set the formatter to 'Responsive image'.
|
||||
$this->submitForm(['options[type]' => 'responsive_image'], 'Apply');
|
||||
$this->assertSession()
|
||||
->responseContains('Responsive image style field is required.');
|
||||
$this->submitForm(['options[settings][responsive_image_style]' => self::RESPONSIVE_IMAGE_STYLE_ID], 'Apply');
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/entity_test_row/default/field/bar');
|
||||
// Make sure the selected value is set.
|
||||
$this->assertSession()
|
||||
->fieldValueEquals('options[settings][responsive_image_style]', self::RESPONSIVE_IMAGE_STYLE_ID);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\Tests\field_ui\Traits\FieldUiJSTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the responsive image field UI.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageFieldUiTest extends WebDriverTestBase {
|
||||
|
||||
use FieldUiJSTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'field_ui',
|
||||
'image',
|
||||
'responsive_image',
|
||||
'responsive_image_test_module',
|
||||
'block',
|
||||
];
|
||||
|
||||
/**
|
||||
* The content type id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $type;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_block');
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
// Create a test user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'access content',
|
||||
'administer content types',
|
||||
'administer node fields',
|
||||
'administer node form display',
|
||||
'administer node display',
|
||||
'bypass node access',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create content type, with underscores.
|
||||
$type_name = $this->randomMachineName(8) . '_test';
|
||||
$type = $this->drupalCreateContentType([
|
||||
'name' => $type_name,
|
||||
'type' => $type_name,
|
||||
]);
|
||||
$this->type = $type->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests formatter settings.
|
||||
*/
|
||||
public function testResponsiveImageFormatterUi(): void {
|
||||
$manage = 'admin/structure/types/manage/' . $this->type;
|
||||
$manage_display = $manage . '/display';
|
||||
/** @var \Drupal\FunctionalJavascriptTests\JSWebAssert $assert_session */
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$this->fieldUIAddNewFieldJS('admin/structure/types/manage/' . $this->type, 'image', 'Image', 'image');
|
||||
|
||||
// Display the "Manage display" page.
|
||||
$this->drupalGet($manage_display);
|
||||
|
||||
// Change the formatter and check that the summary is updated.
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$field_image_type = $page->findField('fields[field_image][type]');
|
||||
$field_image_type->setValue('responsive_image');
|
||||
|
||||
$summary_text = $assert_session->waitForElement('xpath', $this->cssSelectToXpath('#field-image .ajax-new-content .field-plugin-summary'));
|
||||
$this->assertEquals('Select a responsive image style. Loading attribute: lazy', $summary_text->getText());
|
||||
|
||||
$page->pressButton('Save');
|
||||
$assert_session->responseContains("Select a responsive image style.");
|
||||
|
||||
// Create responsive image styles.
|
||||
$responsive_image_style = ResponsiveImageStyle::create([
|
||||
'id' => 'style_one',
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
]);
|
||||
$responsive_image_style
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
])
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'medium',
|
||||
])
|
||||
// Test the normal output of mapping to an image style.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
])
|
||||
->save();
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
// Refresh the page.
|
||||
$this->drupalGet($manage_display);
|
||||
$assert_session->responseContains("Select a responsive image style.");
|
||||
|
||||
// Click on the formatter settings button to open the formatter settings
|
||||
// form.
|
||||
$field_image_type = $page->findField('fields[field_image][type]');
|
||||
$field_image_type->setValue('responsive_image');
|
||||
|
||||
$page->find('css', '#edit-fields-field-image-settings-edit')->click();
|
||||
$assert_session->waitForField('fields[field_image][settings_edit_form][settings][responsive_image_style]');
|
||||
|
||||
// Assert that the correct fields are present.
|
||||
$fieldnames = [
|
||||
'fields[field_image][settings_edit_form][settings][responsive_image_style]',
|
||||
'fields[field_image][settings_edit_form][settings][image_link]',
|
||||
];
|
||||
foreach ($fieldnames as $fieldname) {
|
||||
$assert_session->fieldExists($fieldname);
|
||||
}
|
||||
$page->findField('fields[field_image][settings_edit_form][settings][responsive_image_style]')->setValue('style_one');
|
||||
$page->findField('fields[field_image][settings_edit_form][settings][image_link]')->setValue('content');
|
||||
// Save the form to save the settings.
|
||||
$page->pressButton('Save');
|
||||
|
||||
$this->assertTrue($assert_session->waitForText('Responsive image style: Style One'));
|
||||
$this->assertTrue($assert_session->waitForText('Linked to content'));
|
||||
|
||||
$page->find('css', '#edit-fields-field-image-settings-edit')->click();
|
||||
$assert_session->waitForField('fields[field_image][settings_edit_form][settings][responsive_image_style]');
|
||||
$page->findField('fields[field_image][settings_edit_form][settings][image_link]')->setValue('file');
|
||||
|
||||
// Save the form to save the settings.
|
||||
$page->pressButton('Save');
|
||||
|
||||
$this->assertTrue($assert_session->waitForText('Responsive image style: Style One'));
|
||||
$this->assertTrue($assert_session->waitForText('Linked to file'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of responsive image styles.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class MigrateResponsiveImageStylesTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['responsive_image', 'breakpoint', 'image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Ensure the 'picture' module is enabled in the source.
|
||||
$this->sourceDatabase->update('system')
|
||||
->condition('name', 'picture')
|
||||
->fields(['status' => 1])
|
||||
->execute();
|
||||
$this->executeMigrations(['d7_image_styles', 'd7_responsive_image_styles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 to Drupal 8 responsive image styles migration.
|
||||
*/
|
||||
public function testResponsiveImageStyles(): void {
|
||||
$expected_image_style_mappings = [
|
||||
[
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'custom_image_style_1',
|
||||
'breakpoint_id' => 'responsive_image.computer',
|
||||
'multiplier' => 'multiplier_1',
|
||||
],
|
||||
[
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '2',
|
||||
'sizes_image_styles' => [
|
||||
'custom_image_style_1',
|
||||
'custom_image_style_2',
|
||||
],
|
||||
],
|
||||
'breakpoint_id' => 'responsive_image.computer',
|
||||
'multiplier' => 'multiplier_2',
|
||||
],
|
||||
[
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '2',
|
||||
'sizes_image_styles' => [
|
||||
'custom_image_style_1',
|
||||
'custom_image_style_2',
|
||||
],
|
||||
],
|
||||
'breakpoint_id' => 'responsive_image.computertwo',
|
||||
'multiplier' => 'multiplier_2',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected_image_style_mappings, ResponsiveImageStyle::load('narrow')
|
||||
->getImageStyleMappings());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D7 responsive image styles source plugin.
|
||||
*
|
||||
* @covers \Drupal\responsive_image\Plugin\migrate\source\d7\ResponsiveImageStyles
|
||||
* @group image
|
||||
*/
|
||||
class ResponsiveImageStylesTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'migrate_drupal',
|
||||
'responsive_image',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['picture_mapping'] = [
|
||||
[
|
||||
'label' => 'Narrow',
|
||||
'machine_name' => 'narrow',
|
||||
'breakpoint_group' => 'responsive_image',
|
||||
'mapping' => 'a:2:{s:38:"breakpoints.theme.my_theme_id.computer";a:3:{s:12:"multiplier_1";a:2:{s:12:"mapping_type";s:11:"image_style";s:11:"image_style";s:20:"custom_image_style_1";}s:12:"multiplier_2";a:3:{s:12:"mapping_type";s:5:"sizes";s:5:"sizes";i:2;s:18:"sizes_image_styles";a:2:{i:0;s:20:"custom_image_style_1";i:1;s:20:"custom_image_style_2";}}s:12:"multiplier_3";a:1:{s:12:"mapping_type";s:5:"_none";}}s:42:"breakpoints.theme.my_theme_id.computer_two";a:1:{s:12:"multiplier_2";a:3:{s:12:"mapping_type";s:5:"sizes";s:5:"sizes";i:2;s:18:"sizes_image_styles";a:2:{i:0;s:20:"custom_image_style_1";i:1;s:20:"custom_image_style_2";}}}}',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'label' => 'Narrow',
|
||||
'machine_name' => 'narrow',
|
||||
'breakpoint_group' => 'responsive_image',
|
||||
'mapping' => [
|
||||
'breakpoints.theme.my_theme_id.computer' =>
|
||||
[
|
||||
'multiplier_1' =>
|
||||
[
|
||||
'mapping_type' => 'image_style',
|
||||
'image_style' => 'custom_image_style_1',
|
||||
],
|
||||
'multiplier_2' =>
|
||||
[
|
||||
'mapping_type' => 'sizes',
|
||||
'sizes' => 2,
|
||||
'sizes_image_styles' =>
|
||||
[
|
||||
0 => 'custom_image_style_1',
|
||||
1 => 'custom_image_style_2',
|
||||
],
|
||||
],
|
||||
'multiplier_3' =>
|
||||
[
|
||||
'mapping_type' => '_none',
|
||||
],
|
||||
],
|
||||
'breakpoints.theme.my_theme_id.computer_two' =>
|
||||
[
|
||||
'multiplier_2' =>
|
||||
[
|
||||
'mapping_type' => 'sizes',
|
||||
'sizes' => 2,
|
||||
'sizes_image_styles' =>
|
||||
[
|
||||
0 => 'custom_image_style_1',
|
||||
1 => 'custom_image_style_2',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Kernel;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
|
||||
/**
|
||||
* Tests the integration of responsive image with other components.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageIntegrationTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'responsive_image',
|
||||
'field',
|
||||
'image',
|
||||
'file',
|
||||
'entity_test',
|
||||
'breakpoint',
|
||||
'responsive_image_test_module',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('entity_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests integration with entity view display.
|
||||
*/
|
||||
public function testEntityViewDisplayDependency(): void {
|
||||
// Create a responsive image style.
|
||||
ResponsiveImageStyle::create([
|
||||
'id' => 'foo',
|
||||
'label' => 'Foo',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
])->save();
|
||||
// Create an image field to be used with a responsive image formatter.
|
||||
FieldStorageConfig::create([
|
||||
'type' => 'image',
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'bar',
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'field_name' => 'bar',
|
||||
])->save();
|
||||
/** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
|
||||
$display = EntityViewDisplay::create([
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
]);
|
||||
$display->setComponent('bar', [
|
||||
'type' => 'responsive_image',
|
||||
'label' => 'hidden',
|
||||
'settings' => ['responsive_image_style' => 'foo', 'image_link' => ''],
|
||||
'third_party_settings' => [],
|
||||
])->save();
|
||||
|
||||
// Check that the 'foo' field is on the display.
|
||||
$this->assertNotNull($display = EntityViewDisplay::load('entity_test.entity_test.default'));
|
||||
$this->assertNotEmpty($display->getComponent('bar'));
|
||||
$this->assertArrayNotHasKey('bar', $display->get('hidden'));
|
||||
|
||||
// Delete the responsive image style.
|
||||
ResponsiveImageStyle::load('foo')->delete();
|
||||
|
||||
// Check that the view display was not deleted.
|
||||
$this->assertNotNull($display = EntityViewDisplay::load('entity_test.entity_test.default'));
|
||||
// Check that the 'foo' field was disabled.
|
||||
$this->assertNull($display->getComponent('bar'));
|
||||
$this->assertArrayHasKey('bar', $display->get('hidden'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Kernel;
|
||||
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
|
||||
/**
|
||||
* Tests validation of responsive_image_style entities.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageStyleValidationTest extends ConfigEntityValidationTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['breakpoint', 'image', 'responsive_image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entity = ResponsiveImageStyle::create([
|
||||
'id' => 'test',
|
||||
'label' => 'Test',
|
||||
]);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,407 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\responsive_image\Unit;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeRepositoryInterface;
|
||||
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\responsive_image\Entity\ResponsiveImageStyle
|
||||
* @group block
|
||||
*/
|
||||
class ResponsiveImageStyleConfigEntityUnitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The entity type used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entity type manager used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The breakpoint manager used for testing.
|
||||
*
|
||||
* @var \Drupal\breakpoint\BreakpointManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $breakpointManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface');
|
||||
$this->entityType->expects($this->any())
|
||||
->method('getProvider')
|
||||
->willReturn('responsive_image');
|
||||
|
||||
$this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
|
||||
$this->entityTypeManager->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('responsive_image_style')
|
||||
->willReturn($this->entityType);
|
||||
|
||||
$this->breakpointManager = $this->createMock('\Drupal\breakpoint\BreakpointManagerInterface');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('entity_type.manager', $this->entityTypeManager);
|
||||
$container->set('breakpoint.manager', $this->breakpointManager);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::calculateDependencies
|
||||
*/
|
||||
public function testCalculateDependencies(): void {
|
||||
// Set up image style loading mock.
|
||||
$styles = [];
|
||||
foreach (['fallback', 'small', 'medium', 'large'] as $style) {
|
||||
$mock = $this->createMock('Drupal\Core\Config\Entity\ConfigEntityInterface');
|
||||
$mock->expects($this->any())
|
||||
->method('getConfigDependencyName')
|
||||
->willReturn('image.style.' . $style);
|
||||
$styles[$style] = $mock;
|
||||
}
|
||||
$storage = $this->createMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
|
||||
$storage->expects($this->any())
|
||||
->method('loadMultiple')
|
||||
->with(array_keys($styles))
|
||||
->willReturn($styles);
|
||||
|
||||
$this->entityTypeManager->expects($this->any())
|
||||
->method('getStorage')
|
||||
->with('image_style')
|
||||
->willReturn($storage);
|
||||
|
||||
$entity_type_repository = $this->createMock(EntityTypeRepositoryInterface::class);
|
||||
$entity_type_repository->expects($this->any())
|
||||
->method('getEntityTypeFromClass')
|
||||
->with('Drupal\image\Entity\ImageStyle')
|
||||
->willReturn('image_style');
|
||||
|
||||
$entity = new ResponsiveImageStyle(['breakpoint_group' => 'test_group']);
|
||||
$entity->setBreakpointGroup('test_group');
|
||||
$entity->setFallbackImageStyle('fallback');
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'small',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'medium' => 'medium',
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->breakpointManager->expects($this->any())
|
||||
->method('getGroupProviders')
|
||||
->with('test_group')
|
||||
->willReturn(['olivero' => 'theme', 'toolbar' => 'module']);
|
||||
|
||||
\Drupal::getContainer()->set('entity_type.repository', $entity_type_repository);
|
||||
|
||||
$dependencies = $entity->calculateDependencies()->getDependencies();
|
||||
$this->assertEquals(['toolbar'], $dependencies['module']);
|
||||
$this->assertEquals(['olivero'], $dependencies['theme']);
|
||||
$this->assertEquals(['image.style.fallback', 'image.style.large', 'image.style.medium', 'image.style.small'], $dependencies['config']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addImageStyleMapping
|
||||
* @covers ::hasImageStyleMappings
|
||||
*/
|
||||
public function testHasImageStyleMappings(): void {
|
||||
$entity = new ResponsiveImageStyle([]);
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '',
|
||||
]);
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
$entity->removeImageStyleMappings();
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [],
|
||||
],
|
||||
]);
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
$entity->removeImageStyleMappings();
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
$entity->removeImageStyleMappings();
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$this->assertTrue($entity->hasImageStyleMappings());
|
||||
$entity->removeImageStyleMappings();
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->assertTrue($entity->hasImageStyleMappings());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addImageStyleMapping
|
||||
* @covers ::getImageStyleMapping
|
||||
*/
|
||||
public function testGetImageStyleMapping(): void {
|
||||
$entity = new ResponsiveImageStyle(['']);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$expected = [
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'multiplier' => '1x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
];
|
||||
$this->assertEquals($expected, $entity->getImageStyleMapping('test_breakpoint', '1x'));
|
||||
$this->assertNull($entity->getImageStyleMapping('test_unknown_breakpoint', '1x'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addImageStyleMapping
|
||||
* @covers ::getKeyedImageStyleMappings
|
||||
*/
|
||||
public function testGetKeyedImageStyleMappings(): void {
|
||||
$entity = new ResponsiveImageStyle(['']);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '2x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '_original image_',
|
||||
]);
|
||||
|
||||
$expected = [
|
||||
'test_breakpoint' => [
|
||||
'1x' => [
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'multiplier' => '1x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
],
|
||||
'2x' => [
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'multiplier' => '2x',
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'test_breakpoint2' => [
|
||||
'1x' => [
|
||||
'breakpoint_id' => 'test_breakpoint2',
|
||||
'multiplier' => '1x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
],
|
||||
'2x' => [
|
||||
'breakpoint_id' => 'test_breakpoint2',
|
||||
'multiplier' => '2x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '_original image_',
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected, $entity->getKeyedImageStyleMappings());
|
||||
|
||||
// Add another mapping to ensure keyed mapping static cache is rebuilt.
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '2x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'medium',
|
||||
]);
|
||||
$expected['test_breakpoint2']['2x'] = [
|
||||
'breakpoint_id' => 'test_breakpoint2',
|
||||
'multiplier' => '2x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'medium',
|
||||
];
|
||||
$this->assertEquals($expected, $entity->getKeyedImageStyleMappings());
|
||||
|
||||
// Overwrite a mapping to ensure keyed mapping static cache is rebuilt.
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '2x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$expected['test_breakpoint2']['2x'] = [
|
||||
'breakpoint_id' => 'test_breakpoint2',
|
||||
'multiplier' => '2x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
];
|
||||
$this->assertEquals($expected, $entity->getKeyedImageStyleMappings());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addImageStyleMapping
|
||||
* @covers ::getImageStyleMappings
|
||||
*/
|
||||
public function testGetImageStyleMappings(): void {
|
||||
$entity = new ResponsiveImageStyle(['']);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
]);
|
||||
|
||||
$expected = [
|
||||
[
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'multiplier' => '1x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
],
|
||||
[
|
||||
'breakpoint_id' => 'test_breakpoint',
|
||||
'multiplier' => '2x',
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'breakpoint_id' => 'test_breakpoint2',
|
||||
'multiplier' => '1x',
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected, $entity->getImageStyleMappings());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addImageStyleMapping
|
||||
* @covers ::removeImageStyleMappings
|
||||
*/
|
||||
public function testRemoveImageStyleMappings(): void {
|
||||
$entity = new ResponsiveImageStyle(['']);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
]);
|
||||
|
||||
$this->assertTrue($entity->hasImageStyleMappings());
|
||||
$entity->removeImageStyleMappings();
|
||||
$this->assertEmpty($entity->getImageStyleMappings());
|
||||
$this->assertEmpty($entity->getKeyedImageStyleMappings());
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setBreakpointGroup
|
||||
* @covers ::getBreakpointGroup
|
||||
*/
|
||||
public function testSetBreakpointGroup(): void {
|
||||
$entity = new ResponsiveImageStyle(['breakpoint_group' => 'test_group']);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint', '2x', [
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => [
|
||||
'sizes' => '(min-width:700px) 700px, 100vw',
|
||||
'sizes_image_styles' => [
|
||||
'large' => 'large',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->addImageStyleMapping('test_breakpoint2', '1x', [
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
]);
|
||||
|
||||
// Ensure that setting to same group does not remove mappings.
|
||||
$entity->setBreakpointGroup('test_group');
|
||||
$this->assertTrue($entity->hasImageStyleMappings());
|
||||
$this->assertEquals('test_group', $entity->getBreakpointGroup());
|
||||
|
||||
// Ensure that changing the group removes mappings.
|
||||
$entity->setBreakpointGroup('test_group2');
|
||||
$this->assertEquals('test_group2', $entity->getBreakpointGroup());
|
||||
$this->assertFalse($entity->hasImageStyleMappings());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user