file_browser-8.x-1.3/tests/src/Kernel/ImageEmbedBlockTest.php
tests/src/Kernel/ImageEmbedBlockTest.php
<?php
namespace Drupal\Tests\file_browser\Kernel;
use Drupal\block\Entity\Block;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Session\UserSession;
use Drupal\file\FileInterface;
use Drupal\KernelTests\KernelTestBase;
use PHPUnit\Framework\Attributes\Group;
/**
* Tests the Image Embed Block functionality.
*/
#[Group("file_browser")]
class ImageEmbedBlockTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
parent::register($container);
// Ensure the private stream wrapper is available in kernel tests.
$container->register('stream_wrapper.private', 'Drupal\Core\StreamWrapper\PrivateStream')
->addTag('stream_wrapper', ['scheme' => 'private']);
}
/**
* {@inheritdoc}
*
* We set this to FALSE here as DropzoneJS and Entity Browser use dynamic
* config settings which fail strict checks during installation.
*/
protected $strictConfigSchema = FALSE;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'claro';
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'user',
'field',
'file',
'image',
'block',
'block_content',
'entity_embed',
'entity_browser',
'dropzonejs',
'file_browser',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Install required entity schemas and configuration used by the tests.
$this->installEntitySchema('user');
$this->installEntitySchema('file');
$this->installEntitySchema('block');
$this->installEntitySchema('block_content');
$this->installSchema('file', ['file_usage']);
$this->installConfig(['system', 'image']);
// Ensure we run as user 1 (bypass all access checks for entity view).
$this->container->get('current_user')->setAccount(new UserSession(['uid' => 1]));
// Configure a private file path so the private stream wrapper works.
$fs = \Drupal::service('file_system');
$private_path = $fs->realpath('public://') . '/private-files';
$fs->prepareDirectory($private_path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$this->setSetting('file_private_path', $private_path);
// Create test image files.
$this->testImage = $this->createTestImageFile('test-image1.png');
$this->testImage2 = $this->createTestImageFile('test-image2.png');
// Install default image styles.
$this->container->get('module_installer')->install(['image']);
}
/**
* A test image file entity.
*
* @var \Drupal\file\FileInterface
*/
protected FileInterface $testImage;
/**
* A second test image file entity.
*
* @var \Drupal\file\FileInterface
*/
protected FileInterface $testImage2;
/**
* A test block instance.
*
* @var \Drupal\block\Entity\Block
*/
protected Block $testBlock;
/**
* Creates a test image file entity.
*
* @param string $filename
* The filename for the test image.
*
* @return \Drupal\file\FileInterface
* The created image file entity.
*/
protected function createTestImageFile(string $filename) {
// Create a minimal 1x1 pixel PNG image.
$image_data = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAHF/mWAAAAASUVORK5CYII=');
/** @var \Drupal\file\FileRepositoryInterface $file_repository */
$file_repository = \Drupal::service('file.repository');
$file = $file_repository->writeData($image_data, 'public://' . $filename);
// Ensure a proper MIME type is set.
$file->setMimeType('image/png');
$file->setPermanent();
$file->save();
return $file;
}
/**
* Tests the block configuration form the structure.
*/
public function testBlockConfigurationForm() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Test blockForm method directly to avoid web interface issues.
$form = [];
$form_state = new FormState();
$block_form = $block_plugin->blockForm($form, $form_state);
// Verify the block form contains expected elements.
$this->assertIsArray($block_form, 'Block form should return an array');
$this->assertArrayHasKey('selection', $block_form, 'Block form should have selection element');
$this->assertArrayHasKey('image_style', $block_form, 'Block form should have image_style element');
// Verify image style selector configuration.
$image_style_field = $block_form['image_style'];
$this->assertEquals('select', $image_style_field['#type']);
$this->assertArrayHasKey('#options', $image_style_field);
$this->assertArrayHasKey('', $image_style_field['#options'], 'Should have empty option for no style');
// Verify entity browser container configuration.
$selection_field = $block_form['selection'];
$this->assertEquals('container', $selection_field['#type']);
$this->assertEquals('image-embed-block-browser', $selection_field['#attributes']['id']);
}
/**
* Tests block configuration saving and retrieval.
*/
public function testBlockConfigurationSaving() {
// Test block configuration persistence programmatically.
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed', [
'image_style' => 'thumbnail',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Test alt text'],
],
],
]);
// Verify the configuration is set correctly.
$config = $block_plugin->getConfiguration();
$this->assertEquals('thumbnail', $config['image_style']);
$this->assertIsArray($config['files']);
$this->assertCount(1, $config['files']);
$this->assertEquals($this->testImage->id(), $config['files'][0]['fid']);
$this->assertEquals('Test alt text', $config['files'][0]['settings']['alt']);
// Test creating a block entity programmatically.
$block = Block::create([
'id' => 'test_image_block_config',
'theme' => $this->defaultTheme,
'region' => 'content',
'plugin' => 'image_embed',
'settings' => [
'label' => 'Test Image Block',
'image_style' => 'medium',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Saved alt text'],
],
],
],
]);
$block->save();
// Verify the block was saved and can be loaded.
$loaded_block = Block::load('test_image_block_config');
$this->assertNotNull($loaded_block, 'Block should be created successfully');
$this->assertEquals('Test Image Block', $loaded_block->label());
$settings = $loaded_block->get('settings');
$this->assertEquals('medium', $settings['image_style']);
$this->assertIsArray($settings['files']);
$this->assertCount(1, $settings['files']);
}
/**
* Tests block rendering with no files configured.
*/
public function testBlockRenderingEmpty() {
// Create a block with no files.
$this->testBlock = Block::create([
'id' => 'test_empty_image_block',
'theme' => $this->defaultTheme,
'region' => 'content',
'weight' => 0,
'plugin' => 'image_embed',
'settings' => [
'label' => 'Test Empty Image Block',
'label_display' => 'visible',
'image_style' => '',
'files' => [],
],
]);
$this->testBlock->save();
// The block should render but be empty since no files are configured.
// We can't easily test the block content without placing it, but we can
// verify it doesn't cause errors when built.
$plugin = $this->testBlock->getPlugin();
$build = $plugin->build();
$this->assertIsArray($build, 'Block should return a build array');
$this->assertEmpty($build, 'Empty block should return empty build array');
}
/**
* Tests block rendering with configured files.
*/
public function testBlockRenderingWithFiles() {
// Create a block with file configuration.
$this->testBlock = Block::create([
'id' => 'test_image_block_with_files',
'theme' => $this->defaultTheme,
'region' => 'content',
'weight' => 0,
'plugin' => 'image_embed',
'settings' => [
'label' => 'Test Image Block',
'label_display' => 'visible',
'image_style' => 'thumbnail',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => [
'alt' => 'Test image alt text',
],
],
[
'fid' => $this->testImage2->id(),
'settings' => [
'alt' => 'Second test image',
],
],
],
],
]);
$this->testBlock->save();
// Test the block build method directly.
$plugin = $this->testBlock->getPlugin();
$build = $plugin->build();
$this->assertIsArray($build, 'Block should return a build array');
$this->assertCount(2, $build, 'Block should render 2 images');
// Verify the first image.
$this->assertEquals('image_style', $build[0]['#theme']);
$this->assertEquals('thumbnail', $build[0]['#style_name']);
$this->assertEquals('Test image alt text', $build[0]['#alt']);
// Verify the second image.
$this->assertEquals('image_style', $build[1]['#theme']);
$this->assertEquals('thumbnail', $build[1]['#style_name']);
$this->assertEquals('Second test image', $build[1]['#alt']);
}
/**
* Tests block rendering with no image style.
*/
public function testBlockRenderingNoImageStyle() {
// Create a block without image style.
$this->testBlock = Block::create([
'id' => 'test_image_block_no_style',
'theme' => $this->defaultTheme,
'region' => 'content',
'weight' => 0,
'plugin' => 'image_embed',
'settings' => [
'label' => 'Test Image Block No Style',
'label_display' => 'visible',
'image_style' => '',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => [
'alt' => 'Test image without style',
],
],
],
],
]);
$this->testBlock->save();
// Test the block build method.
$plugin = $this->testBlock->getPlugin();
$build = $plugin->build();
$this->assertIsArray($build, 'Block should return a build array');
$this->assertCount(1, $build, 'Block should render 1 image');
// When no image style is used, should use 'image' theme.
$this->assertEquals('image', $build[0]['#theme']);
$this->assertArrayNotHasKey('#style_name', $build[0]);
$this->assertEquals('Test image without style', $build[0]['#alt']);
}
/**
* Tests entity browser integration in block form.
*/
public function testEntityBrowserIntegration() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Test browserForm method to verify entity browser integration.
$browser_form = $block_plugin->browserForm([]);
// Verify entity browser components are configured correctly.
$this->assertArrayHasKey('fids', $browser_form);
$this->assertEquals('entity_browser', $browser_form['fids']['#type']);
$this->assertEquals('browse_files_modal', $browser_form['fids']['#entity_browser']);
// Verify entity browser validators.
$this->assertArrayHasKey('#entity_browser_validators', $browser_form['fids']);
$this->assertEquals('file', $browser_form['fids']['#entity_browser_validators']['entity_type']['type']);
// Verify processing callbacks are configured.
$this->assertArrayHasKey('#process', $browser_form['fids']);
$this->assertCount(2, $browser_form['fids']['#process']);
}
/**
* Tests block default configuration.
*/
public function testDefaultConfiguration() {
// Create an Image Embed block plugin instance.
$block_manager = \Drupal::service('plugin.manager.block');
$plugin_definition = $block_manager->getDefinition('image_embed');
$this->assertEquals('image_embed', $plugin_definition['id']);
$this->assertEquals('Image Embed', (string) $plugin_definition['admin_label']);
$this->assertEquals('Embed', (string) $plugin_definition['category']);
// Test default configuration.
$block = $block_manager->createInstance('image_embed');
$default_config = $block->defaultConfiguration();
$this->assertArrayHasKey('image_style', $default_config);
$this->assertArrayHasKey('files', $default_config);
$this->assertEquals('', $default_config['image_style']);
$this->assertEquals([], $default_config['files']);
}
/**
* Tests block form processing and submission.
*/
public function testBlockFormProcessing() {
// Create a block programmatically and test its form.
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed', [
'image_style' => 'medium',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Configured alt text'],
],
],
]);
// Test blockForm method.
$form = [];
$form_state = new FormState();
$block_form = $block_plugin->blockForm($form, $form_state);
$this->assertIsArray($block_form, 'blockForm should return an array');
$this->assertArrayHasKey('selection', $block_form);
$this->assertArrayHasKey('image_style', $block_form);
// Verify image style field configuration.
$this->assertEquals('select', $block_form['image_style']['#type']);
$this->assertEquals('medium', $block_form['image_style']['#default_value']);
// Verify selection container.
$this->assertEquals('container', $block_form['selection']['#type']);
$this->assertEquals('image-embed-block-browser', $block_form['selection']['#attributes']['id']);
}
/**
* Tests file access control in block rendering.
*/
public function testFileAccessControl() {
// Create a private file for access testing.
$private_image_data = base64_decode(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAHF/mWAAAAASUVORK5CYII='
);
/** @var \Drupal\file\FileRepositoryInterface $file_repository */
$file_repository = \Drupal::service('file.repository');
$private_file = $file_repository->writeData($private_image_data, 'private://private-test-image.png');
$private_file->setMimeType('image/png');
$private_file->setPermanent();
$private_file->save();
// Create a block with the private file.
$this->testBlock = Block::create([
'id' => 'test_private_image_block',
'theme' => $this->defaultTheme,
'region' => 'content',
'weight' => 0,
'plugin' => 'image_embed',
'settings' => [
'label' => 'Test Private Image Block',
'label_display' => 'visible',
'image_style' => '',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Public image'],
],
[
'fid' => $private_file->id(),
'settings' => ['alt' => 'Private image'],
],
],
],
]);
$this->testBlock->save();
// Test block rendering respects file access.
$plugin = $this->testBlock->getPlugin();
$build = $plugin->build();
// The build should only include files that are accessible.
// Public files should be included, private file access depends on
// permissions.
$this->assertIsArray($build, 'Block should return a build array');
// Clean up.
$private_file->delete();
}
/**
* Tests browserForm method functionality.
*/
public function testBrowserFormGeneration() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Test browserForm with files.
$files = [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Test alt text'],
],
];
$browser_form = $block_plugin->browserForm($files);
$this->assertIsArray($browser_form, 'browserForm should return an array');
$this->assertEquals('container', $browser_form['#type']);
$this->assertEquals('image-embed-block-browser', $browser_form['#attributes']['id']);
// Verify entity browser element.
$this->assertArrayHasKey('fids', $browser_form);
$this->assertEquals('entity_browser', $browser_form['fids']['#type']);
$this->assertEquals('browse_files_modal', $browser_form['fids']['#entity_browser']);
// Verify table structure.
$this->assertArrayHasKey('table', $browser_form);
$this->assertEquals('table', $browser_form['table']['#type']);
$this->assertArrayHasKey('#header', $browser_form['table']);
$this->assertArrayHasKey('#tabledrag', $browser_form['table']);
// Verify the file row is created.
$file_id = $this->testImage->id();
$this->assertArrayHasKey($file_id, $browser_form['table']);
$this->assertArrayHasKey('display', $browser_form['table'][$file_id]);
$this->assertArrayHasKey('filename', $browser_form['table'][$file_id]);
$this->assertArrayHasKey('alt', $browser_form['table'][$file_id]);
$this->assertArrayHasKey('_weight', $browser_form['table'][$file_id]);
// Verify alt field configuration.
$alt_field = $browser_form['table'][$file_id]['alt'];
$this->assertEquals('textfield', $alt_field['#type']);
$this->assertEquals('Test alt text', $alt_field['#default_value']);
$this->assertEquals(512, $alt_field['#maxlength']);
}
/**
* Tests empty browserForm generation.
*/
public function testEmptyBrowserForm() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Test browserForm with no files.
$browser_form = $block_plugin->browserForm([]);
$this->assertIsArray($browser_form, 'browserForm should return an array');
$this->assertArrayHasKey('fids', $browser_form);
$this->assertArrayHasKey('table', $browser_form);
// Table should be empty.
$table_keys = array_filter(array_keys($browser_form['table']), function ($key) {
return !str_starts_with($key, '#');
});
$this->assertEmpty($table_keys, 'Empty browserForm should have no file rows');
}
/**
* Tests block submission and configuration persistence.
*/
public function testBlockSubmitConfiguration() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Simulate form state with file selections.
$form_state = new FormState();
$form_state->setValue(['selection', 'table'], [
$this->testImage->id() => [
'alt' => 'Submitted alt text',
'_weight' => 0,
],
$this->testImage2->id() => [
'alt' => 'Second submitted alt text',
'_weight' => 1,
],
]);
$form_state->setValue('image_style', 'large');
// Call blockSubmit.
$block_plugin->blockSubmit([], $form_state);
// Verify the configuration was updated.
$config = $block_plugin->getConfiguration();
$this->assertEquals('large', $config['image_style']);
$this->assertCount(2, $config['files']);
// Verify file configurations.
$this->assertEquals($this->testImage->id(), $config['files'][0]['fid']);
$this->assertEquals('Submitted alt text', $config['files'][0]['settings']['alt']);
$this->assertEquals($this->testImage2->id(), $config['files'][1]['fid']);
$this->assertEquals('Second submitted alt text', $config['files'][1]['settings']['alt']);
}
/**
* Tests block build method with various configurations.
*/
public function testBlockBuildMethod() {
$block_manager = \Drupal::service('plugin.manager.block');
// Test with image style.
$block_plugin = $block_manager->createInstance('image_embed', [
'image_style' => 'medium',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Styled image'],
],
],
]);
$build = $block_plugin->build();
$this->assertCount(1, $build);
$this->assertEquals('image_style', $build[0]['#theme']);
$this->assertEquals('medium', $build[0]['#style_name']);
$this->assertEquals('Styled image', $build[0]['#alt']);
// Test without image style.
$block_plugin_no_style = $block_manager->createInstance('image_embed', [
'image_style' => '',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Unstyled image'],
],
],
]);
$build_no_style = $block_plugin_no_style->build();
$this->assertCount(1, $build_no_style);
$this->assertEquals('image', $build_no_style[0]['#theme']);
$this->assertArrayNotHasKey('#style_name', $build_no_style[0]);
$this->assertEquals('Unstyled image', $build_no_style[0]['#alt']);
}
/**
* Tests block behavior with invalid file references.
*/
public function testInvalidFileReferences() {
$block_manager = \Drupal::service('plugin.manager.block');
// Create a block with invalid file ID.
$invalid_fid = $this->testImage->id() + 999;
$block_plugin = $block_manager->createInstance('image_embed', [
'image_style' => '',
'files' => [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Valid image'],
],
[
'fid' => $invalid_fid,
'settings' => ['alt' => 'Invalid image'],
],
],
]);
$build = $block_plugin->build();
// Should only render the valid file.
$this->assertCount(1, $build, 'Block should only render valid files');
$this->assertEquals('Valid image', $build[0]['#alt']);
}
/**
* Tests block form structure with files.
*/
public function testBlockFormStructure() {
$block_manager = \Drupal::service('plugin.manager.block');
$block_plugin = $block_manager->createInstance('image_embed');
// Test browserForm structure with files.
$files = [
[
'fid' => $this->testImage->id(),
'settings' => ['alt' => 'Test alt text'],
],
];
$browser_form = $block_plugin->browserForm($files);
// Verify table structure and headers.
$this->assertArrayHasKey('table', $browser_form);
$table = $browser_form['table'];
$this->assertEquals('table', $table['#type']);
$this->assertArrayHasKey('#header', $table);
// Verify table headers.
$headers = $table['#header'];
// Headers contain TranslatableMarkup objects, so convert to strings for
// comparison.
$header_strings = array_map('strval', $headers);
$this->assertContains('Preview', $header_strings);
$this->assertContains('Filename', $header_strings);
$this->assertContains('Metadata', $header_strings);
$this->assertContains('Order', $header_strings);
// Verify tabledrag configuration.
$this->assertArrayHasKey('#tabledrag', $table);
$this->assertNotEmpty($table['#tabledrag']);
// Verify empty state message is configured.
$this->assertEquals('No files yet', (string) $table['#empty']);
// Verify file row structure.
$file_id = $this->testImage->id();
$this->assertArrayHasKey($file_id, $table);
$file_row = $table[$file_id];
$this->assertArrayHasKey('display', $file_row);
$this->assertArrayHasKey('filename', $file_row);
$this->assertArrayHasKey('alt', $file_row);
$this->assertArrayHasKey('_weight', $file_row);
}
}
