I am trying to set content inside ckeditor, to be precise inside <body>
of an <iframe>
, but once when I switch to frame, system throws: NoSuchElementException. I have tried to find element by class or by css selector - none of these gave results.
I have found that issue is in setting content of <body>
itself, and this post:
How to get and set text editor value in selenium
but I am not sure how to execute JavaScript using Atata. Below are parts of my code.
Page where <iframe>
is located:
public class DocumentEditPage : Page<_>
{
[FindById("cke_1_contents")]
//[FindByClass("cke_wysiwyg_frame cke_reset")]
//[FindByIndex(0)]
public Frame<DocumentFramePage, _> ContentSwedish { get; private set;
}
Frame page:
public class DocumentFramePage : Page<_>
{
[FindByClass("cke_editable cke_editable_themed cke_contents_ltr cke_show_borders")]
//[FindByCss("body")]
public TextInput<_> TextBoxEditingContent { get; private set; }
}
Test:
[Test]
public void SaveContentInsideFrame()
{
string ID = "7";
string valueToBeSet = "TestContent";
Go.To<DocumentsPage>().
Documents.Rows[x => x.Dokument_ID == ID].Edit().
// Refresh page so the content can be visible
RefreshPage().
ContentSwedish.SwitchTo().
TextBoxEditingContent.Clear().
TextBoxEditingContent.Set(valueToBeSet).
SwitchToRoot<DocumentEditPage>().
// Click on Save button
Save();
}
HTML code of page:
<div id="cke_1_contents" class="cke_contents cke_reset" role="presentation" style="height: 200px;">
<span id="cke_52" class="cke_voice_label">Press ALT 0 for help</span>
<iframe src="" style="width: 100%; height: 100%;" class="cke_wysiwyg_frame cke_reset" title="Rich Text Editor, Details_0__Content" aria-describedby="cke_52" tabindex="0" allowtransparency="true" frameborder="0"></iframe></div>
<body class="cke_editable cke_editable_themed cke_contents_ltr cke_show_borders" spellcheck="false" contenteditable="true">
<h1>Test</h1>
<p>Test<br></p>
<p>Test<br></p>
<p><br></p>
</body>
You can create a control class for CKEditor as follows:
[ControlDefinition("iframe", ContainingClass = "cke_wysiwyg_frame", ComponentTypeName = "CKEditor")]
public class CKEditor<TOwner> : EditableField<string, TOwner>
where TOwner : PageObject<TOwner>
{
protected override string GetValue()
{
string value = null;
DoWithinFrame(body =>
{
value = body.Text;
});
return value;
}
protected override void SetValue(string value)
{
DoWithinFrame(body =>
{
body.Clear();
body.SendKeys(value);
});
}
// An appoach to set a value using JavaScript.
//protected override void SetValue(string value)
//{
// Driver.ExecuteScript(
// "arguments[0].contentDocument.getElementsByClassName('cke_editable_themed')[0].innerHTML = arguments[1];",
// Scope, // Actual CKEditor <iframe> element.
// value);
//}
protected void DoWithinFrame(Action<IWebElement> frameBodyAction)
{
var frame = Driver.SwitchTo().Frame(Scope);
var frameBody = frame.Get(By.TagName("body"));
frameBodyAction?.Invoke(frameBody);
Driver.SwitchTo().DefaultContent();
}
}
The logic of iframe
switches encapsulates inside it.
Then use it in the page object:
public class DocumentEditPage : Page<_>
{
public CKEditor<_> Editor { get; private set; }
}
And in the test interact with it as with a regular input field:
Go.To<DocumentEditPage>().
Editor.Set("sample text").
Editor.Should.Equal("sample text");
Above code works for CKEditor 4. Tested on https://ckeditor.com/ckeditor-4/demo/ page.