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    public static void waitUntilEnabledAndClick(WebElement element, int waitUntilEnabledTimeout)
280            throws NotFoundException {
281        Locator.waitUntilEnabledAndClick(element, waitUntilEnabledTimeout);
282    }
283
284    /**
285     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
286     * the element is enabled, with a {@code waitUntilEnabledTimeout}.
287     *
288     * @param by the locating mechanism
289     * @param findElementTimeout the find element timeout in milliseconds
290     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
291     * @return the first matching element on the current page, if found
292     * @throws NotFoundException if the element is not found or not enabled
293     */
294    public static WebElement findElementAndWaitUntilEnabled(By by, int findElementTimeout, int waitUntilEnabledTimeout)
295            throws NotFoundException {
296        return Locator.findElementAndWaitUntilEnabled(by, findElementTimeout, waitUntilEnabledTimeout);
297    }
298
299    /**
300     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
301     * is enabled, with the default timeout.
302     *
303     * @param by the locating mechanism
304     * @return the first matching element on the current page, if found
305     * @throws NotFoundException if the element is not found or not enabled
306     */
307    public static WebElement findElementAndWaitUntilEnabled(By by) throws NotFoundException {
308        return Locator.findElementAndWaitUntilEnabled(by);
309    }
310
311    /**
312     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
313     * the element is enabled, with a {@code waitUntilEnabledTimeout}. Then clicks on the element.
314     *
315     * @param by the locating mechanism
316     * @param findElementTimeout the find element timeout in milliseconds
317     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
318     * @throws NotFoundException if the element is not found or not enabled
319     * @deprecated since 8.3, use {@link Locator#findElementWaitUntilEnabledAndClick(WebElement, By, int, int)}
320     */
321    @Deprecated
322    public static void findElementWaitUntilEnabledAndClick(By by, int findElementTimeout, int waitUntilEnabledTimeout)
323            throws NotFoundException {
324        Locator.findElementWaitUntilEnabledAndClick(by, findElementTimeout, waitUntilEnabledTimeout);
325    }
326
327    /**
328     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
329     * is enabled, with the default timeout. Then clicks on the element.
330     *
331     * @param by the locating mechanism
332     * @throws NotFoundException if the element is not found or not enabled
333     */
334    public static void findElementWaitUntilEnabledAndClick(By by) throws NotFoundException {
335        Locator.findElementWaitUntilEnabledAndClick(by);
336    }
337
338    /**
339     * Waits until the URL is different from the one given in parameter, with a timeout.
340     *
341     * @param url the URL to compare to
342     */
343    public void waitUntilURLDifferentFrom(String url) {
344        Locator.waitUntilURLDifferentFrom(url);
345    }
346
347    /**
348     * Selects item in drop down menu.
349     *
350     * @since 5.7
351     */
352    public void selectItemInDropDownMenu(WebElement selector, String optionLabel) {
353        Select select = new Select(selector);
354        select.selectByVisibleText(optionLabel);
355    }
356
357    /**
358     * Switch to given frame id.
359     *
360     * @since 5.7.3
361     */
362    public WebDriver switchToFrame(String id) {
363        driver.switchTo().defaultContent();
364        // you are now outside both frames
365        return driver.switchTo().frame(id);
366    }
367
368    /**
369     * Helper method to adapt tests behaviour when ajaxifying tabs.
370     *
371     * @since 7.10
372     */
373    public boolean useAjaxTabs() {
374        return true;
375    }
376
377    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement) {
378        clickOnTabIfNotSelected(tabPanelId, tabElement, useAjaxTabs());
379    }
380
381    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement, boolean useAjax) {
382        WebElement selectedTab = findElementWithTimeout(
383                By.xpath("//div[@id='" + tabPanelId + "']//li[@class='selected']//a/span"));
384        if (!selectedTab.equals(tabElement)) {
385            if (useAjax) {
386                AjaxRequestManager arm = new AjaxRequestManager(driver);
387                arm.begin();
388                waitUntilEnabledAndClick(tabElement);
389                arm.end();
390            } else {
391                waitUntilEnabledAndClick(tabElement);
392            }
393        }
394    }
395
396    protected void clickOnTabIfNotSelected(String tabPanelId, String tabElementId) {
397        WebElement tabElement = findElementWithTimeout(
398                By.xpath("//div[@id='" + tabPanelId + "']//a[contains(@id,'" + tabElementId + "')]/span"));
399        clickOnTabIfNotSelected(tabPanelId, tabElement);
400    }
401
402}