001/*
002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Sun Seng David TAN
018 *     Florent Guillaume
019 *     Antoine Taillefer
020 *     Yannis JULIENNE
021 */
022package org.nuxeo.functionaltests.pages;
023
024import java.util.List;
025import java.util.concurrent.TimeUnit;
026
027import org.nuxeo.functionaltests.AbstractTest;
028import org.nuxeo.functionaltests.AjaxRequestManager;
029import org.nuxeo.functionaltests.Assert;
030import org.nuxeo.functionaltests.Locator;
031import org.nuxeo.functionaltests.fragment.WebFragment;
032import org.openqa.selenium.By;
033import org.openqa.selenium.NoSuchElementException;
034import org.openqa.selenium.NotFoundException;
035import org.openqa.selenium.WebDriver;
036import org.openqa.selenium.WebElement;
037import org.openqa.selenium.support.FindBy;
038import org.openqa.selenium.support.ui.ExpectedConditions;
039import org.openqa.selenium.support.ui.FluentWait;
040import org.openqa.selenium.support.ui.Select;
041
042import static org.junit.Assert.assertNotNull;
043
044/**
045 * Base functions for all pages.
046 */
047public abstract class AbstractPage {
048
049    @FindBy(xpath = "//div[@id='nxw_userMenuActions_panel']/ul/li/span")
050    public WebElement userServicesForm;
051
052    protected WebDriver driver;
053
054    public AbstractPage(WebDriver driver) {
055        this.driver = driver;
056    }
057
058    /**
059     * Returns true if corresponding element is found in the test page.
060     *
061     * @since 5.7
062     */
063    public boolean hasElement(By by) {
064        return Assert.hasElement(by);
065    }
066
067    public <T> T get(String url, Class<T> pageClassToProxy) {
068        return AbstractTest.get(url, pageClassToProxy);
069    }
070
071    public <T> T asPage(Class<T> pageClassToProxy) {
072        return AbstractTest.asPage(pageClassToProxy);
073    }
074
075    public <T extends WebFragment> T getWebFragment(By by, Class<T> webFragmentClass) {
076        return AbstractTest.getWebFragment(by, webFragmentClass);
077    }
078
079    public <T extends WebFragment> T getWebFragment(WebElement element, Class<T> webFragmentClass) {
080        return AbstractTest.getWebFragment(element, webFragmentClass);
081    }
082
083    /**
084     * Gets the info feedback message.
085     *
086     * @return the message if any or an empty string.
087     * @deprecated since 5.8
088     */
089    @Deprecated
090    public String getFeedbackMessage() {
091        String ret;
092        try {
093            ret = findElementWithTimeout(By.xpath("//li[@class=\"errorFeedback\"]")).getText();
094        } catch (NoSuchElementException e) {
095            ret = "";
096        }
097        return ret.trim();
098    }
099
100    /**
101     * Returns the error feedback message.
102     * <p>
103     * If there are more than one error message, always return the last one (not interested by 'Please correct errors'
104     * message).
105     *
106     * @since 5.8
107     */
108    public String getErrorFeedbackMessage() {
109        return getFeedbackMessage("errorFeedback");
110    }
111
112    /**
113     * Returns the info feedback message.
114     * <p>
115     * If there are more than one info message, always return the last one.
116     *
117     * @since 8.3
118     */
119    public String getInfoFeedbackMessage() {
120        return getFeedbackMessage("infoFeedback");
121    }
122
123    protected String getFeedbackMessage(String styleClass) {
124        String ret = "";
125        try {
126            List<WebElement> elements = findElementsWithTimeout(
127                    By.xpath("//div[contains(@class, '" + styleClass + "')]/div[@class='ambiance-title']"));
128            if (elements.size() == 1) {
129                ret = elements.get(0).getText();
130            } else if (elements.size() > 1) {
131                ret = elements.get(elements.size() - 1).getText();
132            }
133        } catch (NoSuchElementException e) {
134            ret = "";
135        }
136        return ret.trim();
137    }
138
139    /**
140     * Gets the top bar navigation sub page.
141     */
142    public HeaderLinksSubPage getHeaderLinks() {
143        assertNotNull(userServicesForm);
144        return asPage(HeaderLinksSubPage.class);
145    }
146
147    /**
148     * Returns the fancy box content web element.
149     *
150     * @since 5.7
151     */
152    public static WebElement getFancyBoxContent() {
153        // make sure the fancybox content is loaded
154        WebElement fancyBox = findElementWithTimeout(By.id("fancybox-content"));
155        FluentWait<WebDriver> wait = Locator.getFluentWait();
156        wait.until(ExpectedConditions.visibilityOf(fancyBox));
157        return fancyBox;
158    }
159
160    /**
161     * Closes current fancy box.
162     *
163     * @since 8.3
164     */
165    public static void closeFancyBox() {
166        AjaxRequestManager arm = new AjaxRequestManager(AbstractTest.driver);
167        arm.begin();
168        findElementWaitUntilEnabledAndClick(By.id("fancybox-close"));
169        arm.end();
170        waitForFancyBoxClosed();
171    }
172
173    /**
174     * Waits for the fancybox to be fully closed.
175     *
176     * @since 8.3
177     */
178    public static void waitForFancyBoxClosed() {
179        // make sure the fancybox content is not loaded anymore
180        FluentWait<WebDriver> wait = Locator.getFluentWait();
181        wait.withTimeout(AbstractTest.AJAX_TIMEOUT_SECONDS, TimeUnit.SECONDS);
182        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("fancybox-overlay")));
183    }
184
185    /**
186     * Finds the first {@link WebElement} using the given method, with a timeout.
187     *
188     * @param by the locating mechanism
189     * @param timeout the timeout in milliseconds
190     * @return the first matching element on the current page, if found
191     * @throws NoSuchElementException when not found
192     */
193    public WebElement findElementWithTimeout(By by, int timeout) throws NoSuchElementException {
194        return Locator.findElementWithTimeout(by, timeout);
195    }
196
197    /**
198     * Finds the first {@link WebElement} using the given method, with a timeout.
199     *
200     * @param by the locating mechanism
201     * @param timeout the timeout in milliseconds
202     * @param parentElement find from the element
203     * @return the first matching element on the current page, if found
204     * @throws NoSuchElementException when not found
205     */
206    public WebElement findElementWithTimeout(By by, int timeout, WebElement parentElement)
207            throws NoSuchElementException {
208        return Locator.findElementWithTimeout(by, timeout, parentElement);
209    }
210
211    /**
212     * Finds the first {@link WebElement} using the given method, with a timeout.
213     *
214     * @param by the locating mechanism
215     * @param timeout the timeout in milliseconds
216     * @return the first matching element on the current page, if found
217     * @throws NoSuchElementException when not found
218     */
219    public static WebElement findElementWithTimeout(By by) throws NoSuchElementException {
220        return Locator.findElementWithTimeout(by);
221    }
222
223    /**
224     * Finds webelement list using the given method, with a timeout
225     */
226    public static List<WebElement> findElementsWithTimeout(By by) throws NoSuchElementException {
227        return Locator.findElementsWithTimeout(by);
228    }
229
230    /**
231     * Finds the first {@link WebElement} using the given method, with a timeout.
232     *
233     * @param by the locating mechanism
234     * @param parentElement find from the element
235     * @return the first matching element on the current page, if found
236     * @throws NoSuchElementException when not found
237     */
238    public static WebElement findElementWithTimeout(By by, WebElement parentElement) throws NoSuchElementException {
239        return Locator.findElementWithTimeout(by, parentElement);
240    }
241
242    /**
243     * Waits until an element is enabled, with a default timeout.
244     *
245     * @param element the element
246     */
247    public static void waitUntilEnabled(WebElement element) throws NotFoundException {
248        Locator.waitUntilEnabled(element);
249    }
250
251    /**
252     * Waits until an element is enabled, with a timeout.
253     *
254     * @param element the element
255     * @param timeout the timeout in milliseconds
256     * @since 8.3
257     */
258    public static void waitUntilEnabled(WebElement element, int waitUntilEnabledTimeout) throws NotFoundException {
259        Locator.waitUntilEnabled(element, waitUntilEnabledTimeout);
260    }
261
262    /**
263     * Waits until an element is enabled, with a default timeout. Then clicks on the element.
264     *
265     * @param element the element
266     * @since 8.3
267     */
268    public static void waitUntilEnabledAndClick(WebElement element) throws NotFoundException {
269        Locator.waitUntilEnabledAndClick(element);
270    }
271
272    /**
273     * Waits until an element is enabled, with a timeout. Then clicks on the element.
274     *
275     * @param element the element
276     * @param timeout the timeout in milliseconds
277     * @since 8.3
278     */
279
280    public static void waitUntilEnabledAndClick(WebElement element, int waitUntilEnabledTimeout)
281            throws NotFoundException {
282        Locator.waitUntilEnabledAndClick(element, waitUntilEnabledTimeout);
283    }
284
285    /**
286     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
287     * the element is enabled, with a {@code waitUntilEnabledTimeout}.
288     *
289     * @param by the locating mechanism
290     * @param findElementTimeout the find element timeout in milliseconds
291     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
292     * @return the first matching element on the current page, if found
293     * @throws NotFoundException if the element is not found or not enabled
294     */
295    public static WebElement findElementAndWaitUntilEnabled(By by, int findElementTimeout, int waitUntilEnabledTimeout)
296            throws NotFoundException {
297        return Locator.findElementAndWaitUntilEnabled(by, findElementTimeout, waitUntilEnabledTimeout);
298    }
299
300    /**
301     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
302     * is enabled, with the default timeout.
303     *
304     * @param by the locating mechanism
305     * @return the first matching element on the current page, if found
306     * @throws NotFoundException if the element is not found or not enabled
307     */
308    public static WebElement findElementAndWaitUntilEnabled(By by) throws NotFoundException {
309        return Locator.findElementAndWaitUntilEnabled(by);
310    }
311
312    /**
313     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
314     * the element is enabled, with a {@code waitUntilEnabledTimeout}. Then clicks on the element.
315     *
316     * @param by the locating mechanism
317     * @param findElementTimeout the find element timeout in milliseconds
318     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
319     * @throws NotFoundException if the element is not found or not enabled
320     * @deprecated since 8.3, use {@link Locator#findElementWaitUntilEnabledAndClick(WebElement, By, int, int)}
321     */
322    @Deprecated
323    public static void findElementWaitUntilEnabledAndClick(By by, int findElementTimeout, int waitUntilEnabledTimeout)
324            throws NotFoundException {
325        Locator.findElementWaitUntilEnabledAndClick(by, findElementTimeout, waitUntilEnabledTimeout);
326    }
327
328    /**
329     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
330     * is enabled, with the default timeout. Then clicks on the element.
331     *
332     * @param by the locating mechanism
333     * @throws NotFoundException if the element is not found or not enabled
334     */
335    public static void findElementWaitUntilEnabledAndClick(By by) throws NotFoundException {
336        Locator.findElementWaitUntilEnabledAndClick(by);
337    }
338
339    /**
340     * Waits until the URL is different from the one given in parameter, with a timeout.
341     *
342     * @param url the URL to compare to
343     */
344    public void waitUntilURLDifferentFrom(String url) {
345        Locator.waitUntilURLDifferentFrom(url);
346    }
347
348    /**
349     * Selects item in drop down menu.
350     *
351     * @since 5.7
352     */
353    public void selectItemInDropDownMenu(WebElement selector, String optionLabel) {
354        Select select = new Select(selector);
355        select.selectByVisibleText(optionLabel);
356    }
357
358    /**
359     * Switch to given frame id.
360     *
361     * @since 5.7.3
362     */
363    public WebDriver switchToFrame(String id) {
364        driver.switchTo().defaultContent();
365        // you are now outside both frames
366        return driver.switchTo().frame(id);
367    }
368
369    /**
370     * Helper method to adapt tests behaviour when ajaxifying tabs.
371     *
372     * @since 7.10
373     */
374    public boolean useAjaxTabs() {
375        return true;
376    }
377
378    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement) {
379        clickOnTabIfNotSelected(tabPanelId, tabElement, useAjaxTabs());
380    }
381
382    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement, boolean useAjax) {
383        WebElement selectedTab = findElementWithTimeout(
384                By.xpath("//div[@id='" + tabPanelId + "']//li[@class='selected']//a/span"));
385        if (!selectedTab.equals(tabElement)) {
386            if (useAjax) {
387                AjaxRequestManager arm = new AjaxRequestManager(driver);
388                arm.begin();
389                waitUntilEnabledAndClick(tabElement);
390                arm.end();
391            } else {
392                waitUntilEnabledAndClick(tabElement);
393            }
394        }
395    }
396
397    protected void clickOnTabIfNotSelected(String tabPanelId, String tabElementId) {
398        WebElement tabElement = findElementWithTimeout(
399                By.xpath("//div[@id='" + tabPanelId + "']//a[contains(@id,'" + tabElementId + "')]/span"));
400        clickOnTabIfNotSelected(tabPanelId, tabElement);
401    }
402
403}