Closed xurizaemon closed 9 months ago
Had a look at this today on a project.
Can confirm that CKEditor 5 does not use an iframe.
The sibling element also has the class ck
instead of cke
The editor element is child of the sibling with class ck-editor__editable
and has the attribute contenteditable="true"
My first thought was we can target the element using the xpath $field->getXpath() . "/following-sibling::div[contains(@class, 'ck')]//div[contains(@class, 'ck-editor__editable')]";
and then using that element as the keyboard trigger.
The project I was testing on is using the ChromeDriver not Selenium, so that stopped me going down that path.
In the end I've got it working using a similar approach to https://stackoverflow.com/questions/72445268/how-can-i-use-behat-to-set-the-value-of-a-ckeditor-5-field
$editorId = $field->getAttribute('data-ckeditor5-id');
$this->getSession()->executeScript("Drupal.CKEditor5Instances.get(\"$editorId\").setData(\"$value\");");
Keen to get feedback on that approach used in that Stack overflow issue / above.
This is a code that is working on the consumer project. It will be a replacement for an existing wysiwygFillField()
.
The old wysiwygFillField()
implementation will be removed (BC break). Anyone needing the old implementation can copy/paste the code into their custom FeatureContext.
/**
* Set value for WYSIWYG field.
*
* If used with Selenium driver, it will try to find associated WYSIWYG and
* fill it in. If used with webdriver - it will fill in the field as normal.
*
* @When /^(?:|I )fill in WYSIWYG "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
*/
public function wysiwygFillField($field, $value) {
$field = $this->wysiwygFixStepArgument($field);
$value = $this->wysiwygFixStepArgument($value);
$page = $this->getSession()->getPage();
$element = $page->findField($field);
if ($element === NULL) {
throw new ElementNotFoundException($this->getSession()->getDriver(), 'form field', 'id|name|label|value|placeholder', $field);
}
$driver = $this->getSession()->getDriver();
try {
$driver->evaluateScript('true');
}
catch (UnsupportedDriverActionException $exception) {
// For non-JS drivers process field in a standard way.
$element->setValue($value);
return;
}
// Find parent element.
$parent_element_xpath = $element->getXpath() . "/ancestor::div[contains(@class, 'form-item--')][1]";
$parent_elements = $driver->find($parent_element_xpath);
if (empty($parent_elements[0])) {
throw new ElementNotFoundException($this->getSession()->getDriver(), 'WYSIWYG form field', 'id|name|label|value|placeholder', $field);
}
$parent_field_classes = $parent_elements[0]->getAttribute('class');
$parent_field_classes = explode(' ', $parent_field_classes);
// Find exact class name starting with 'form-item--'.
$parent_field_classes = array_filter($parent_field_classes, function ($class) {
return str_starts_with($class, 'form-item--');
});
$parent_field_class = reset($parent_field_classes);
$this->getSession()
->executeScript(
"
const domEditableElement = document.querySelector(\"div.$parent_field_class .ck-editor__editable\");
if (domEditableElement.ckeditorInstance) {
const editorInstance = domEditableElement.ckeditorInstance;
if (editorInstance) {
editorInstance.setData(\"$value\");
} else {
throw new Exception('Could not get the editor instance');
}
} else {
throw new Exception('Could not find the element');
}
");
}
Implemented in #168
While testing #122, I noticed that the current
When I fill in WYSIWYG "Body" with "Some content"
doesn't locate any iframes - and I think this is because CKEditor 5 does not use iframes.If that's true, then WysiwygTrait will need updating to support that.
https://github.com/drevops/behat-steps/blob/master/src/WysiwygTrait.php#L17-L88
Would appreciate anyone being able to confirm this!