crop-8.x-2.x-dev/tests/src/Functional/CropFunctionalTest.php
tests/src/Functional/CropFunctionalTest.php
<?php
namespace Drupal\Tests\crop\Functional;
use Drupal\Component\Utility\UrlHelper;
use Drupal\crop\CropInterface;
use Drupal\image\Entity\ImageStyle;
use Drupal\Tests\BrowserTestBase;
use Drupal\crop\Entity\Crop;
use Drupal\crop\Entity\CropType;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
/**
* Functional tests for crop API.
*
* @group crop
*/
class CropFunctionalTest extends BrowserTestBase {
/**
* Test file URI.
*/
protected string $fileUri = 'public://sarajevo.png';
/**
* Modules to enable.
*
* @var array
*/
protected static $modules = ['crop', 'file'];
/**
* Admin user.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* Test image style.
*
* @var \Drupal\image\ImageStyleInterface
*/
protected $testStyle;
/**
* Test crop type.
*
* @var \Drupal\crop\CropInterface
*/
protected $cropType;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->adminUser = $this->drupalCreateUser(['administer crop types', 'administer image styles']);
// Create test image style.
$this->testStyle = ImageStyle::create([
'name' => 'test',
'label' => 'Test image style',
'effects' => [],
]);
$this->testStyle->save();
}
/**
* Tests crop type crud pages.
*/
public function testCropTypeCrud(): void {
$assert_session = $this->assertSession();
// Anonymous users don't have access to crop type admin pages.
$this->drupalGet('admin/config/media/crop');
$assert_session->statusCodeEquals(403);
$this->drupalGet('admin/config/media/crop/add');
$assert_session->statusCodeEquals(403);
// Can access pages if logged in and no crop types exist.
$this->drupalLogin($this->adminUser);
$this->drupalGet('admin/config/media/crop');
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains('No crop types available.');
$assert_session->linkExists('Add crop type');
// Can access add crop type form.
$this->clickLink('Add crop type');
$assert_session->statusCodeEquals(200);
$assert_session->addressEquals('admin/config/media/crop/add');
// Create crop type.
$crop_type_id = strtolower($this->randomMachineName());
$edit = [
'id' => $crop_type_id,
'label' => $this->randomMachineName(),
'description' => $this->getRandomGenerator()->word(10),
];
$this->drupalGet('admin/config/media/crop/add');
$this->submitForm($edit, 'Save crop type');
$assert_session->responseContains("The crop type <em class=\"placeholder\">{$edit['label']}</em> has been added.");
$this->cropType = CropType::load($crop_type_id);
$assert_session->addressEquals('admin/config/media/crop');
$label = $this->xpath("//td[contains(concat(' ',normalize-space(@class),' '),' menu-label ')]");
$this->assertStringContainsString($edit['label'], $label[0]->getText(), 'Crop type label found on listing page.');
$assert_session->pageTextContains($edit['description']);
// Check edit form.
$this->clickLink('Edit');
$assert_session->pageTextContains("Edit {$edit['label']} crop type");
$assert_session->responseContains($edit['id']);
$assert_session->fieldExists('edit-label');
$assert_session->responseContains($edit['description']);
// See if crop type appears on image effect configuration form.
$this->drupalGet('admin/config/media/image-styles/manage/' . $this->testStyle->id() . '/add/crop_crop');
$option = $this->xpath("//select[@id='edit-data-crop-type']/option");
$this->assertStringContainsString($edit['label'], $option[0]->getText(), 'Crop type label found on image effect page.');
$this->drupalGet('admin/config/media/image-styles/manage/' . $this->testStyle->id() . '/add/crop_crop');
$this->submitForm(['data[crop_type]' => $edit['id']], 'Add effect');
$assert_session->pageTextContains('The image effect was successfully applied.');
$assert_session->pageTextContains("Manual crop uses {$edit['label']} crop type");
$this->testStyle = $this->container->get('entity_type.manager')->getStorage('image_style')->loadUnchanged($this->testStyle->id());
$this->assertCount(1, $this->testStyle->getEffects(), 'One image effect added to test image style.');
$effect_configuration = $this->testStyle->getEffects()->getIterator()->current()->getConfiguration();
self::assertEquals($effect_configuration['data'], ['crop_type' => $edit['id'], 'automatic_crop_provider' => NULL], 'Manual crop effect uses correct image style.');
// Tests the image URI is extended with shortened hash in case of image
// style and corresponding crop existence.
$this->doTestFileUriAlter();
$this->assertSame(0, $this->countCrops());
// Try to access edit form as anonymous user.
$this->drupalLogout();
$this->drupalGet('admin/config/media/crop/manage/' . $edit['id']);
$assert_session->statusCodeEquals(403);
$this->drupalLogin($this->adminUser);
// Try to create crop type with same machine name.
$this->drupalGet('admin/config/media/crop/add');
$this->submitForm($edit, 'Save crop type');
$assert_session->pageTextContains('The machine-readable name is already in use. It must be unique.');
$file = $this->createFile();
$this->addCropToCropType($file);
$this->assertSame(1, $this->countCrops());
// Flush all crops of the type we just saved.
$this->drupalGet('admin/config/media/crop');
$assert_session->linkExists('Test image style');
$this->clickLink('Flush');
$assert_session->pageTextContains('This action cannot be undone.');
$this->click('.crop-type-flush-form .form-actions input[type="submit"]');
// Expected that all crop are deleted.
$this->assertSame(0, $this->countCrops());
$this->drupalGet('admin/config/media/crop');
$assert_session->linkExists('Test image style');
$this->clickLink('Flush');
$assert_session->pageTextContains("you can safely delete this crop type.");
// Clean file.
$file->delete();
// Delete crop type.
$this->drupalGet('admin/config/media/crop');
$assert_session->linkExists('Test image style');
$this->clickLink('Delete');
$label = $edit['label'];
$assert_session->pageTextContains("Are you sure you want to delete the crop type $label?");
// Confirm that the user is warned about the crop type being used by other
// config objects.
$assert_session->pageTextContains('The listed configuration will be deleted.');
$assert_session->pageTextContains('Test image style');
$this->submitForm([], 'Delete');
$assert_session->statusMessageContains("The crop type $label has been deleted.");
$assert_session->pageTextContains('No crop types available.');
}
/**
* Asserts a shortened hash is added to the file URI.
*
* Tests crop_file_url_alter().
*/
protected function doTestFileUriAlter(): void {
$file = $this->createFile();
$crop = $this->addCropToCropType($file);
$this->assertSame(1, $this->countCrops());
// Test that the hash is appended both when a URL is created and passed
// through file_create_url() and when a URL is created, without additional
// file_create_url() calls.
$shortened_hash = $crop->getShortHash();
// Build an image style derivative for the file URI.
$image_style_uri = $this->testStyle->buildUri($this->fileUri);
$image_style_uri_url = \Drupal::service('file_url_generator')->generateAbsoluteString($image_style_uri);
$url = UrlHelper::parse($image_style_uri_url);
$this->assertSame($shortened_hash, $url['query']['h'], 'The image style URL contains a shortened hash.');
$image_style_url = $this->testStyle->buildUrl($this->fileUri);
$url = UrlHelper::parse($image_style_url);
$this->assertSame($shortened_hash, $url['query']['h'], 'The image style URL contains a shortened hash.');
// Update the crop to assert the hash has changed.
$crop->setPosition('80', '80')->save();
$old_hash = $shortened_hash;
$new_hash = $crop->getShortHash();
$image_style_url = $this->testStyle->buildUrl($this->fileUri);
$url = UrlHelper::parse($image_style_url);
$this->assertSame($new_hash, $url['query']['h'], 'The image style URL contains an updated hash.');
// Delete the file and the crop entity associated,
// the crop entity are auto cleaned by crop_file_delete().
$file->delete();
// Check that the crop entity is correctly deleted.
$this->assertFalse(Crop::cropExists($this->fileUri), 'The Crop entity was correctly deleted after file delete.');
}
/**
* Creates a file to use for testing crops.
*
* @return \Drupal\file\FileInterface
* A new, saved file entity.
*/
private function createFile(): FileInterface {
\Drupal::service('file_system')
->copy(__DIR__ . '/../../files/sarajevo.png', 'public://');
/** @var \Drupal\file\FileInterface $file*/
$file = File::create(['uri' => $this->fileUri]);
$file->setPermanent();
$file->save();
return $file;
}
/**
* Create Crop.
*
* @param \Drupal\file\FileInterface $file
* Public file.
*
* @return \Drupal\crop\CropInterface
* Newly created Crop.
*/
private function addCropToCropType(FileInterface $file): CropInterface {
$crop = Crop::create([
'type' => $this->cropType->id(),
'entity_id' => $file->id(),
'entity_type' => $file->getEntityTypeId(),
'uri' => $this->fileUri,
'x' => '100',
'y' => '150',
'width' => '200',
'height' => '250',
]);
$crop->save();
return $crop;
}
/**
* Count the number of crops of $this->cropType that exist.
*
* @return int
* Number of crops.
*/
private function countCrops(): int {
return \Drupal::entityTypeManager()
->getStorage('crop')
->getQuery()
->count()
->accessCheck(FALSE)
->condition('type', $this->cropType->id())
->execute();
}
}
