Skip to content

Commit b646b33

Browse files
committed
XWIKI-21338: Add automated functional tests for the real-time WYSIWYG editor
* Progress on the Page Objects and functional tests (cherry picked from commit ecaffe9)
1 parent 5b6007c commit b646b33

File tree

7 files changed

+258
-3
lines changed

7 files changed

+258
-3
lines changed

xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-test/xwiki-platform-ckeditor-test-pageobjects/src/main/java/org/xwiki/ckeditor/test/po/CKEditorToolBar.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,12 @@ public void toggleSourceMode()
100100
// Wait for the conversion between HTML and wiki syntax (source) to be done.
101101
getDriver().waitUntilElementDisappears(this.container, By.cssSelector(".cke_button__source_icon.loading"));
102102
}
103+
104+
/**
105+
* @return the element containing the tool bar
106+
*/
107+
protected WebElement getContainer()
108+
{
109+
return this.container;
110+
}
103111
}

xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-test/xwiki-platform-ckeditor-test-pageobjects/src/main/java/org/xwiki/ckeditor/test/po/RichTextAreaElement.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class RichTextAreaElement extends BaseElement
4242
/**
4343
* The in-line frame element.
4444
*/
45-
private final WebElement iframe;
45+
protected final WebElement iframe;
4646

4747
/**
4848
* Creates a new rich text area element.
@@ -183,4 +183,18 @@ public void waitUntilContentEditable()
183183
getDriver().switchTo().defaultContent();
184184
}
185185
}
186+
187+
/**
188+
* @return the scroll top position of the rich text area
189+
*/
190+
public int getScrollTop()
191+
{
192+
try {
193+
getDriver().switchTo().frame(this.iframe);
194+
return Integer
195+
.parseInt(getDriver().findElementWithoutWaiting(By.tagName("html")).getDomProperty("scrollTop"));
196+
} finally {
197+
getDriver().switchTo().defaultContent();
198+
}
199+
}
186200
}

xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-test/xwiki-platform-realtime-wysiwyg-test-docker/src/test/it/org/xwiki/realtime/wysiwyg/test/ui/RealtimeWYSIWYGEditorIT.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,18 @@
2020
package org.xwiki.realtime.wysiwyg.test.ui;
2121

2222
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.assertFalse;
24+
import static org.junit.jupiter.api.Assertions.assertTrue;
25+
26+
import java.util.List;
2327

2428
import org.junit.jupiter.api.BeforeAll;
2529
import org.junit.jupiter.api.Order;
2630
import org.junit.jupiter.api.Test;
2731
import org.xwiki.administration.test.po.WYSIWYGEditorAdministrationSectionPage;
2832
import org.xwiki.realtime.wysiwyg.test.po.RealtimeCKEditor;
33+
import org.xwiki.realtime.wysiwyg.test.po.RealtimeRichTextAreaElement;
34+
import org.xwiki.realtime.wysiwyg.test.po.RealtimeRichTextAreaElement.CoeditorPosition;
2935
import org.xwiki.realtime.wysiwyg.test.po.RealtimeWYSIWYGEditPage;
3036
import org.xwiki.test.docker.junit5.TestReference;
3137
import org.xwiki.test.docker.junit5.UITest;
@@ -79,10 +85,50 @@ static void configure(TestUtils setup)
7985
@Order(1)
8086
void editAlone(TestReference testReference, TestUtils setup)
8187
{
88+
// Start fresh.
89+
setup.deletePage(testReference);
90+
8291
RealtimeWYSIWYGEditPage editPage = RealtimeWYSIWYGEditPage.gotoPage(testReference);
8392
RealtimeCKEditor editor = editPage.getContenEditor();
84-
editor.getRichTextArea().sendKeys("test");
85-
ViewPage viewPage = editPage.clickSaveAndView();
93+
94+
// Verify that the Allow Realtime Collaboration checkbox is checked.
95+
assertTrue(editPage.isRealtimeEditing());
96+
97+
// Verify that the Preview button is hidden.
98+
assertFalse(editPage.getPreviewButton().isDisplayed());
99+
100+
// The Autosave checkbox is also hidden because autosave is done by the realtime editor (you can't disable it
101+
// while editing in realtime).
102+
assertFalse(editPage.getAutoSaveCheckbox().isDisplayed());
103+
104+
// Verify that we're editing alone.
105+
assertTrue(editor.getToolBar().isEditingAlone());
106+
107+
RealtimeRichTextAreaElement textArea = editor.getRichTextArea();
108+
textArea.sendKeys("test");
109+
110+
// Verify the cursor indicator on the left of the editing area.
111+
List<CoeditorPosition> coeditorPositions = textArea.getCoeditorPositions();
112+
assertEquals(1, coeditorPositions.size());
113+
114+
CoeditorPosition selfPosition = coeditorPositions.get(0);
115+
assertEquals("John", selfPosition.getAvatarHint());
116+
assertTrue(selfPosition.getAvatarURL().contains("noavatar.png"),
117+
"Unexpected avatar URL: " + selfPosition.getAvatarURL());
118+
assertEquals(3, selfPosition.getLocation().getX());
119+
assertEquals(18, selfPosition.getLocation().getY());
120+
121+
// Verify the action buttons (Save and Cancel).
122+
editPage.clickSaveAndContinue();
123+
textArea.sendKeys(" alone");
124+
ViewPage viewPage = editPage.clickCancel();
86125
assertEquals("test", viewPage.getContent());
126+
127+
// Edit again and verify the Save and View button.
128+
viewPage.edit();
129+
editPage = new RealtimeWYSIWYGEditPage();
130+
editPage.getContenEditor().getRichTextArea().sendKeys(" alone");
131+
viewPage = editPage.clickSaveAndView();
132+
assertEquals("test alone", viewPage.getContent());
87133
}
88134
}

xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-test/xwiki-platform-realtime-wysiwyg-test-pageobjects/src/main/java/org/xwiki/realtime/wysiwyg/test/po/RealtimeCKEditorToolBar.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919
*/
2020
package org.xwiki.realtime.wysiwyg.test.po;
2121

22+
import java.util.List;
23+
import java.util.stream.Collectors;
24+
25+
import org.openqa.selenium.By;
26+
import org.openqa.selenium.WebElement;
2227
import org.xwiki.ckeditor.test.po.CKEditorToolBar;
28+
import org.xwiki.test.ui.po.BaseElement;
2329

2430
/**
2531
* Represents the realtime CKEditor tool bar.
@@ -31,6 +37,59 @@
3137
*/
3238
public class RealtimeCKEditorToolBar extends CKEditorToolBar
3339
{
40+
/**
41+
* Represents a coeditor listed in the tool bar.
42+
*/
43+
public static class Coeditor extends BaseElement
44+
{
45+
private WebElement container;
46+
47+
public Coeditor(WebElement container)
48+
{
49+
this.container = container;
50+
}
51+
52+
public String getId()
53+
{
54+
return this.container.getAttribute("data-id");
55+
}
56+
57+
public String getName()
58+
{
59+
return this.container.getText();
60+
}
61+
62+
public String getReference()
63+
{
64+
return this.container.getAttribute("data-reference");
65+
}
66+
67+
public String getURL()
68+
{
69+
return this.container.getAttribute("href");
70+
}
71+
72+
public String getAvatarURL()
73+
{
74+
return getAvatar().getAttribute("src");
75+
}
76+
77+
public String getAvatarHint()
78+
{
79+
return getAvatar().getAttribute("title");
80+
}
81+
82+
public void click()
83+
{
84+
this.container.click();
85+
}
86+
87+
private WebElement getAvatar()
88+
{
89+
return getDriver().findElementWithoutWaiting(this.container, By.className("rt-user-avatar"));
90+
}
91+
}
92+
3493
/**
3594
* Create a new tool bar instance for the given editor.
3695
*
@@ -40,4 +99,22 @@ public RealtimeCKEditorToolBar(RealtimeCKEditor editor)
4099
{
41100
super(editor);
42101
}
102+
103+
/**
104+
* @return {@code true} if the user is editing alone, {@code false} otherwise
105+
*/
106+
public boolean isEditingAlone()
107+
{
108+
return "Editing alone"
109+
.equals(getDriver().findElementWithoutWaiting(getContainer(), By.className("rt-user-list")).getText());
110+
}
111+
112+
/**
113+
* @return the list of coeditors listed in the tool bar
114+
*/
115+
public List<Coeditor> getCoeditors()
116+
{
117+
return getDriver().findElementsWithoutWaiting(getContainer(), By.className("rt-user-link")).stream()
118+
.map(Coeditor::new).collect(Collectors.toList());
119+
}
43120
}

xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-test/xwiki-platform-realtime-wysiwyg-test-pageobjects/src/main/java/org/xwiki/realtime/wysiwyg/test/po/RealtimeRichTextAreaElement.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,15 @@
1919
*/
2020
package org.xwiki.realtime.wysiwyg.test.po;
2121

22+
import java.util.List;
23+
import java.util.stream.Collectors;
24+
25+
import org.apache.commons.lang3.StringUtils;
26+
import org.openqa.selenium.By;
27+
import org.openqa.selenium.Point;
2228
import org.openqa.selenium.WebElement;
2329
import org.xwiki.ckeditor.test.po.RichTextAreaElement;
30+
import org.xwiki.test.ui.po.BaseElement;
2431

