You are here

public function MediaTest::testLinkability in Drupal 10

Same name in this branch
  1. 10 core/modules/ckeditor/tests/src/FunctionalJavascript/MediaTest.php \Drupal\Tests\ckeditor\FunctionalJavascript\MediaTest::testLinkability()
  2. 10 core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php \Drupal\Tests\ckeditor5\FunctionalJavascript\MediaTest::testLinkability()

Tests linkability of the media CKEditor widget.

Due to the very different HTML markup generated for the editing view and the data view, this is explicitly testing the "editingDowncast" and "dataDowncast" results. These are CKEditor 5 concepts.

@dataProvider providerLinkability

See also

https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture...

File

core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php, line 855

Class

MediaTest
@coversDefaultClass \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Media @group ckeditor5 @internal

Namespace

Drupal\Tests\ckeditor5\FunctionalJavascript

Code

public function testLinkability(bool $unrestricted) {

  // Disable filter_html.
  if ($unrestricted) {
    FilterFormat::load('test_format')
      ->setFilterConfig('filter_html', [
      'status' => FALSE,
    ])
      ->save();
  }
  $page = $this
    ->getSession()
    ->getPage();
  $this
    ->drupalGet($this->host
    ->toUrl('edit-form'));
  $this
    ->waitForEditor();
  $assert_session = $this
    ->assertSession();

  // Initial state: the Drupal Media CKEditor Widget is not selected.
  $drupalmedia = $assert_session
    ->waitForElementVisible('css', '.ck-content .ck-widget.drupal-media');
  $this
    ->assertNotEmpty($drupalmedia);
  $this
    ->assertFalse($drupalmedia
    ->hasClass('.ck-widget_selected'));

  // Assert the "editingDowncast" HTML before making changes.
  $assert_session
    ->elementExists('css', '.ck-content .ck-widget.drupal-media > [data-drupal-media-preview]');

  // Assert the "dataDowncast" HTML before making changes.
  $xpath = new \DOMXPath($this
    ->getEditorDataAsDom());
  $this
    ->assertNotEmpty($xpath
    ->query('//drupal-media'));
  $this
    ->assertEmpty($xpath
    ->query('//a'));

  // Assert the link button is present and not pressed.
  $link_button = $this
    ->getEditorButton('Link');
  $this
    ->assertSame('false', $link_button
    ->getAttribute('aria-pressed'));

  // Wait for the preview to load.
  $preview = $assert_session
    ->waitForElement('css', '.ck-content .ck-widget.drupal-media [data-drupal-media-preview="ready"]');
  $this
    ->assertNotEmpty($preview);

  // Tests linking Drupal media.
  $drupalmedia
    ->click();
  $this
    ->assertTrue($drupalmedia
    ->hasClass('ck-widget_selected'));
  $this
    ->assertEditorButtonEnabled('Link');

  // Assert structure of image toolbar balloon.
  $this
    ->assertVisibleBalloon('.ck-toolbar[aria-label="Drupal Media toolbar"]');
  $link_media_button = $this
    ->getBalloonButton('Link media');

  // Click the "Link media" button.
  $this
    ->assertSame('false', $link_media_button
    ->getAttribute('aria-pressed'));
  $link_media_button
    ->press();

  // Assert structure of link form balloon.
  $balloon = $this
    ->assertVisibleBalloon('.ck-link-form');
  $url_input = $balloon
    ->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text');

  // Fill in link form balloon's <input> and hit "Save".
  $url_input
    ->setValue('http://linking-embedded-media.com');
  $balloon
    ->pressButton('Save');

  // Assert the "editingDowncast" HTML after making changes. Assert the link
  // exists, then assert the link exists. Then assert the expected DOM
  // structure in detail.
  $assert_session
    ->elementExists('css', '.ck-content a[href="http://linking-embedded-media.com"]');
  $assert_session
    ->elementExists('css', '.ck-content .drupal-media.ck-widget > a[href="http://linking-embedded-media.com"] > div[aria-label] > article > div > img[src*="image-test.png"]');

  // Assert the "dataDowncast" HTML after making changes.
  $xpath = new \DOMXPath($this
    ->getEditorDataAsDom());
  $this
    ->assertNotEmpty($xpath
    ->query('//drupal-media'));
  $this
    ->assertNotEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com"]'));
  $this
    ->assertNotEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com"]/drupal-media'));

  // Ensure that the media caption is retained and not linked as a result of
  // linking media.
  $this
    ->assertNotEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com"]/drupal-media[@data-caption="baz"]'));

  // Add `class="trusted"` to the link.
  $this
    ->assertEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com" and @class="trusted"]'));
  $this
    ->pressEditorButton('Source');
  $source_text_area = $assert_session
    ->waitForElement('css', '.ck-source-editing-area textarea');
  $this
    ->assertNotEmpty($source_text_area);
  $new_value = str_replace('<a ', '<a class="trusted" ', $source_text_area
    ->getValue());
  $source_text_area
    ->setValue('<p>temp</p>');
  $source_text_area
    ->setValue($new_value);
  $this
    ->pressEditorButton('Source');

  // When unrestricted, additional attributes on links should be retained.
  $xpath = new \DOMXPath($this
    ->getEditorDataAsDom());
  $this
    ->assertCount($unrestricted ? 1 : 0, $xpath
    ->query('//a[@href="http://linking-embedded-media.com" and @class="trusted"]'));

  // Save the entity whose text field is being edited.
  $page
    ->pressButton('Save');

  // Assert the HTML the end user sees.
  $assert_session
    ->elementExists('css', $unrestricted ? 'a[href="http://linking-embedded-media.com"].trusted img[src*="image-test.png"]' : 'a[href="http://linking-embedded-media.com"] img[src*="image-test.png"]');

  // Go back to edit the now *linked* <drupal-media>. Everything from this
  // point onwards is effectively testing "upcasting" and proving there is no
  // data loss.
  $this
    ->drupalGet($this->host
    ->toUrl('edit-form'));
  $this
    ->waitForEditor();

  // Assert the "dataDowncast" HTML before making changes.
  $xpath = new \DOMXPath($this
    ->getEditorDataAsDom());
  $this
    ->assertNotEmpty($xpath
    ->query('//drupal-media'));
  $this
    ->assertNotEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com"]'));
  $this
    ->assertNotEmpty($xpath
    ->query('//a[@href="http://linking-embedded-media.com"]/drupal-media'));

  // Tests unlinking media.
  $drupalmedia
    ->click();
  $this
    ->assertEditorButtonEnabled('Link');
  $this
    ->assertSame('true', $this
    ->getEditorButton('Link')
    ->getAttribute('aria-pressed'));

  // Assert structure of Drupal media toolbar balloon.
  $this
    ->assertVisibleBalloon('.ck-toolbar[aria-label="Drupal Media toolbar"]');
  $link_media_button = $this
    ->getBalloonButton('Link media');
  $this
    ->assertSame('true', $link_media_button
    ->getAttribute('aria-pressed'));
  $link_media_button
    ->click();

  // Assert structure of link actions balloon.
  $this
    ->getBalloonButton('Edit link');
  $unlink_image_button = $this
    ->getBalloonButton('Unlink');

  // Click the "Unlink" button.
  $unlink_image_button
    ->click();
  $this
    ->assertSame('false', $this
    ->getEditorButton('Link')
    ->getAttribute('aria-pressed'));

  // Assert the "editingDowncast" HTML after making changes. Assert the link
  // exists, then assert no link exists. Then assert the expected DOM
  // structure in detail.
  $assert_session
    ->elementNotExists('css', '.ck-content a');
  $assert_session
    ->elementExists('css', '.ck-content .drupal-media.ck-widget > div[aria-label] > article > div > img[src*="image-test.png"]');

  // Ensure that figcaption exists.
  // @see https://www.drupal.org/project/drupal/issues/3268318
  $assert_session
    ->elementExists('css', '.ck-content .drupal-media.ck-widget > figcaption');

  // Assert the "dataDowncast" HTML after making changes.
  $xpath = new \DOMXPath($this
    ->getEditorDataAsDom());
  $this
    ->assertNotEmpty($xpath
    ->query('//drupal-media'));
  $this
    ->assertEmpty($xpath
    ->query('//a'));
}