image_to_media_swapper-2.x-dev/tests/src/Kernel/BatchProcessorServiceKernelTest.php
tests/src/Kernel/BatchProcessorServiceKernelTest.php
<?php
declare(strict_types=1);
namespace Drupal\Tests\image_to_media_swapper\Kernel;
use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\file\FileInterface;
use Drupal\image_to_media_swapper\BatchProcessorService;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\NodeInterface;
use Drupal\user\UserInterface;
/**
* Tests access to BatchProcessorService.
*
* @group image_to_media_swapper
*/
class BatchProcessorServiceKernelTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'user',
'field',
'file',
'media',
'filter',
'editor',
'text',
'image',
'node',
'options',
'ckeditor5',
'image_to_media_swapper',
];
/**
* The BatchProcessor service under test.
*
* @var \Drupal\image_to_media_swapper\BatchProcessorService
*/
protected BatchProcessorService $service;
/**
* The entity definition update manager.
*
* @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
*/
protected EntityDefinitionUpdateManagerInterface $entityDefinitionUpdateManager;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* The file URL generator service.
*
* @var \Drupal\Core\File\FileUrlGeneratorInterface
*/
protected FileUrlGeneratorInterface $fileUrlGenerator;
/**
* The file entity used in tests.
*
* @var \Drupal\file\FileInterface
*/
protected FileInterface $file;
/**
* The node entity used in tests.
*
* @var \Drupal\node\NodeInterface
*/
protected NodeInterface $node;
/**
* The user entity used in tests.
*
* @var \Drupal\user\UserInterface
*/
protected UserInterface $user;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Install required schemas.
$this->installEntitySchema('node');
$this->installSchema('node', ['node_access']);
$this->installEntitySchema('user');
$this->installEntitySchema('file');
$this->installSchema('file', ['file_usage']);
$this->installEntitySchema('media');
// Install configuration for needed modules.
$this->installConfig(['filter', 'editor', 'media']);
// Retrieve services.
// Create the test-specific SwapperService first.
$testSwapperService = new TestSwapperService(
$this->container->get('entity_type.manager'),
$this->container->get('http_client'),
$this->container->get('file_system'),
$this->container->get('logger.factory'),
$this->container->get('image_to_media_swapper.security_validation'),
$this->container->get('config.factory'),
$this->container->get('entity_type.bundle.info'),
$this->container->get('entity_field.manager'),
$this->container->get('module_handler'),
$this->container->get('file.mime_type.guesser'),
$this->container->get('image_to_media_swapper.content_verification')
);
// Create and use the test-specific batch processor service.
$this->service = new TestBatchProcessorService(
$this->container->get('entity_type.manager'),
$this->container->get('entity_field.manager'),
$this->container->get('logger.factory'),
$testSwapperService,
$this->container->get('entity_display.repository'),
$this->container->get('current_user'),
$this->container->get('datetime.time'),
$this->container->get('module_handler')
);
$this->entityDefinitionUpdateManager = $this->container->get('entity.definition_update_manager');
$this->entityTypeManager = $this->container->get('entity_type.manager');
$fileSystem = $this->container->get('file_system');
$this->fileUrlGenerator = $this->container->get('file_url_generator');
// Create the 'image' media type bundle if it doesn't exist.
if (!$this->entityTypeManager->getStorage('media_type')->load('image')) {
$this->entityTypeManager->getStorage('media_type')->create([
'id' => 'image',
'label' => 'Image',
'source' => 'image',
'status' => TRUE,
'description' => 'Image media type',
'source_configuration' => [
'source_field' => 'field_media_image',
],
'field_map' => [
'image' => 'field_media_image',
],
])->save();
}
// Create field storage and field config for field_media_image.
if (!$this->entityTypeManager->getStorage('field_storage_config')
->load('media.field_media_image')) {
$this->entityTypeManager->getStorage('field_storage_config')->create([
'field_name' => 'field_media_image',
'entity_type' => 'media',
'type' => 'image',
'cardinality' => 1,
'settings' => [
'file_directory' => 'media/image',
'file_extensions' => 'png gif jpg jpeg',
'max_filesize' => '',
'max_resolution' => '',
'min_resolution' => '',
'alt_field' => TRUE,
'alt_field_required' => TRUE,
'title_field' => FALSE,
'title_field_required' => FALSE,
'default_image' => [
'uuid' => NULL,
'alt' => '',
'title' => '',
'width' => NULL,
'height' => NULL,
],
],
])->save();
}
if (!$this->entityTypeManager->getStorage('field_config')
->load('media.image.field_media_image')) {
$this->entityTypeManager->getStorage('field_config')->create([
'field_name' => 'field_media_image',
'entity_type' => 'media',
'bundle' => 'image',
'label' => 'Image',
'required' => TRUE,
])->save();
}
if (!$this->entityTypeManager->getStorage('node_type')->load('node_type.article')) {
$this->entityTypeManager->getStorage('node_type')->create([
'type' => 'article',
'name' => 'Article',
])->save();
}
if (!$this->entityTypeManager->getStorage('field_storage_config')->load('field_storage_config.field_name.body')) {
$this->entityTypeManager->getStorage('field_storage_config')->create([
'field_name' => 'body',
'entity_type' => 'node',
'type' => 'text_long',
])->save();
}
if (!$this->entityTypeManager->getStorage('field_config')->load('field_config.field_name.body')) {
$this->entityTypeManager->getStorage('field_config')->create([
'field_name' => 'body',
'entity_type' => 'node',
'bundle' => 'article',
'label' => 'Body',
'settings' => [
'allowed_formats' => ['full_html'],
],
])->save();
}
// Create a filter format with media_embed enabled.
$format = $this->entityTypeManager->getStorage('filter_format')->create([
'format' => 'full_html',
'name' => 'Full HTML',
'filters' => [
'media_embed' => ['status' => TRUE],
],
]);
$format->save();
// Create an editor using CKEditor 5.
$this->entityTypeManager->getStorage('editor')->create([
'format' => 'full_html',
'editor' => 'ckeditor5',
])->save();
// Prepare the public directory.
$publicDirectory = 'public://';
$fileSystem->prepareDirectory($publicDirectory, FileSystemInterface::CREATE_DIRECTORY |
FileSystemInterface::MODIFY_PERMISSIONS);
// Create a test image in the public directory with real content.
$fileName = 'test_image.jpg';
$filePath = $publicDirectory . $fileName;
// Create a simple JPEG image content (minimal valid JPEG header)
$imageContent = base64_decode('/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKAP/2Q==');
file_put_contents($filePath, $imageContent);
/** @var \Drupal\file\FileInterface $file */
$file = $this->entityTypeManager->getStorage('file')->create([
'uri' => $filePath,
'filename' => $fileName,
'filemime' => 'image/jpeg',
'status' => 1,
]);
$file->save();
$this->file = $file;
// Create a user.
$user = $this->entityTypeManager->getStorage('user')->create([
'name' => 'tester',
]);
$user->save();
$this->user = $user;
// Get the file URL (important for tests to use the correct path format)
$file_url = $this->fileUrlGenerator->generateAbsoluteString($this->file->getFileUri());
// Strip the domain part for internal URL - but ensure it starts with the
// public files path.
$file_url = parse_url($file_url, PHP_URL_PATH);
// Create a node with a raw <img> tag in the body.
$node = $this->entityTypeManager->getStorage('node')->create([
'type' => 'article',
'title' => 'Test Node',
'body' => [
'value' => '<p>Image: <img src="' . $file_url . '" alt="test image" /></p>',
'format' => 'full_html',
],
'uid' => $user->id(),
]);
$node->save();
$this->node = $node;
// Assertions to confirm the setup is valid.
$this->assertNotNull($this->entityTypeManager->getStorage('media_type')
->load('image'));
$this->assertTrue($this->entityTypeManager->getStorage('media')
->getEntityType()
->hasKey('bundle'));
$this->assertTrue($node->hasField('body'));
}
/**
* Tests that the service can find eligible text fields.
*
* @covers \Drupal\image_to_media_swapper\BatchProcessorService::getEligibleTextFields
*/
public function testEligibleTextFieldsWithAllowedFormat(): void {
$fields = $this->service->getEligibleTextFields();
$this->assertArrayHasKey('node.article.body', $fields);
}
/**
* Tests that the service can find entities with images in a specific field.
*
* @covers \Drupal\image_to_media_swapper\BatchProcessorService::getEntitiesWithFiles
*/
public function testGetEntitiesWithFilesFindsNodes(): void {
$result = $this->service->getEntitiesWithFiles('node.article.body');
$this->assertArrayHasKey($this->node->id(), $result);
$this->assertCount(1, $result);
}
/**
* Tests that the service can find a file entity from a public URI.
*
* @covers \Drupal\image_to_media_swapper\BatchProcessorService::processContentByCategory
*/
public function testSwapImagesToMedia(): void {
// Debug the file URL to verify it's what we expect.
$file_url = $this->fileUrlGenerator->generateAbsoluteString($this->file->getFileUri());
$file_path = parse_url($file_url, PHP_URL_PATH);
$this->assertNotEmpty($file_path, 'File path should not be empty');
// Debug the node body content to verify the img tag is correct.
$body_value = $this->node->get('body')->value;
$this->assertStringContainsString('<img src="', $body_value, 'Body should contain img tag');
$this->assertStringContainsString($file_path, $body_value, 'Body should contain correct file path');
// Process the node to convert images to media entities.
$result = $this->service->processContentByCategory('node.article.body', [$this->node], 'images');
// Debug the result array.
if (empty($result)) {
$this->fail('Result array is empty - no entities were processed');
}
// Check that the node was processed.
$this->assertArrayHasKey($this->node->id(), $result);
// Load the updated node.
$updated = $this->entityTypeManager->getStorage('node')
->load($this->node->id());
$this->assertNotNull($updated, 'Updated node was loaded.');
// Check that the node body now contains drupal-media tag.
$value = $updated->get('body')->value;
$this->assertStringContainsString('<drupal-media', $value);
$this->assertStringContainsString('data-entity-uuid', $value);
}
}