2532
/**
2633
* Represents the realtime rich text area.
@@ -32,6 +39,39 @@
3239
*/
3340
public class RealtimeRichTextAreaElement extends RichTextAreaElement
3441
{
42+
/**
43+
* Represents the position of a coeditor in the rich text area (displayed on the left side).
44+
*/
45+
public static class CoeditorPosition extends BaseElement
46+
{
47+
private WebElement container;
48+
49+
public CoeditorPosition(WebElement container)
50+
{
51+
this.container = container;
52+
}
53+
54+
public String getCoeditorId()
55+
{
56+
return StringUtils.removeStart(this.container.getAttribute("id"), "rt-user-");
57+
}
58+
59+
public String getAvatarURL()
60+
{
61+
return this.container.getAttribute("src");
62+
}
63+
64+
public String getAvatarHint()
65+
{
66+
return this.container.getAttribute("title");
67+
}
68+
69+
public Point getLocation()
70+
{
71+
return this.container.getLocation();
72+
}
73+
}
74+
3575
/**
3676
* Creates a new realtime rich text area element.
3777
*
@@ -41,4 +81,28 @@ public RealtimeRichTextAreaElement(WebElement iframe)
4181
{
4282
super(iframe);
4383
}
84+
85+
/**
86+
* @return the position of the coeditors inside the rich text area
87+
*/
88+
public List<CoeditorPosition> getCoeditorPositions()
89+
{
90+
try {
91+
getDriver().switchTo().frame(this.iframe);
92+
return getDriver().findElementsWithoutWaiting(By.className("rt-user-position")).stream()
93+
.map(CoeditorPosition::new).collect(Collectors.toList());
94+
} finally {
95+
getDriver().switchTo().defaultContent();
96+
}
97+
}
98+
99+
/**
100+
* @param coeditorId the coeditor identifier
101+
* @return the location where the specified coeditor is currently editing
102+
*/
103+
public CoeditorPosition getCoeditorPosition(String coeditorId)
104+
{
105+
return getCoeditorPositions().stream().filter(position -> position.getCoeditorId().equals(coeditorId))
106+
.findFirst().orElse(null);
107+
}
44108
}

xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-test/xwiki-platform-realtime-wysiwyg-test-pageobjects/src/main/java/org/xwiki/realtime/wysiwyg/test/po/RealtimeWYSIWYGEditPage.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
package org.xwiki.realtime.wysiwyg.test.po;
2121

22+
import org.openqa.selenium.WebElement;
23+
import org.openqa.selenium.support.FindBy;
2224
import org.xwiki.model.reference.EntityReference;
2325
import org.xwiki.test.ui.po.editor.WYSIWYGEditPage;
2426

@@ -32,6 +34,9 @@
3234
*/
3335
public class RealtimeWYSIWYGEditPage extends WYSIWYGEditPage
3436
{
37+
@FindBy(className = "realtime-allow")
38+
private WebElement allowRealtimeCheckbox;
39+
3540
/**
3641
* Open the specified page in realtime WYSIWYG edit mode.
3742
*
@@ -51,4 +56,34 @@ public RealtimeCKEditor getContenEditor()
5156
{
5257
return new RealtimeCKEditor();
5358
}
59+
60+
/**
61+
* @return {@code true} if realtime editing is enabled, {@code false} otherwise
62+
*/
63+
public boolean isRealtimeEditing()
64+
{
65+
return this.allowRealtimeCheckbox.isSelected();
66+
}
67+
68+
/**
69+
* Leave the realtime editing session.
70+
*/
71+
public void leaveRealtimeEditing()
72+
{
73+
if (isRealtimeEditing()) {
74+
this.allowRealtimeCheckbox.click();
75+
// TODO: Handle the confirmation modal.
76+
}
77+
}
78+
79+
/**
80+
* Join the realtime editing session.
81+
*/
82+
public void joinRealtimeEditing()
83+
{
84+
if (!isRealtimeEditing()) {
85+
// TODO: Handle the confirmation modal and the page reload.
86+
this.allowRealtimeCheckbox.click();
87+
}
88+
}
5489
}

xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/editor/EditPage.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public class EditPage extends BasePage
5555
@FindBy(name = "action_cancel")
5656
protected WebElement cancel;
5757

58+
@FindBy(id = "doAutosave")
59+
protected WebElement autoSaveCheckbox;
60+
5861
@FindBy(id = "editcolumn")
5962
protected WebElement currentEditorDiv;
6063

@@ -222,6 +225,14 @@ public WebElement getSaveAndViewButton()
222225
return save;
223226
}
224227

228+
/**
229+
* @return the checkbox used to toggle auto-save
230+
*/
231+
public WebElement getAutoSaveCheckbox()
232+
{
233+
return this.autoSaveCheckbox;
234+
}
235+
225236
public ViewPage clickCancel()
226237
{
227238
this.cancel.click();

0 commit comments

Comments
 (0)