editor_advanced_image-8.x-2.x-dev/tests/src/FunctionalJavascript/CKEditor5EditorAdvancedImageDialogTest.php
tests/src/FunctionalJavascript/CKEditor5EditorAdvancedImageDialogTest.php
<?php
namespace Drupal\Tests\editor_advanced_image\FunctionalJavascript;
use Drupal\editor\Entity\Editor;
use Drupal\file\Entity\File;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\Tests\ckeditor5\Traits\CKEditor5TestTrait;
use Drupal\Tests\TestFileCreationTrait;
/**
* Ensure the CKE5 editor_advanced_image balloon works.
*
* @group editor_advanced_image
* @group editor_advanced_image_functional
* @group editor_advanced_image_ckeditor5
*
* @requires module ckeditor5
*/
class CKEditor5EditorAdvancedImageDialogTest extends WebDriverTestBase {
use CKEditor5TestTrait;
use TestFileCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'ckeditor5',
'node',
'text',
'editor_advanced_image',
];
/**
* The sample image File entity to embed.
*
* @var \Drupal\file\FileInterface
*/
protected $file;
/**
* The user to use during testing.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* The node to use during testing.
*
* @var \Drupal\node\NodeInterface
*/
protected $testNode;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'starterkit_theme';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
FilterFormat::create([
'format' => 'test_format',
'name' => 'Test format',
])->save();
Editor::create([
'editor' => 'ckeditor5',
'format' => 'test_format',
'settings' => [
'toolbar' => [
'items' => [
'link',
'bold',
'italic',
'drupalInsertImage',
],
],
'plugins' => [
'editor_advanced_image_image' => [
'enabled_attributes' => [],
'default_class' => '',
],
],
],
'image_upload' => [
'status' => TRUE,
'scheme' => 'public',
'directory' => 'inline-images',
'max_size' => '',
'max_dimensions' => [
'width' => 0,
'height' => 0,
],
],
])->save();
// Create a sample host entity to embed images in.
$this->file = File::create([
'uri' => $this->getTestFiles('image')[0]->uri,
]);
// Valid image.
$img_tag = '<img ' . $this->imageAttributesAsString() . ' width="500" />';
// Create a sample node to test EditorAdvancedImage on.
$this->drupalCreateContentType(['type' => 'blog']);
$this->testNode = $this->createNode([
'type' => 'blog',
'title' => 'Animals with strange names',
'body' => [
'value' => '<p><a href="https://en.wikipedia.org/wiki/Llama">Llamas</a> are cool!</p>' . $img_tag,
'format' => 'test_format',
],
]);
$this->testNode->save();
$this->drupalLogin($this->drupalCreateUser([
'use text format test_format',
'bypass node access',
]));
}
/**
* Provides the relevant image attributes.
*/
private function imageAttributes(): array {
return ['src' => '/core/misc/druplicon.png'];
}
/**
* Helper to format attributes.
*
* @param bool $reverse
* Reverse attributes when printing them.
*/
private function imageAttributesAsString($reverse = FALSE): string {
$string = [];
foreach ($this->imageAttributes() as $key => $value) {
$string[] = $key . '="' . $value . '"';
}
if ($reverse) {
$string = array_reverse($string);
}
return implode(' ', $string);
}
/**
* Tests that EditorAdvancedImage enabled setting attr are usable into CKE5.
*
* @dataProvider providerAttributesTest
*/
public function testAttributes(string $attribute_name, string $expected_input_label): void {
// Update text format and editor to allow editing of this attribute through
// the EditorAdvancedImage plugin.
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$settings['plugins']['editor_advanced_image_image']['enabled_attributes'][] = $attribute_name;
$editor->setSettings($settings)->save();
$page = $this->getSession()->getPage();
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
// Confirm the images widget exists.
$this->assertNotEmpty($image_block = $assert_session->waitForElementVisible('css', ".ck-content .ck-widget.image"));
// Open the Image balloon.
$img = $assert_session->waitForElementVisible('css', '.ck-content img', 1000);
$img->click();
// Ensure that the Editor Advanced Image button is visible on the Image
// Balloon.
$this->assertNotEmpty($eai_button = $this->getBalloonButton('Editor Advanced Image'));
$eai_button->click();
// Ensure the enabled attribute will enable only the corresponding input.
$balloon = $this->assertVisibleBalloon('.ck-editor-advanced-image');
$this->assertTrue($balloon->hasField($expected_input_label));
$eai_input = $page->find('css', '.ck-balloon-panel .ck-editor-advanced-image input[type=text]');
$eai_input->setValue("foo-bar-{$attribute_name}");
// Save the Balloon changes.
$this->assertNotEmpty($save_button = $this->getBalloonButton('Save'));
$save_button->click();
// Save the node and confirm that the attribute text is retained.
$page->pressButton('Save');
$this->assertNotEmpty($assert_session->waitForElement('css', "img[{$attribute_name}=\"foo-bar-{$attribute_name}\"]"));
// Ensure once re-open, the attribute value is reused as default value
// on the input of Editor Advanced Image Balloon form.
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
$img = $assert_session->waitForElementVisible('css', '.ck-content img', 1000);
$img->click();
$eai_button = $this->getBalloonButton('Editor Advanced Image');
$eai_button->click();
$balloon = $this->assertVisibleBalloon('.ck-editor-advanced-image');
$balloon->hasField($expected_input_label);
$eai_input = $page->find('css', '.ck-balloon-panel .ck-editor-advanced-image input[type=text]');
self::assertSame("foo-bar-{$attribute_name}", $eai_input->getValue());
// Clear the input field and save the changes in the balloon.
$eai_input->setValue('');
$this->assertNotEmpty($save_button = $this->getBalloonButton('Save'));
$save_button->click();
// Save the node and verify that the attribute value has been removed.
$page->pressButton('Save');
$imgElement = $assert_session->waitForElement('css', "img[{$attribute_name}]");
$this->assertEmpty($imgElement->getAttribute($attribute_name), "The attribute {$attribute_name} should be removed but {$imgElement->getAttribute($attribute_name)} founded.");
}
/**
* Tests that EditorAdvancedImage default class feature works.
*/
public function testDefaultClass(): void {
// Update text format and editor to allow editing of the class attribute via
// the EditorAdvancedImage plugin.
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$settings['plugins']['editor_advanced_image_image']['enabled_attributes'][] = 'class';
$settings['plugins']['editor_advanced_image_image']['default_class'] = 'img-responsive';
$editor->setSettings($settings)->save();
$page = $this->getSession()->getPage();
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
// Confirm the images widget exists.
$this->assertNotEmpty($image_block = $assert_session->waitForElementVisible('css', ".ck-content .ck-widget.image"));
// Open the Image balloon.
$image_block->click();
// Ensure that the Editor Advanced Image button is visible on the Image
// Balloon.
$eai_button = $this->getBalloonButton('Editor Advanced Image');
$eai_button->click();
// Ensure the enabled attribute will enable only the corresponding input.
$this->assertVisibleBalloon('.ck-editor-advanced-image');
// Ensure the class input will be filled with the default value.
$eai_input = $page->find('css', '.ck-balloon-panel .ck-editor-advanced-image input[type=text]');
self::assertSame("img-responsive", $eai_input->getValue());
// Override the value with another more specific class that should be kept.
$eai_input->setValue('img-fluid');
// Save the Balloon changes.
$this->assertNotEmpty($save_button = $this->getBalloonButton('Save'));
$save_button->click();
// Save the node and confirm that the attribute text is retained.
$page->pressButton('Save');
$this->assertNotEmpty($assert_session->waitForElement('css', 'img[class="img-fluid"]'));
// Ensure once re-open, the attribute value is reused as default value
// and replace the configured default_class.
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
$img = $assert_session->waitForElementVisible('css', '.ck-content img', 1000);
$img->click();
$eai_button = $this->getBalloonButton('Editor Advanced Image');
$eai_button->click();
$balloon = $this->assertVisibleBalloon('.ck-editor-advanced-image');
$balloon->hasField('class');
$eai_input = $page->find('css', '.ck-balloon-panel .ck-editor-advanced-image input[type=text]');
self::assertSame("img-fluid", $eai_input->getValue());
}
/**
* Tests that EditorAdvancedImage default class feature works.
*
* The difference to testDefaultClass() is, that the Editor Advanced Image
* form will not be opened and saved. The default class should be applied
* anyway.
*/
public function testDefaultClassWithoutInteraction(): void {
// Update text format and editor to allow editing of the class attribute via
// the EditorAdvancedImage plugin.
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$settings['plugins']['editor_advanced_image_image']['enabled_attributes'][] = 'class';
$settings['plugins']['editor_advanced_image_image']['default_class'] = 'img-responsive';
$editor->setSettings($settings)->save();
$page = $this->getSession()->getPage();
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
// Confirm the images widget exists.
$this->assertNotEmpty($image_block = $assert_session->waitForElementVisible('css', ".ck-content .ck-widget.image"));
// Open the Image balloon.
$image_block->click();
// Save the node and confirm that the attribute text is retained.
$page->pressButton('Save');
$this->assertNotEmpty($assert_session->waitForElement('css', 'img[class="img-responsive"]'));
}
/**
* A collection of attribute to enable and ensure works when enabled.
*/
public static function providerAttributesTest(): iterable {
return [
'<img title>' => [
'attribute_name' => 'title',
'expected_input_label' => 'Title',
],
'<img class>' => [
'attribute_name' => 'class',
'expected_input_label' => 'CSS classes',
],
'<img id>' => [
'attribute_name' => 'id',
'expected_input_label' => 'ID',
],
];
}
/**
* Tests that EditorAdvancedImage "Disable Balloon" setting prevent EAI btn.
*/
public function testDisabledBalloon(): void {
// Update text format and editor to disable the EAI balloon.
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$settings['plugins']['editor_advanced_image_image']['disable_balloon'] = TRUE;
$settings['plugins']['editor_advanced_image_image']['default_class'] = 'img-responsive';
$editor->setSettings($settings)->save();
$page = $this->getSession()->getPage();
$this->drupalGet($this->testNode->toUrl('edit-form'));
$this->waitForEditor();
$assert_session = $this->assertSession();
// Confirm the images widget exists.
$this->assertNotEmpty($image_block = $assert_session->waitForElementVisible('css', ".ck-content .ck-widget.image"));
// Open the Image balloon.
$image_block->click();
// Ensure the Default Class has been applied directly when the image has
// been added to CKEditor 5.
$this->assertNotEmpty($assert_session->waitForElement('css', 'img[class="img-responsive"]'));
// Ensure that the Editor Advanced Image button is not visible on the Image
// Balloon.
$button = $this->assertSession()->waitForElementVisible('xpath', "//button[span[text()='Editor Advanced Image']]");
$this->assertEmpty($button);
// Save the node and confirm that the attribute text is retained.
$page->pressButton('Save');
$this->assertNotEmpty($assert_session->waitForElement('css', 'img[class="img-responsive"]'));
}
}
