CKEditorAdminTest.php 14.3 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\ckeditor\Tests\CKEditorAdminTest.
6 7 8 9
 */

namespace Drupal\ckeditor\Tests;

10
use Drupal\Component\Serialization\Json;
11
use Drupal\editor\Entity\Editor;
12
use Drupal\filter\FilterFormatInterface;
13 14 15 16
use Drupal\simpletest\WebTestBase;

/**
 * Tests administration of CKEditor.
17 18
 *
 * @group ckeditor
19 20 21 22 23 24 25 26 27 28
 */
class CKEditorAdminTest extends WebTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  public static $modules = array('filter', 'editor', 'ckeditor');

29 30 31 32 33 34 35
  /**
   * A user with the 'administer filters' permission.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $adminUser;

36
  protected function setUp() {
37 38 39 40 41 42 43 44 45 46 47 48
    parent::setUp();

    // Create text format.
    $filtered_html_format = entity_create('filter_format', array(
      'format' => 'filtered_html',
      'name' => 'Filtered HTML',
      'weight' => 0,
      'filters' => array(),
    ));
    $filtered_html_format->save();

    // Create admin user.
49
    $this->adminUser = $this->drupalCreateUser(array('administer filters'));
50 51
  }

52 53 54 55
  /**
   * Tests configuring a text editor for an existing text format.
   */
  function testExistingFormat() {
56
    $ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
57

58
    $this->drupalLogin($this->adminUser);
59
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

    // Ensure no Editor config entity exists yet.
    $editor = entity_load('editor', 'filtered_html');
    $this->assertFalse($editor, 'No Editor config entity exists yet.');

    // Verify the "Text Editor" <select> when a text editor is available.
    $select = $this->xpath('//select[@name="editor[editor]"]');
    $select_is_disabled = $this->xpath('//select[@name="editor[editor]" and @disabled="disabled"]');
    $options = $this->xpath('//select[@name="editor[editor]"]/option');
    $this->assertTrue(count($select) === 1, 'The Text Editor select exists.');
    $this->assertTrue(count($select_is_disabled) === 0, 'The Text Editor select is not disabled.');
    $this->assertTrue(count($options) === 2, 'The Text Editor select has two options.');
    $this->assertTrue(((string) $options[0]) === 'None', 'Option 1 in the Text Editor select is "None".');
    $this->assertTrue(((string) $options[1]) === 'CKEditor', 'Option 2 in the Text Editor select is "CKEditor".');
    $this->assertTrue(((string) $options[0]['selected']) === 'selected', 'Option 1 ("None") is selected.');

76 77 78 79
    // Select the "CKEditor" editor and click the "Save configuration" button.
    $edit = array(
      'editor[editor]' => 'ckeditor',
    );
80
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
81 82
    $this->assertRaw(t('You must configure the selected text editor.'));

83 84 85
    // Ensure the CKEditor editor returns the expected default settings.
    $expected_default_settings = array(
      'toolbar' => array(
86 87
        'rows' => array(
          // Button groups
88
          array(
89
            array(
90
              'name' => 'Formatting',
91 92 93
              'items' => array('Bold', 'Italic',),
            ),
            array(
94
              'name' => 'Links',
95 96 97
              'items' => array('DrupalLink', 'DrupalUnlink',),
            ),
            array(
98
              'name' => 'Lists',
99 100 101
              'items' => array('BulletedList', 'NumberedList',),
            ),
            array(
102
              'name' => 'Media',
103 104 105
              'items' => array('Blockquote', 'DrupalImage',),
            ),
            array(
106
              'name' => 'Tools',
107 108
              'items' => array('Source',),
            ),
109 110 111 112 113
          ),
        ),
      ),
      'plugins' => array(),
    );
114
    $this->assertIdentical($this->castSafeStrings($ckeditor->getDefaultSettings()), $expected_default_settings);
115

116
    // Keep the "CKEditor" editor selected and click the "Configure" button.
117
    $this->drupalPostAjaxForm(NULL, $edit, 'editor_configure');
118 119 120
    $editor = entity_load('editor', 'filtered_html');
    $this->assertFalse($editor, 'No Editor config entity exists yet.');

121 122 123 124 125 126 127 128 129 130 131 132
    // Ensure that drupalSettings is correct.
    $ckeditor_settings_toolbar = array(
      '#theme' => 'ckeditor_settings_toolbar',
      '#editor' => Editor::create(['editor' => 'ckeditor']),
      '#plugins' => $this->container->get('plugin.manager.ckeditor.plugin')->getButtons(),
    );
    $this->assertEqual(
      $this->drupalSettings['ckeditor']['toolbarAdmin'],
      $this->container->get('renderer')->renderPlain($ckeditor_settings_toolbar),
      'CKEditor toolbar settings are rendered as part of drupalSettings.'
    );

133 134
    // Ensure the toolbar buttons configuration value is initialized to the
    // expected default value.
135 136
    $expected_buttons_value = json_encode($expected_default_settings['toolbar']['rows']);
    $this->assertFieldByName('editor[settings][toolbar][button_groups]', $expected_buttons_value);
137 138 139 140 141 142 143

    // Ensure the styles textarea exists and is initialized empty.
    $styles_textarea = $this->xpath('//textarea[@name="editor[settings][plugins][stylescombo][styles]"]');
    $this->assertFieldByXPath('//textarea[@name="editor[settings][plugins][stylescombo][styles]"]', '', 'The styles textarea exists and is empty.');
    $this->assertTrue(count($styles_textarea) === 1, 'The "styles" textarea exists.');

    // Submit the form to save the selection of CKEditor as the chosen editor.
144
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
145 146 147 148 149 150

    // Ensure an Editor object exists now, with the proper settings.
    $expected_settings = $expected_default_settings;
    $expected_settings['plugins']['stylescombo']['styles'] = '';
    $editor = entity_load('editor', 'filtered_html');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists now.');
151
    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
152 153

    // Configure the Styles plugin, and ensure the updated settings are saved.
154
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
155 156 157
    $edit = array(
      'editor[settings][plugins][stylescombo][styles]' => "h1.title|Title\np.callout|Callout\n\n",
    );
158
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
159 160 161
    $expected_settings['plugins']['stylescombo']['styles'] = "h1.title|Title\np.callout|Callout\n\n";
    $editor = entity_load('editor', 'filtered_html');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
162
    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
163 164 165 166

    // Change the buttons that appear on the toolbar (in JavaScript, this is
    // done via drag and drop, but here we can only emulate the end result of
    // that interaction). Test multiple toolbar rows and a divider within a row.
167
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
168 169
    $expected_settings['toolbar']['rows'][0][] = array(
      'name' => 'Action history',
170
      'items' => array('Undo', '|', 'Redo', 'JustifyCenter'),
171 172
    );
    $edit = array(
173
      'editor[settings][toolbar][button_groups]' => json_encode($expected_settings['toolbar']['rows']),
174
    );
175
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
176 177
    $editor = entity_load('editor', 'filtered_html');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
178
    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
    // Check that the markup we're setting for the toolbar buttons (actually in
    // JavaScript's drupalSettings, and Unicode-escaped) is correctly rendered.
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
    // Create function to encode HTML as we expect it in drupalSettings.
    $json_encode = function($html) {
      return trim(Json::encode($html), '"');
    };
    // Check the Button separator.
    $this->assertRaw($json_encode('<li data-drupal-ckeditor-button-name="-" class="ckeditor-button-separator ckeditor-multiple-button" data-drupal-ckeditor-type="separator"><a href="#" role="button" aria-label="Button separator" class="ckeditor-separator"></a></li>'));
    // Check the Format dropdown.
    $this->assertRaw($json_encode('<li data-drupal-ckeditor-button-name="Format" class="ckeditor-button"><a href="#" role="button" aria-label="Format"><span class="ckeditor-button-dropdown">Format<span class="ckeditor-button-arrow"></span></span></a></li>'));
    // Check the Styles dropdown.
    $this->assertRaw($json_encode('<li data-drupal-ckeditor-button-name="Styles" class="ckeditor-button"><a href="#" role="button" aria-label="Styles"><span class="ckeditor-button-dropdown">Styles<span class="ckeditor-button-arrow"></span></span></a></li>'));
    // Check strikethrough.
    $this->assertRaw($json_encode('<li data-drupal-ckeditor-button-name="Strike" class="ckeditor-button"><a href="#" class="cke-icon-only cke_ltr" role="button" title="strike" aria-label="strike"><span class="cke_button_icon cke_button__strike_icon">strike</span></a></li>'));

196 197
    // Now enable the ckeditor_test module, which provides one configurable
    // CKEditor plugin — this should not affect the Editor config entity.
198
    \Drupal::service('module_installer')->install(array('ckeditor_test'));
199
    $this->resetAll();
200
    $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
201
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
202 203 204 205
    $ultra_llama_mode_checkbox = $this->xpath('//input[@type="checkbox" and @name="editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]" and not(@checked)]');
    $this->assertTrue(count($ultra_llama_mode_checkbox) === 1, 'The "Ultra llama mode" checkbox exists and is not checked.');
    $editor = entity_load('editor', 'filtered_html');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
206
    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
207 208

    // Finally, check the "Ultra llama mode" checkbox.
209
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
210 211 212
    $edit = array(
      'editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]' => '1',
    );
213
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
214
    $this->drupalGet('admin/config/content/formats/manage/filtered_html');
215 216
    $ultra_llama_mode_checkbox = $this->xpath('//input[@type="checkbox" and @name="editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]" and @checked="checked"]');
    $this->assertTrue(count($ultra_llama_mode_checkbox) === 1, 'The "Ultra llama mode" checkbox exists and is checked.');
217
    $expected_settings['plugins']['llama_contextual_and_button']['ultra_llama_mode'] = TRUE;
218 219
    $editor = entity_load('editor', 'filtered_html');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
220
    $this->assertIdentical($expected_settings, $editor->getSettings());
221 222
  }

223 224 225 226 227 228 229
  /**
   * Tests configuring a text editor for a new text format.
   *
   * This test only needs to ensure that the basics of the CKEditor
   * configuration form work; details are tested in testExistingFormat().
   */
  function testNewFormat() {
230
    $this->drupalLogin($this->adminUser);
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    $this->drupalGet('admin/config/content/formats/add');

    // Verify the "Text Editor" <select> when a text editor is available.
    $select = $this->xpath('//select[@name="editor[editor]"]');
    $select_is_disabled = $this->xpath('//select[@name="editor[editor]" and @disabled="disabled"]');
    $options = $this->xpath('//select[@name="editor[editor]"]/option');
    $this->assertTrue(count($select) === 1, 'The Text Editor select exists.');
    $this->assertTrue(count($select_is_disabled) === 0, 'The Text Editor select is not disabled.');
    $this->assertTrue(count($options) === 2, 'The Text Editor select has two options.');
    $this->assertTrue(((string) $options[0]) === 'None', 'Option 1 in the Text Editor select is "None".');
    $this->assertTrue(((string) $options[1]) === 'CKEditor', 'Option 2 in the Text Editor select is "CKEditor".');
    $this->assertTrue(((string) $options[0]['selected']) === 'selected', 'Option 1 ("None") is selected.');

    // Name our fancy new text format, select the "CKEditor" editor and click
    // the "Configure" button.
    $edit = array(
      'name' => 'My amazing text format',
      'format' => 'amazing_format',
      'editor[editor]' => 'ckeditor',
    );
    $this->drupalPostAjaxForm(NULL, $edit, 'editor_configure');
    $filter_format = entity_load('filter_format', 'amazing_format');
    $this->assertFalse($filter_format, 'No FilterFormat config entity exists yet.');
    $editor = entity_load('editor', 'amazing_format');
    $this->assertFalse($editor, 'No Editor config entity exists yet.');

    // Ensure the toolbar buttons configuration value is initialized to the
    // default value.
    $ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
    $default_settings = $ckeditor->getDefaultSettings();
    $expected_buttons_value = json_encode($default_settings['toolbar']['rows']);
    $this->assertFieldByName('editor[settings][toolbar][button_groups]', $expected_buttons_value);

    // Ensure the styles textarea exists and is initialized empty.
    $styles_textarea = $this->xpath('//textarea[@name="editor[settings][plugins][stylescombo][styles]"]');
    $this->assertFieldByXPath('//textarea[@name="editor[settings][plugins][stylescombo][styles]"]', '', 'The styles textarea exists and is empty.');
    $this->assertTrue(count($styles_textarea) === 1, 'The "styles" textarea exists.');

    // Submit the form to create both a new text format and an associated text
    // editor.
    $this->drupalPostForm(NULL, $edit, t('Save configuration'));

    // Ensure a FilterFormat object exists now.
    $filter_format = entity_load('filter_format', 'amazing_format');
    $this->assertTrue($filter_format instanceof FilterFormatInterface, 'A FilterFormat config entity exists now.');

    // Ensure an Editor object exists now, with the proper settings.
    $expected_settings = $default_settings;
    $expected_settings['plugins']['stylescombo']['styles'] = '';
    $editor = entity_load('editor', 'amazing_format');
    $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists now.');
282
    $this->assertIdentical($this->castSafeStrings($expected_settings), $this->castSafeStrings($editor->getSettings()), 'The Editor config entity has the correct settings.');
283 284
  }

285
}