CKEditor is a WYSIWYG editor. There are other WYSIWYG editors, for example: TinyMCE.

most of the WYSIWYG editor along with CKEditor use <iframe> instead of <textarea> and displays the content inside the <body> element, however, it makes the UI automation process a little bit different.

Automate using native Selenium WebDriver API

Both CKEditor and TinyMCE are JavaScript based, which means they can be automated using Selenium WebDriver’s native API just like any other HTML web applications.

Basic Instructions

In the following example, we have used a Drupal Basic Page content type creation page.

From the Basic page creation page, first, we need to switch into CKEditor iframe:

#Wait for the CKEditor iframe to load and switch to iframe
time.sleep(3)
basic_page_body_xpath = "//div[contains(@id, 'cke_1_contents')]/iframe"

#Locate the iframes
ckeditor_frame = self.driver.find_element_by_xpath(basic_page_body_xpath)

#Switch to iframe
self.driver.switch_to.frame(ckeditor_frame)

Note that, for switching to any iframe we need to wait for the iframe to load.

Here, ‘time.sleep(3)’ do the waiting.

Now, input into the CKEditor:

#Send key to Ckeditor Body
editor_body = self.driver.find_element_by_xpath("//body")
editor_body.send_keys("Test Body")

Now, we need to get our from the CKEditor iframe and switch back to our main site content:

# if driver is already inside ckeditor_frame, switch out first
self.driver.switch_to_default_content()

These are the basic to input data into CKEditor. There are other advance features which are described bellow:

Click toolbar buttons

WYSIWYG editors normally provide native methods to set raw HTML content directly through API, automating the toolbar doesn’t seem to be really necessary. If it’s needed to be done for some reason, it shouldn’t be much of a problem, because toolbar elements are just ordinary web elements, the automating process is fairly straight-forward without any frame switching required.

  1. Find the elements by appropriate locators according to the HTML markup.
  2. Manipulate those elements see if they work or not.

Markup for CKEditor’s toolbar “Numbered List” button:

<a id="cke_39" class="cke_button cke_button__numberedlist" href="javascript:void('Insert/Remove Numbered List')" title="Insert/Remove Numbered List" role="button">
    <span class="cke_button_icon cke_button__numberedlist_icon" >&nbsp;</span>
    <span id="cke_39_label" class="cke_button_label cke_button__numberedlist_label">Insert/Remove Numbered List</span>
</a>

Markup for TinyMCE’s toolbar “Numbered List” button:

id=“mce_11” class=“mce-widget mce-btn” role=“button” aria-label=“Numbered list” aria-pressed=“false”> type=“button”> class=“mce-ico mce-i-numlist”>

Selenium WebDriver Ruby code to click the buttons:

# click CKEditor's 'Numbered List' button
ckeditor_btn_numbered_list = driver.find_element(:class => "cke_button__numberedlist")
ckeditor_btn_numbered_list.click

# click TinyMCE editor's 'Numbered List' button
tinymce_btn_numbered_list = driver.find_element(:css => ".mce-btn[aria-label='Numbered list'] button")
tinymce_btn_numbered_list.click

Clear all input

A quote from Selenium Ruby’s API documentation on clear() method:

If this element is a text entry element, this will clear the value. Has no effect on other elements.

Although clear() method is stated as not available for non-text entry elements, it seems it can actually clear the input iframe without any exceptions.

Apart from clear(), an alternative is to use Selenium’s ActionBuilder to construct an action chain to mimic keyboard shortcut pressing. Ctrl + A will select all, then push Backspace to clear.

# Method 1. Using clear() method
editor_body.clear

# Method 2. Using ActionBuilder
driver.action.click(editor_body)
             .key_down(:control)
             .send_keys("a")
             .key_up(:control)
             .perform
driver.action.send_keys(:backspace).perform

Automate using editors’ built-in JavaScript API

Without worrying about frame switching like using Selenium WebDriver’s native API, it would also be a stable solution to inject JavaScript directly usingdriver.execute_script() to call editors’ built-in JS functions.

Set content

Both editors have built-in methods to set the content of entire input area. CKEditor’s API provides a method called setData(), which replaces editor data with raw input HTML data. Similar method setContent() also exists in TinyMCE editor’s API.

