image_to_media_swapper-2.x-dev/tests/src/FunctionalJavascript/MediaSwapperCKEditorTestDisabled.php

tests/src/FunctionalJavascript/MediaSwapperCKEditorTestDisabled.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\image_to_media_swapper\FunctionalJavascript;

use Drupal\editor\Entity\Editor;
use Drupal\file\FileInterface;
use Drupal\filter\Entity\FilterFormat;
use Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5TestBase;
use Drupal\media\MediaInterface;
use Drupal\Tests\ckeditor5\Traits\CKEditor5TestTrait;
use Drupal\Tests\image_to_media_swapper\Traits\MediaFieldSetupTrait;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\Tests\TestFileCreationTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\user\RoleInterface;
use Drupal\user\UserInterface;

/**
 * Tests CKEditor media swapping functionality.
 *
 * @group image_to_media_swapper
 * @group ckeditor5
 */
class MediaSwapperCKEditorTestDisabled extends CKEditor5TestBase {

  use CKEditor5TestTrait;
  use MediaFieldSetupTrait;
  use MediaTypeCreationTrait;
  use TestFileCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'node',
    'ckeditor5',
    'file',
    'image',
    'media',
    'media_library',
    'image_to_media_swapper',
    'serialization',
    'options',
  ];

  /**
   * A user with permission to create content and use media.
   *
   * @var \Drupal\user\UserInterface
   */
  protected UserInterface $authorUser;

  /**
   * Test file entity.
   *
   * @var \Drupal\file\FileInterface
   */
  protected FileInterface $testFile;

  /**
   * Test media entity.
   *
   * @var \Drupal\media\MediaInterface
   */
  protected MediaInterface $testMedia;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    // Create image media type using the trait.
    $this->createMediaImageType();

    // Setup text format with media swapper.
    $this->setupTextFormatWithMediaSwapper();

    // Configure the body field to allow our format.
    $this->configureBodyField();

    // Create user with comprehensive permissions.
    $permissions = [
      'administer filters',
      'create page content',
      'edit own page content',
      'edit any page content',
      'use text format ckeditor5',
      'create media',
      'access media overview',
      'access content',
      'view own unpublished content',
    ];
    $user = $this->drupalCreateUser($permissions);
    $this->drupalLogin($user);
    $this->authorUser = $user;

    // Create a test image file.
    $test_files = $this->getTestFiles('image');
    $this->testFile = File::create([
      'uri' => $test_files[0]->uri,
      'filename' => $test_files[0]->filename,
      'filemime' => mime_content_type($test_files[0]->uri),
      'status' => 1,
    ]);
    $this->testFile->save();

    // Create test media entity.
    $this->testMedia = Media::create([
      'bundle' => 'image',
      'name' => 'Test Image',
      'field_media_image' => [
        'target_id' => $this->testFile->id(),
        'alt' => 'Test image alt text',
      ],
    ]);
    $this->testMedia->save();
  }

  /**
   * Configure the body field to allow our text format.
   */
  protected function configureBodyField(): void {
    // Create a new filter format that's available to all authenticated users.
    FilterFormat::create([
      'format' => 'basic_html',
      'name' => 'Basic HTML',
      'roles' => [RoleInterface::AUTHENTICATED_ID],
      'filters' => [
        'filter_html' => [
          'status' => TRUE,
          'settings' => [
            'allowed_html' => '<p> <br>',
          ],
        ],
      ],
    ])->save();

    $field_config = FieldConfig::loadByName('node', 'page', 'body');
    if (!$field_config) {
      return;
    }

    // Allow both formats so there's a selector.
    $settings = $field_config->getSettings();
    $settings['allowed_formats'] = ['ckeditor5', 'basic_html'];
    $settings['default_format'] = 'ckeditor5';
    $field_config->setSettings($settings);
    $field_config->save();

    // Clear caches.
    \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
  }

  /**
   * Sets up text format with media swapper functionality.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function setupTextFormatWithMediaSwapper(): void {
    // Create filter format with proper HTML allowlist.
    FilterFormat::create([
      'format' => 'ckeditor5',
      'name' => 'CKEditor 5',
      'roles' => [RoleInterface::AUTHENTICATED_ID],
      'filters' => [
        'filter_html' => [
          'status' => TRUE,
          'settings' => [
            'allowed_html' => '<br> <p> <h2> <h3> <h4> <h5> <h6> <strong> <em> <img alt height src width data-entity-type data-entity-uuid> <drupal-media data-entity-type data-entity-uuid alt data-view-mode>',
          ],
        ],
        'filter_align' => ['status' => TRUE],
        'filter_caption' => ['status' => TRUE],
      ],
    ])->save();

    // Create editor configuration with proper toolbar including media swapper.
    Editor::create([
      'editor' => 'ckeditor5',
      'format' => 'ckeditor5',
      'settings' => [
        'toolbar' => [
          'items' => [
            'bold',
            'italic',
            'drupalInsertImage',
          ],
        ],
        'plugins' => [
          'ckeditor5_heading' => [
            'enabled_headings' => [
              'heading2',
              'heading3',
              'heading4',
              'heading5',
              'heading6',
            ],
          ],
        ],
      ],
      'image_upload' => [
        'status' => FALSE,
      ],
    ])->save();
  }

  /**
   * Tests that the media swapper button appears in CKEditor toolbar.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Drupal\Core\Entity\EntityMalformedException|\Behat\Mink\Exception\ElementNotFoundException
   */

  /**
   * Helper method to create a test node with CKEditor body field.
   *
   * @return \Drupal\node\Entity\Node
   *   The created node.
   */
  protected function createTestNode(): Node {
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'uid' => $this->authorUser->id(),
      'status' => 1,
      'body' => [
        [
          'value' => '<p>Test content</p>',
          'format' => 'ckeditor5',
          'summary' => '',
        ],
      ],
    ]);
    $node->save();
    return $node;
  }

  /**
   * Helper method to insert an image into CKEditor using JavaScript.
   *
   * @param array $attributes
   *   Image attributes to set.
   */
  protected function insertImageIntoEditor(array $attributes): void {
    $attrs_js = json_encode($attributes);
    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  if (!editorId) {
    throw new Error('No CKEditor5 instances found');
  }
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {$attrs_js});
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for image to appear in the editor.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img', 10000);
  }

  /**
   * Helper method to safely click confirm button with proper waits.
   *
   * @param string $selector
   *   CSS selector for the button to click.
   */
  protected function clickConfirmButton(string $selector = '.confirm-yes'): void {
    // First wait for the confirm container to exist with timeout.
    $container = $this->assertSession()->waitForElement('css', '.custom-confirm-container', 10000);
    $this->assertNotNull($container, 'Confirm dialog container should appear');

    // Wait for the specific button to be visible and clickable.
    $confirm_button = $this->assertSession()->waitForElementVisible('css', $selector, 5000);

    // If the specific selector not found, try fallback buttons in order.
    if (!$confirm_button) {
      $possible_selectors = ['.confirm-yes', '.confirm-no', '.custom-confirm-box button'];
      foreach ($possible_selectors as $fallback_selector) {
        $confirm_button = $this->assertSession()->waitForElementVisible('css', $fallback_selector, 2000);
        if ($confirm_button) {
          break;
        }
      }
    }

    $this->assertNotNull($confirm_button, 'No clickable button found in confirm dialog. Tried selector: ' . $selector);

    // Ensure the button is actually clickable before clicking.
    $this->assertTrue($confirm_button->isVisible(), 'Button should be visible before clicking');
    $confirm_button->click();
  }

  /**
   * Tests that the media swapper button exists in the CKEditor toolbar.
   */
  public function testMediaSwapperButtonExists(): void {
    // Debug: Check current user permissions.
    $current_user = \Drupal::currentUser();
    $user_permissions = [];
    if ($current_user->isAuthenticated()) {
      $user_permissions = $current_user->getAccount()->getRoles();
    }

    // Create and visit test node.
    $node = $this->createTestNode();

    // Debug: Check node details.
    if (!$node->id()) {
      $this->fail('Node was not saved properly - no ID found');
    }

    // Debug: Try to load the node to make sure it exists.
    $loaded_node = Node::load($node->id());
    if (!$loaded_node) {
      $this->fail('Created node could not be loaded from database');
    }

    $edit_url = $node->toUrl('edit-form')->toString();
    $this->drupalGet($edit_url);

    // Debug: Check what page we actually landed on.
    $page = $this->getSession()->getPage();
    $current_url = $this->getSession()->getCurrentUrl();
    $page_title = $page->find('css', 'title')?->getText() ?? 'No title';
    $page_h1 = $page->find('css', 'h1')?->getText() ?? 'No H1';

    // Check for any error messages.
    $error_messages = $page->findAll('css', '.messages--error');
    $errors = [];
    foreach ($error_messages as $error) {
      $errors[] = $error->getText();
    }

    if (!empty($errors)) {
      $this->fail('Page has error messages: ' . implode('; ', $errors) . '. URL: ' . $current_url);
    }

    // Check if we got redirected (common for permission issues)
    if (strpos($current_url, '/edit') === FALSE) {
      $this->fail("Got redirected away from edit form. Current URL: $current_url, Page title: $page_title, H1: $page_h1, User roles: " . implode(', ', $user_permissions));
    }

    // Debug: Let's see what fields are actually available on the page.
    $form_elements = $page->findAll('css', 'input, textarea, select');

    $available_fields = [];
    foreach ($form_elements as $element) {
      $name = $element->getAttribute('name');
      $id = $element->getAttribute('id');
      if ($name) {
        $available_fields[] = "name: $name";
      }
      if ($id) {
        $available_fields[] = "id: $id";
      }
    }

    if (empty($available_fields)) {
      // Get more info about the page content.
      $page_content_sample = substr($page->getText(), 0, 500);
      $this->fail("No form fields found. URL: $current_url, Title: $page_title, H1: $page_h1, Content sample: $page_content_sample");
    }

    // Try different possible body field selectors.
    $possible_selectors = [
      'body[0][value]',
      'edit-body-0-value',
      'body',
      'edit-body',
      '.field--name-body textarea',
      'textarea[data-drupal-selector="edit-body-0-value"]',
    ];

    $body_field = NULL;
    foreach ($possible_selectors as $selector) {
      try {
        if (strpos($selector, '.') === 0 || strpos($selector, '[') !== FALSE) {
          // CSS selector.
          $body_field = $page->find('css', $selector);
        }
        else {
          // Field name.
          $body_field = $page->findField($selector);
        }
        if ($body_field) {
          break;
        }
      }
      catch (\Exception $e) {
        // Continue trying other selectors.
      }
    }

    if (!$body_field) {
      $this->fail('Body field not found. Available fields: ' . implode(', ', array_slice($available_fields, 0, 20)));
    }

    // Debug: Check what text format selector is present.
    $format_selector = $page->find('css', 'select[data-drupal-selector="edit-body-0-format--2"]');
    if (!$format_selector) {
      $format_selector = $page->find('css', 'select[name="body[0][format]"]');
    }

    if ($format_selector) {
      $selected_format = $format_selector->getValue();
      $available_options = [];
      $options = $format_selector->findAll('css', 'option');
      foreach ($options as $option) {
        $available_options[] = $option->getValue() . ':' . $option->getText();
      }

      if ($selected_format !== 'ckeditor5') {
        $this->fail("Wrong text format selected. Current: '$selected_format', Available: " . implode(', ', $available_options));
      }
    }
    else {
      $this->fail('No text format selector found - this suggests the field is not configured for multiple formats');
    }

    // Debug: Check if CKEditor instances are being created.
    $script = "return typeof Drupal.CKEditor5Instances !== 'undefined' ? Object.keys(Drupal.CKEditor5Instances).length : 'undefined';";
    $instances_count = $this->getSession()->evaluateScript($script);

    // Wait for CKEditor to initialize.
    $assert_session = $this->assertSession();
    $editor_element = $assert_session->waitForElement('css', '.ck-editor', 15000);
    if (!$editor_element) {
      $this->fail("CKEditor (.ck-editor) element not found. CKEditor5 instances: $instances_count");
    }

    // Debug: Check what elements are actually present.
    $ck_elements = $page->findAll('css', '[class*="ck-"]');
    $ck_classes = [];
    foreach (array_slice($ck_elements, 0, 10) as $element) {
      $ck_classes[] = $element->getAttribute('class');
    }

    // First verify CKEditor basic functionality works.
    $toolbar = $this->assertSession()
      ->waitForElement('css', '.ck-toolbar', 10000);
    if (!$toolbar) {
      $this->fail("CKEditor toolbar not found. CK elements found: " . implode(', ', $ck_classes));
    }

    // Debug: Check what buttons are actually in the toolbar.
    $toolbar_buttons = $toolbar->findAll('css', '.ck-button');
    $button_tooltips = [];
    foreach ($toolbar_buttons as $button) {
      $tooltip = $button->getAttribute('data-cke-tooltip-text');
      if ($tooltip) {
        $button_tooltips[] = $tooltip;
      }
    }

    // Check for basic buttons to ensure editor is working.
    $bold_button = $this->assertSession()
      ->waitForElement('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Bold"]', 5000);
    if (!$bold_button) {
      $this->fail("Bold button not found. Available buttons: " . implode(', ', $button_tooltips));
    }
  }

  /**
   * Tests that clicking the media swapper button works.
   */
  public function testMediaSwapperButtonClick(): void {
    // Create a test node.
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'body' => [
        'value' => '<p>Test content</p>',
        'format' => 'ckeditor5',
      ],
    ]);
    $node->save();

    // Visit the node edit page.
    $this->drupalGet($node->toUrl('edit-form'));

    // Wait for CKEditor to initialize.
    $this->waitForEditor();

    // Insert a simple image for testing.
    $file_uri = $this->testFile->getFileUri();
    $image_url = \Drupal::service('file_url_generator')
      ->generateAbsoluteString($file_uri);

    // Use the WebDriver session execute method like core tests.
    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {
      dataEntityType: 'file',
      dataEntityUuid: '{$this->testFile->uuid()}',
      src: '{$image_url}',
      alt: 'Test image'
    });
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for the image to appear.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img');

    // Click on the image to select it using more reliable method.
    $image = $this->assertSession()->waitForElementVisible('css', '.ck-editor__editable img');
    $this->assertNotNull($image, 'Image should be visible in editor');
    $image->click();
    $this->assertSession()->waitForElement('css', '.ck-widget.ck-widget_selected');

    // Find and click the media swapper button with better waiting.
    $button = $this->assertSession()->waitForElement('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Convert to Media"]');
    $this->assertNotNull($button, 'Media Swapper button should be present');
    $button->click();

    // A custom dialog should appear asking to convert the image.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');
    $this->assertSession()
      ->elementTextContains('css', '.custom-confirm-box p', 'Convert this file-based image to a media entity?');

    // Click the "Yes" button to accept the dialog.
    $this->clickConfirmButton();

    // Wait for dialog to disappear with timeout.
    $this->assertSession()
      ->waitForElementRemoved('css', '.custom-confirm-container', 10000);
  }

  /**
   * Tests that media swapper shows error for external images.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @throws \Behat\Mink\Exception\ElementNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException|\Behat\Mink\Exception\ElementTextException
   * @throws \Behat\Mink\Exception\ExpectationException
   */
  public function testMediaSwapperWithExternalImage(): void {
    // Create a test node.
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'body' => [
        'value' => '<p>Test content</p>',
        'format' => 'ckeditor5',
      ],
    ]);
    $node->save();

    // Visit the node edit page.
    $this->drupalGet($node->toUrl('edit-form'));

    // Wait for CKEditor to initialize.
    $this->waitForEditor();

    // Insert an external image (no file entity attributes).
    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {
      src: 'https://example.com/external-image.jpg',
      alt: 'External image'
    });
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for the image to appear and click it.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img');
    $image = $this->assertSession()->waitForElement('css', '.ck-editor__editable img');
    $this->assertNotNull($image, 'Image should be present');
    $image->click();
    $this->getSession()->wait(500);

    // Click the media swapper button - should show error.
    $button = $this->assertSession()->waitForElement('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Convert to Media"]');
    $this->assertNotNull($button, 'Media swapper button should be present');
    $button->click();
    // Wait a bit for the API call to complete and error dialog to appear.
    $this->getSession()->wait(1000);

    // Verify error dialog appears.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');
    // Get the text of the error message.
    $this->assertSession()->elementExists('css', '.custom-confirm-box p');
    $this->assertSession()
      ->elementTextContains('css', '.custom-confirm-box p', 'Convert this file-based image to a media entity?');

    // Click "Yes" to proceed with conversion.
    $this->clickConfirmButton();

    // Wait for dialog to disappear.
    $this->assertSession()
      ->waitForElementRemoved('css', '.custom-confirm-container');

    // Wait a bit for the API call to complete and error dialog to appear.
    $this->getSession()->wait(1000);

    // An error dialog should appear after the API call fails.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');
  }

  /**
   * Tests that media swapper shows error for untracked images.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @throws \Behat\Mink\Exception\ElementNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException|\Behat\Mink\Exception\ElementTextException
   * @throws \Behat\Mink\Exception\ExpectationException
   */
  public function testMediaSwapperWithUntrackedImage(): void {
    // Create a test node.
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'body' => [
        'value' => '<p>Test content</p>',
        'format' => 'ckeditor5',
      ],
    ]);
    $node->save();

    // Visit the node edit page.
    $this->drupalGet($node->toUrl('edit-form'));

    // Wait for CKEditor to initialize.
    $this->waitForEditor();

    // Insert a simple image for testing.
    $file_uri = $this->testFile->getFileUri();
    $image_url = \Drupal::service('file_url_generator')
      ->generateAbsoluteString($file_uri);

    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {
      src: '{$image_url}',
      alt: 'Untracked image'
    });
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for the image to appear and click it.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img');
    $image = $this->getSession()
      ->getPage()
      ->find('css', '.ck-editor__editable img');
    $image->click();
    $this->getSession()->wait(500);

    // Click the media swapper button - should show error.
    $button = $this->getSession()
      ->getPage()
      ->find('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Convert to Media"]');
    $button->click();
    // Wait a bit for the API call to complete and error dialog to appear.
    $this->getSession()->wait(1000);

    // Verify error dialog appears.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');
    // Get the text of the error message.
    $this->assertSession()->elementExists('css', '.custom-confirm-box p');
    $this->assertSession()
      ->elementTextContains('css', '.custom-confirm-box p', 'Convert this file-based image to a media entity?');

  }

  /**
   * Tests that media swapper works with valid remote files.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Behat\Mink\Exception\ElementNotFoundException
   */
  public function testMediaSwapperWithValidRemoteFile(): void {
    // Create a test node.
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'body' => [
        'value' => '<p>Test content</p>',
        'format' => 'ckeditor5',
      ],
    ]);
    $node->save();

    // Visit the node edit page.
    $this->drupalGet($node->toUrl('edit-form'));

    // Wait for CKEditor to initialize.
    $this->waitForEditor();

    // Insert a remote image using a reliable placeholder service.
    $remote_image_url = 'https://via.placeholder.com/300x200.jpg';
    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {
      src: '{$remote_image_url}',
      alt: 'Remote test image'
    });
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for the image to appear and click it.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img');
    $image = $this->getSession()
      ->getPage()
      ->find('css', '.ck-editor__editable img');
    $image->click();
    $this->getSession()->wait(500);

    // Click the media swapper button.
    $button = $this->getSession()
      ->getPage()
      ->find('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Convert to Media"]');
    $this->assertNotNull($button, 'Media Swapper button should be present');
    $button->click();

    // Verify confirmation dialog appears.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');
    $this->assertSession()
      ->elementTextContains('css', '.custom-confirm-box p', 'Convert this file-based image to a media entity?');

    // Click "Yes" to proceed with conversion.
    $this->clickConfirmButton();

    // Wait for dialog to disappear.
    $this->assertSession()
      ->waitForElementRemoved('css', '.custom-confirm-container');

    // Note: This test verifies the UI interaction. The actual API call
    // to /media-api/swap-file-to-media/remote-uri would need to be mocked
    // or implemented in the test environment to test the full workflow.
  }

  /**
   * Test that clicking confirm-no leaves the content unchanged.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Behat\Mink\Exception\ElementNotFoundException|\Behat\Mink\Exception\ElementTextException
   */
  public function testMediaSwapperConfirmNo(): void {
    // Create a test node.
    $node = Node::create([
      'type' => 'page',
      'title' => 'Test Node',
      'body' => [
        'value' => '<p>Test content</p>',
        'format' => 'ckeditor5',
      ],
    ]);
    $node->save();

    // Visit the node edit page.
    $this->drupalGet($node->toUrl('edit-form'));

    // Wait for CKEditor to initialize.
    $this->waitForEditor();

    // Insert a simple image for testing.
    $file_uri = $this->testFile->getFileUri();
    $image_url = \Drupal::service('file_url_generator')
      ->generateAbsoluteString($file_uri);

    $script = <<<JS
(function() {
  const editorId = Object.keys(Drupal.CKEditor5Instances)[0];
  const editor = Drupal.CKEditor5Instances[editorId];
  editor.model.change(writer => {
    const imageBlock = writer.createElement('imageBlock', {
      dataEntityType: 'file',
      dataEntityUuid: '{$this->testFile->uuid()}',
      src: '{$image_url}',
      alt: 'Test image'
    });
    const root = editor.model.document.getRoot();
    writer.insert(imageBlock, root, 'end');
  });
})();
JS;
    $this->getSession()->getDriver()->getWebDriverSession()->execute([
      'script' => $script,
      'args' => [],
    ]);

    // Wait for the image to appear.
    $this->assertSession()->waitForElement('css', '.ck-editor__editable img');

    // Click on the image to select it.
    $image = $this->getSession()
      ->getPage()
      ->find('css', '.ck-editor__editable img');
    $image->click();
    $this->getSession()->wait(500);

    // Find and click the media swapper button.
    $button = $this->getSession()
      ->getPage()
      ->find('css', '.ck-toolbar .ck-button[data-cke-tooltip-text="Convert to Media"]');
    $this->assertNotNull($button, 'Media Swapper button should be present');

    // Click the media swapper button.
    $button->click();

    // A custom dialog should appear asking to convert the image.
    $this->assertSession()->waitForElement('css', '.custom-confirm-container');

    // Click the "No" button to cancel conversion.
    $this->assertSession()->elementExists('css', '.custom-confirm-box p');
    $this->assertSession()
      ->elementTextContains('css', '.custom-confirm-box p', 'Convert this file-based image to a media entity?');
    $this->getSession()->getPage()->find('css', '.confirm-no')->click();
    // Wait for dialog to disappear.
    $this->assertSession()
      ->waitForElementRemoved('css', '.custom-confirm-container');
    // Verify the image is still present in the editor.
    $this->assertSession()->elementExists('css', '.ck-editor__editable img');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc