1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.test.ui.po

File BasePage.java

 
createWikiFromTemplateTest: Timed out after 10 seconds waiting for org.xwiki.test.ui....
testLoginLogoutAsAdmin: Element cannot be scrolled into view:[object XrayWrapper ...
 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
41% of files have more coverage

Code metrics

12
118
50
1
663
342
56
0.47
2.36
50
1.12

Classes

Class Line # Actions
BasePage 46 118 0% 56 29
0.838888983.9%
 

Contributing tests

This file is covered by 165 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.test.ui.po;
21   
22    import java.util.ArrayList;
23    import java.util.List;
24    import java.util.Locale;
25    import java.util.regex.Matcher;
26    import java.util.regex.Pattern;
27   
28    import org.apache.commons.lang3.LocaleUtils;
29    import org.openqa.selenium.By;
30    import org.openqa.selenium.JavascriptExecutor;
31    import org.openqa.selenium.WebElement;
32    import org.openqa.selenium.support.FindBy;
33    import org.openqa.selenium.support.FindBys;
34    import org.xwiki.test.ui.po.editor.ClassEditPage;
35    import org.xwiki.test.ui.po.editor.ObjectEditPage;
36    import org.xwiki.test.ui.po.editor.RightsEditPage;
37    import org.xwiki.test.ui.po.editor.WYSIWYGEditPage;
38    import org.xwiki.test.ui.po.editor.WikiEditPage;
39   
40    /**
41    * Represents the common actions possible on all Pages.
42    *
43    * @version $Id: 495121dfa4e4f0d4443709e417f7bcc674544e6c $
44    * @since 3.2M3
45    */
 
46    public class BasePage extends BaseElement
47    {
48    private static final By DRAWER_MATCHER = By.id("tmDrawer");
49   
50    /**
51    * Used for sending keyboard shortcuts to.
52    */
53    @FindBy(id = "xwikimaincontainer")
54    private WebElement mainContainerDiv;
55   
56    /**
57    * The top floating content menu bar.
58    */
59    @FindBy(id = "contentmenu")
60    private WebElement contentMenuBar;
61   
62    @FindBy(xpath = "//div[@id='tmCreate']/a[contains(@role, 'button')]")
63    private WebElement tmCreate;
64   
65    @FindBy(xpath = "//div[@id='tmMoreActions']/a[contains(@role, 'button')]")
66    private WebElement moreActionsMenu;
67   
68    @FindBy(id = "tmDrawerActivator")
69    private WebElement drawerActivator;
70   
71    @FindBy(xpath = "//input[@id='tmWatchDocument']/../span[contains(@class, 'bootstrap-switch-label')]")
72    private WebElement watchDocumentLink;
73   
74    @FindBy(id = "tmPage")
75    private WebElement pageMenu;
76   
77    @FindBys({ @FindBy(id = "tmRegister"), @FindBy(tagName = "a") })
78    private WebElement registerLink;
79   
80    @FindBy(xpath = "//a[@id='tmLogin']")
81    private WebElement loginLink;
82   
83    @FindBy(xpath = "//a[@id='tmUser']")
84    private WebElement userLink;
85   
86    @FindBy(xpath = "//li[contains(@class, 'navbar-avatar')]//img[contains(@class, 'avatar')]")
87    private WebElement userAvatarImage;
88   
89    @FindBy(id = "document-title")
90    private WebElement documentTitle;
91   
92    @FindBy(xpath = "//input[@id='tmWatchSpace']/../span[contains(@class, 'bootstrap-switch-label')]")
93    private WebElement watchSpaceLink;
94   
95    @FindBy(xpath = "//input[@id='tmWatchWiki']/../span[contains(@class, 'bootstrap-switch-label')]")
96    private WebElement watchWikiLink;
97   
98    @FindBy(css = "#tmMoreActions a[title='Children']")
99    private WebElement childrenLink;
100   
101    @FindBy(id = "tmNotifications")
102    private WebElement notificationsMenu;
103   
104    /**
105    * Used to scroll the page to the top before accessing the floating menu.
106    */
107    @FindBy(id = "companylogo")
108    protected WebElement logo;
109   
110    /**
111    * Note: when reusing instances of BasePage, the constructor is not doing the work anymore and the
112    * waitUntilPageJSIsLoaded() method needs to be executed manually, when needed.
113    * <p>
114    * Note2: Never call the constructor before navigating to the page you need to test first.
115    */
 
116  1449 toggle public BasePage()
117    {
118  1449 super();
119  1449 waitUntilPageJSIsLoaded();
120    }
121   
 
122  0 toggle public String getPageTitle()
123    {
124  0 return getDriver().getTitle();
125    }
126   
127    // TODO I think this should be in the AbstractTest instead -cjdelisle
 
128  6 toggle public String getPageURL()
129    {
130  6 return getDriver().getCurrentUrl();
131    }
132   
133    /**
134    * @param metaName the name of the XWiki document metadata
135    * @return the value of the specified XWiki document metadata for the current XWiki document
136    * @see #getHTMLMetaDataValue(String)
137    */
 
138  57 toggle public String getMetaDataValue(String metaName)
139    {
140  57 return getDriver().findElement(By.xpath("/html")).getAttribute("data-xwiki-" + metaName);
141    }
142   
143    /**
144    * @param metaName the name of the HTML meta field
145    * @return the value of the requested HTML meta field with from the current page
146    * @since 7.2RC1
147    */
 
148  2 toggle public String getHTMLMetaDataValue(String metaName)
149    {
150  2 return getDriver().findElement(By.xpath("//meta[@name='" + metaName + "']")).getAttribute("content");
151    }
152   
153    /**
154    * @return true if we are currently logged in, false otherwise
155    */
 
156  19 toggle public boolean isAuthenticated()
157    {
158  19 return getDriver().hasElementWithoutWaiting(By.id("tmUser"));
159    }
160   
161    /**
162    * Determine if the current page is a new document.
163    *
164    * @return true if the document is new, false otherwise
165    */
 
166  10 toggle public boolean isNewDocument()
167    {
168  10 return (Boolean) ((JavascriptExecutor) getDriver()).executeScript("return XWiki.docisnew");
169    }
170   
171    /**
172    * Perform a click on a "edit menu" sub-menu entry.
173    *
174    * @param id The id of the entry to follow
175    */
 
176  44 toggle protected void clickEditSubMenuEntry(String id)
177    {
178  44 clickSubMenuEntryFromMenu(By.xpath("//div[@id='tmEdit']/*[contains(@class, 'dropdown-toggle')]"), id);
179    }
180   
181    /**
182    * Performs a click on the "edit" button.
183    */
 
184  19 toggle public void edit()
185    {
186  19 WebElement editMenuButton =
187    getDriver().findElement(By.xpath("//div[@id='tmEdit']/a[contains(@role, 'button')]"));
188  19 editMenuButton.click();
189    }
190   
191    /**
192    * Gets a string representation of the URL for editing the page.
193    */
 
194  0 toggle public String getEditURL()
195    {
196  0 return getDriver().findElement(By.xpath("//div[@id='tmEdit']//a")).getAttribute("href");
197    }
198   
199    /**
200    * Performs a click on the "edit wiki" entry of the content menu.
201    */
 
202  17 toggle public WikiEditPage editWiki()
203    {
204  17 clickEditSubMenuEntry("tmEditWiki");
205  17 return new WikiEditPage();
206    }
207   
208    /**
209    * Performs a click on the "edit wysiwyg" entry of the content menu.
210    */
 
211  1 toggle public WYSIWYGEditPage editWYSIWYG()
212    {
213  1 clickEditSubMenuEntry("tmEditWysiwyg");
214  1 return new WYSIWYGEditPage();
215    }
216   
217    /**
218    * Performs a click on the "edit inline" entry of the content menu.
219    */
 
220  6 toggle public <T extends InlinePage> T editInline()
221    {
222  6 clickEditSubMenuEntry("tmEditInline");
223  6 return createInlinePage();
224    }
225   
226    /**
227    * Can be overridden to return extended {@link InlinePage}.
228    */
 
229  6 toggle @SuppressWarnings("unchecked")
230    protected <T extends InlinePage> T createInlinePage()
231    {
232  6 return (T) new InlinePage();
233    }
234   
235    /**
236    * Performs a click on the "edit acces rights" entry of the content menu.
237    */
 
238  1 toggle public RightsEditPage editRights()
239    {
240  1 clickEditSubMenuEntry("tmEditRights");
241  1 return new RightsEditPage();
242    }
243   
244    /**
245    * Performs a click on the "edit objects" entry of the content menu.
246    */
 
247  15 toggle public ObjectEditPage editObjects()
248    {
249  15 clickEditSubMenuEntry("tmEditObject");
250  15 return new ObjectEditPage();
251    }
252   
253    /**
254    * Performs a click on the "edit class" entry of the content menu.
255    */
 
256  4 toggle public ClassEditPage editClass()
257    {
258  4 clickEditSubMenuEntry("tmEditClass");
259  4 return new ClassEditPage();
260    }
261   
262    /**
263    * @since 3.2M3
264    */
 
265  12 toggle public void sendKeys(CharSequence... keys)
266    {
267  12 this.mainContainerDiv.sendKeys(keys);
268    }
269   
270    /**
271    * Waits until the page has loaded. Normally we don't need to call this method since a click in Selenium2 is a
272    * blocking call. However there are cases (such as when using a shortcut) when we asynchronously load a page.
273    *
274    * @return this page
275    * @since 3.2M3
276    */
 
277  33 toggle public BasePage waitUntilPageIsLoaded()
278    {
279  33 Test failure here getDriver().waitUntilElementIsVisible(By.id("footerglobal"));
280  32 return this;
281    }
282   
283    /**
284    * @since 7.2M3
285    */
 
286  9 toggle public void toggleDrawer()
287    {
288  9 if (isElementVisible(DRAWER_MATCHER)) {
289    // The drawer is visible, so we close it by clicking outside the drawer
290  0 this.mainContainerDiv.click();
291  0 getDriver().waitUntilElementDisappears(DRAWER_MATCHER);
292    } else {
293    // The drawer is not visible, so we open it
294  9 this.drawerActivator.click();
295  9 getDriver().waitUntilElementIsVisible(DRAWER_MATCHER);
296    }
297    }
298   
299    /**
300    * @return true if the drawer used to be hidden
301    * @since 8.4.5
302    * @since 9.0RC1
303    */
 
304  2 toggle public boolean showDrawer()
305    {
306  2 if (!isElementVisible(DRAWER_MATCHER)) {
307    // The drawer is not visible, so we open it
308  2 this.drawerActivator.click();
309  2 getDriver().waitUntilElementIsVisible(DRAWER_MATCHER);
310   
311  2 return true;
312    }
313   
314  0 return false;
315    }
316   
317    /**
318    * @return true if the drawer used to be displayed
319    * @since 8.4.5
320    * @since 9.0RC1
321    */
 
322  2 toggle public boolean hideDrawer()
323    {
324  2 if (isElementVisible(DRAWER_MATCHER)) {
325    // The drawer is visible, so we close it by clicking outside the drawer
326  2 Test failure here this.mainContainerDiv.click();
327  1 getDriver().waitUntilElementDisappears(DRAWER_MATCHER);
328   
329  1 return true;
330    }
331   
332  0 return false;
333    }
334   
335    /**
336    * @since 8.4.5
337    * @since 9.0RC1
338    */
 
339  0 toggle public boolean isDrawerVisible()
340    {
341  0 return isElementVisible(DRAWER_MATCHER);
342    }
343   
344    /**
345    * @since 7.2M3
346    */
 
347  4 toggle public void toggleActionMenu()
348    {
349  4 this.moreActionsMenu.click();
350    }
351   
352    /**
353    * @since 7.0RC1
354    */
 
355  4 toggle public void clickMoreActionsSubMenuEntry(String id)
356    {
357  4 clickSubMenuEntryFromMenu(By.xpath("//div[@id='tmMoreActions']/a[contains(@role, 'button')]"), id);
358    }
359   
360    /**
361    * @since 7.3M2
362    */
 
363  13 toggle public void clickAdminActionsSubMenuEntry(String id)
364    {
365  13 clickSubMenuEntryFromMenu(By.xpath("//div[@id='tmMoreActions']/a[contains(@role, 'button')]"), id);
366    }
367   
368    /**
369    * @since 7.0RC1
370    */
 
371  61 toggle private void clickSubMenuEntryFromMenu(By menuBy, String id)
372    {
373    // Open the parent Menu
374  61 getDriver().findElement(menuBy).click();
375    // Wait for the submenu entry to be visible
376  61 getDriver().waitUntilElementIsVisible(By.id(id));
377    // Click on the specified entry
378  61 getDriver().findElement(By.id(id)).click();
379    }
380   
381    /**
382    * @since 4.5M1
383    */
 
384  15 toggle public CreatePagePage createPage()
385    {
386  15 this.tmCreate.click();
387  15 return new CreatePagePage();
388    }
389   
390    /**
391    * @since 4.5M1
392    */
 
393  3 toggle public CopyPage copy()
394    {
395  3 clickAdminActionsSubMenuEntry("tmActionCopy");
396  3 return new CopyPage();
397    }
398   
 
399  2 toggle public RenamePage rename()
400    {
401  2 clickAdminActionsSubMenuEntry("tmActionRename");
402  2 return new RenamePage();
403    }
404   
405    /**
406    * @since 4.5M1
407    */
 
408  8 toggle public ConfirmationPage delete()
409    {
410  8 clickAdminActionsSubMenuEntry("tmActionDelete");
411  8 return new ConfirmationPage();
412    }
413   
414    /**
415    * @since 4.5M1
416    */
 
417  1 toggle public boolean canDelete()
418    {
419  1 toggleActionMenu();
420    // Don't wait here since test can use this method to verify that there's no Delete right on the current page
421    // and calling hasElement() would incurr the wait timeout.
422  1 boolean canDelete = getDriver().hasElementWithoutWaiting(By.id("tmActionDelete"));
423  1 toggleActionMenu();
424  1 return canDelete;
425    }
426   
427    /**
428    * @since 4.5M1
429    */
 
430  1 toggle public void watchDocument()
431    {
432  1 toggleNotificationsMenu();
433  1 this.watchDocumentLink.click();
434  1 toggleActionMenu();
435    }
436   
437    /**
438    * @since 4.5M1
439    */
 
440  0 toggle public boolean hasLoginLink()
441    {
442    // Note that we cannot test if the loginLink field is accessible since we're using an AjaxElementLocatorFactory
443    // and thus it would wait 15 seconds before considering it's not accessible.
444  0 return !getDriver().findElementsWithoutWaiting(By.id("tmLogin")).isEmpty();
445    }
446   
447    /**
448    * @since 4.5M1
449    */
 
450  4 toggle public LoginPage login()
451    {
452  4 toggleDrawer();
453  4 this.loginLink.click();
454  4 return new LoginPage();
455    }
456   
457    /**
458    * @since 4.5M1
459    */
 
460  2 toggle public String getCurrentUser()
461    {
462    // We need to show the drawer because #getText() does not allow getting hidden text (but allow finding the
463    // element and its attributes...)
464  2 boolean hide = showDrawer();
465   
466  2 String user = this.userLink.getText();
467   
468  2 if (hide) {
469  2 Test failure here hideDrawer();
470    }
471   
472  1 return user;
473    }
474   
475    /**
476    * @since 9.0RC1
477    */
 
478  1 toggle public List<Locale> getLocales()
479    {
480  1 List<WebElement> elements =
481    getDriver().findElementsWithoutWaiting(By.xpath("//ul[@id='tmLanguages_menu']/li/a"));
482  1 List<Locale> locales = new ArrayList<>(elements.size());
483  1 for (WebElement element : elements) {
484  2 String href = element.getAttribute("href");
485  2 Matcher matcher = Pattern.compile(".*\\?.*language=([^=&]*)").matcher(href);
486  2 if (matcher.matches()) {
487  2 String locale = matcher.group(1);
488  2 locales.add(LocaleUtils.toLocale(locale));
489    }
490    }
491   
492  1 return locales;
493    }
494   
495    /**
496    * @since 9.0RC1
497    */
 
498  1 toggle public ViewPage clickLocale(Locale locale)
499    {
500    // Open drawer
501  1 toggleDrawer();
502   
503    // Open Languages
504  1 WebElement languagesElement = getDriver().findElementWithoutWaiting(By.xpath("//a[@id='tmLanguages']"));
505  1 languagesElement.click();
506   
507    // Wait for the languages submenu to be open
508  1 getDriver().waitUntilCondition(webDriver ->
509    getDriver().findElementWithoutWaiting(By.id("tmLanguages_menu")).getAttribute("class")
510    .contains("collapse in")
511    );
512   
513    // Click passed locale
514  1 WebElement localeElement = getDriver().findElementWithoutWaiting(
515    By.xpath("//ul[@id='tmLanguages_menu']/li/a[contains(@href,'language=" + locale + "')]"));
516  1 localeElement.click();
517   
518  1 return new ViewPage();
519    }
520   
521    /**
522    * @since 4.5M1
523    */
 
524  3 toggle public void logout()
525    {
526  3 toggleDrawer();
527  3 getDriver().findElement(By.id("tmLogout")).click();
528    // Update the CSRF token because the context user has changed (it's guest user now). Otherwise, APIs like
529    // TestUtils#createUser*(), which expect the currently cached token to be valid, will fail because they would be
530    // using the token of the previously logged in user.
531  3 getUtil().recacheSecretToken();
532    }
533   
534    /**
535    * @since 4.5M1
536    */
 
537  0 toggle public RegistrationPage register()
538    {
539  0 toggleDrawer();
540  0 this.registerLink.click();
541  0 return new RegistrationPage();
542    }
543   
544    /**
545    * @since 4.5M1
546    */
 
547  42 toggle public String getDocumentTitle()
548    {
549  42 return this.documentTitle.getText();
550    }
551   
552    /**
553    * @since 4.5M1
554    */
 
555  2 toggle public void watchSpace()
556    {
557  2 toggleNotificationsMenu();
558  2 this.watchSpaceLink.click();
559  2 toggleNotificationsMenu();
560    }
561   
562    /**
563    * @since 6.0M1
564    */
 
565  1 toggle public void watchWiki()
566    {
567  1 toggleNotificationsMenu();
568  1 this.watchWikiLink.click();
569  1 toggleNotificationsMenu();
570    }
571   
572    /**
573    * Waits for the javascript libraries and their plugins that need to load before the UI's elements can be used
574    * safely.
575    * <p>
576    * Subclassed should override this method and add additional checks needed by their logic.
577    *
578    * @since 6.2
579    */
 
580  1451 toggle public void waitUntilPageJSIsLoaded()
581    {
582    // Prototype
583  1451 getDriver().waitUntilJavascriptCondition("return window.Prototype != null && window.Prototype.Version != null");
584   
585    // JQuery and dependencies
586    // JQuery dropdown plugin needed for the edit button's dropdown menu.
587  1451 getDriver().waitUntilJavascriptCondition("return window.jQuery != null && window.jQuery().dropdown != null");
588   
589    // Make sure all asynchronous elements have been executed
590  1451 getDriver().waitUntilJavascriptCondition("return !document.getElementsByClassName('xwiki-async').length");
591    }
592   
593    /**
594    * Opens the viewer that lists the children of the current page.
595    *
596    * @return the viewer that lists the child pages
597    * @since 7.3RC1
598    */
 
599  0 toggle public ChildrenViewer viewChildren()
600    {
601  0 toggleActionMenu();
602  0 this.childrenLink.click();
603  0 return new ChildrenViewer();
604    }
605   
606    /**
607    * Says if the notifications menu is present (it is displayed only if it has some content).
608    *
609    * @return either or not the notifications menu is present
610    * @since 7.4M1
611    */
 
612  0 toggle public boolean hasNotificationsMenu()
613    {
614  0 return getDriver().hasElementWithoutWaiting(By.id("tmNotifications"));
615    }
616   
617    /**
618    * Open/Close the notifications menu.
619    *
620    * @since 7.4M1
621    */
 
622  7 toggle public void toggleNotificationsMenu()
623    {
624  7 boolean hasMenu = isNotificationsMenuOpen();
625  7 this.notificationsMenu.click();
626  7 if (hasMenu) {
627  3 getDriver().waitUntilElementDisappears(this.notificationsMenu, By.className("dropdown-menu"));
628    } else {
629  4 getDriver().waitUntilElementIsVisible(this.notificationsMenu, By.className("dropdown-menu"));
630    }
631    }
632   
633    /**
634    * @return true if the notifications menu is open
635    * @since 7.4M1
636    */
 
637  7 toggle public boolean isNotificationsMenuOpen()
638    {
639  7 return this.notificationsMenu.findElement(By.className("dropdown-menu")).isDisplayed();
640    }
641   
642    /**
643    * @return the text of uncaught errors
644    * @since 8.0M1
645    */
 
646  0 toggle public String getErrorContent()
647    {
648  0 return getDriver()
649    .findElementWithoutWaiting(By.xpath("//div[@id = 'mainContentArea']/pre[contains(@class, 'xwikierror')]"))
650    .getText();
651    }
652   
653    /**
654    * @param panelTitle the panel displayed title
655    * @return true if the panel is visible in the left panels or false otherwise
656    * @since 10.6RC1
657    */
 
658  2 toggle public boolean hasLeftPanel(String panelTitle)
659    {
660  2 return getDriver().hasElementWithoutWaiting(By.xpath(
661    "//div[@id = 'leftPanels']/div/h1[@class = 'xwikipaneltitle' and text() = '" + panelTitle +"']"));
662    }
663    }