driver.execute_script("CKEDITOR.instances.ckeditor.setData('<h1>Yi Zeng</h1> CKEditor')")
driver.execute_script("tinyMCE.activeEditor.setContent('<h1>Yi Zeng</h1> TinyMCE')")

Clear content

With the same logic, clearing content can be done by injecting JavaScript to set the entire content to empty string.

driver.execute_script("CKEDITOR.instances.ckeditor.setData( '' )")
driver.execute_script("tinyMCE.activeEditor.setContent('')")

Insert content

Instead of setting the entire content, it is also possible to insert some content to the editors. CKEditor’s has a method called insertHTML(), which inserts content at currently selected position, in TinyMCE, it’s called insertContent().

driver.execute_script("CKEDITOR.instances.ckeditor.insertHtml('<p>Christchurch</p>')")
driver.execute_script("tinyMCE.activeEditor.insertContent('<p>Christchurch</p>')")

Examples

Set content using Selenium WebDriver API

# Environment tested
# Linux Mint 16, Selenium 2.41.0, Chromium 33.0, ChromeDriver 2.9
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :chrome
driver.get('http://yizeng.me/2014/01/31/test-wysiwyg-editors-using-selenium-webdriver/')

ckeditor_frame = driver.find_element(:class => 'cke_wysiwyg_frame')
tinymce_frame = driver.find_element(:id => 'tinymce-editor_ifr')

# Using JavaScript injection to set innerHTML, shown as WYSIWYG
driver.switch_to.frame(ckeditor_frame)
ck_editor_body = driver.find_element(:tag_name => 'body')
driver.execute_script("arguments[0].innerHTML = '<h1>CKEditor</h1>Yi Zeng'", ck_editor_body)

driver.switch_to.default_content

# Using native 'send_keys' method, all content are wrapped with <p>
driver.switch_to.frame(tinymce_frame)
tinymce_body = driver.find_element(:css => 'body')
tinymce_body.send_keys('<h1>TInyMCE</h1>Yi Zeng')

Select all content

# Environment tested
# Linux Mint 16, Selenium 2.41.0, Chromium 33.0, ChromeDriver 2.9
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :chrome
driver.get('http://yizeng.me/2014/01/31/test-wysiwyg-editors-using-selenium-webdriver/')

driver.switch_to.frame(driver.find_element(:class => 'cke_wysiwyg_frame'))

ck_editor_body = driver.find_element(:tag_name => 'body')
ck_editor_body.send_keys("Yi Zeng")

driver.action.click(ck_editor_body)
             .key_down(:control)
             .send_keys("a")
             .key_up(:control)
             .perform

Click “Numbered list” from toolbar

# Environment tested
# Linux Mint 16, Selenium 2.41.0, Chromium 33.0, ChromeDriver 2.9
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :chrome
driver.get('http://yizeng.me/2014/01/31/test-wysiwyg-editors-using-selenium-webdriver/')

# click CKEditor's 'Numbered List' button
ckeditor_btn_numbered_list = driver.find_element(:class => "cke_button__numberedlist")
ckeditor_btn_numbered_list.click

# click TinyMCE editor's 'Numbered List' button
tinymce_btn_numbered_list = driver.find_element(:css => ".mce-btn[aria-label='Numbered list'] button")
tinymce_btn_numbered_list.click

Set content using editors’ API

# Environment tested
# Linux Mint 16, Selenium 2.41.0, Chromium 33.0, ChromeDriver 2.9
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :chrome
driver.get('http://yizeng.me/2014/01/31/test-wysiwyg-editors-using-selenium-webdriver/')

driver.execute_script("CKEDITOR.instances.ckeditor.setData('<h1>Yi Zeng</h1> CKEditor')")
driver.execute_script("tinyMCE.activeEditor.setContent('<h1>Yi Zeng</h1> TinyMCE')")

driver.execute_script("CKEDITOR.instances.ckeditor.insertHtml('<p>Christchurch</p>')")
driver.execute_script("tinyMCE.activeEditor.insertContent('<p>Christchurch</p>')")
Reference: http://yizeng.me/2014/01/31/test-wysiwyg-editors-using-selenium-webdriver/
Advertisements