I'm trying to fill a rich text editor field (TinyMCE) within my acceptance test in Codeception.
Using the fillField()
function doesn't work as this 'field' isn't really an input field. It's an iframe
, styled to look like a fancy textarea.
How can I set some text into the body of the TinyMCE box? I think I'm looking for the addition of a $I->setContent(xpathOrCSS)
function. Or does something else already exist to do this?
It is best to do this by adding re-usable actions to your Actor
class (AcceptanceTester
, by default). You can then use the actions in your tests to set the content of rich text editor fields without reducing the readability of your tests. More details on this are available in the Codeception documentation.
I have included solutions for TinyMCE and CKEditor below. The solution uses the executeInSelenium()
call to give us access to Facebook's underlying WebDriver bindings. From there, we simply use the frame switching/Javascript injection technique described here to set the content of our target editor.
Note that the final call to $webDriver->switchTo()->defaultContent()
is very important - this switches WebDriver's focus back from the RTE iframe
to the page that contains it.
Actor functions:
<?php
class AcceptanceTester extends \Codeception\Actor {
use _generated\AcceptanceTesterActions;
public function fillCkEditorById($element_id, $content) {
$this->fillRteEditor(
\Facebook\WebDriver\WebDriverBy::cssSelector(
'#cke_' . $element_id . ' .cke_wysiwyg_frame'
),
$content
);
}
public function fillCkEditorByName($element_name, $content) {
$this->fillRteEditor(
\Facebook\WebDriver\WebDriverBy::cssSelector(
'textarea[name="' . $element_name . '"] + .cke .cke_wysiwyg_frame'
),
$content
);
}
public function fillTinyMceEditorById($id, $content) {
$this->fillTinyMceEditor('id', $id, $content);
}
public function fillTinyMceEditorByName($name, $content) {
$this->fillTinyMceEditor('name', $name, $content);
}
private function fillTinyMceEditor($attribute, $value, $content) {
$this->fillRteEditor(
\Facebook\WebDriver\WebDriverBy::xpath(
'//textarea[@' . $attribute . '=\'' . $value . '\']/../div[contains(@class, \'mce-tinymce\')]//iframe'
),
$content
);
}
private function fillRteEditor($selector, $content) {
$this->executeInSelenium(
function (\Facebook\WebDriver\Remote\RemoteWebDriver $webDriver)
use ($selector, $content) {
$webDriver->switchTo()->frame(
$webDriver->findElement($selector)
);
$webDriver->executeScript(
'arguments[0].innerHTML = "' . addslashes($content) . '"',
[$webDriver->findElement(\Facebook\WebDriver\WebDriverBy::tagName('body'))]
);
$webDriver->switchTo()->defaultContent();
});
}
}
Example Usage:
$content = '<h1>Hello, world!</h1>';
// CKEditor
$I->fillCkEditorByName('rich_content', $content);
$I->fillCkEditorById('my_ckeditor_textarea', $content);
// TinyMCE
$I->fillTinyMceEditorByName('rich_content', $content);
$I->fillTinyMceEditorById('my_tinymce_textarea', $content);
In all cases, the first parameter refers to the name
/id
attribute of the original textarea
element, and the second parameter is the HTML content to fill it with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With