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 static org.junit.Assert.assertNotNull;
025
026import java.util.List;
027import java.util.concurrent.TimeUnit;
028
029import org.nuxeo.functionaltests.AbstractTest;
030import org.nuxeo.functionaltests.AjaxRequestManager;
031import org.nuxeo.functionaltests.Assert;
032import org.nuxeo.functionaltests.Locator;
033import org.nuxeo.functionaltests.fragment.WebFragment;
034import org.openqa.selenium.By;
035import org.openqa.selenium.NoSuchElementException;
036import org.openqa.selenium.NotFoundException;
037import org.openqa.selenium.WebDriver;
038import org.openqa.selenium.WebElement;
039import org.openqa.selenium.support.FindBy;
040import org.openqa.selenium.support.ui.ExpectedConditions;
041import org.openqa.selenium.support.ui.FluentWait;
042import org.openqa.selenium.support.ui.Select;
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     * Returns the error feedback message.
085     * <p>
086     * If there are more than one error message, always return the last one (not interested by 'Please correct errors'
087     * message).
088     *
089     * @since 5.8
090     */
091    public String getErrorFeedbackMessage() {
092        return getFeedbackMessage("errorFeedback");
093    }
094
095    /**
096     * Returns the info feedback message.
097     * <p>
098     * If there are more than one info message, always return the last one.
099     *
100     * @since 8.3
101     */
102    public String getInfoFeedbackMessage() {
103        return getFeedbackMessage("infoFeedback");
104    }
105
106    protected String getFeedbackMessage(String styleClass) {
107        String ret = "";
108        try {
109            List<WebElement> elements = findElementsWithTimeout(
110                    By.xpath("//div[contains(@class, '" + styleClass + "')]/div[@class='ambiance-title']"));
111            if (elements.size() == 1) {
112                ret = elements.get(0).getText();
113            } else if (elements.size() > 1) {
114                ret = elements.get(elements.size() - 1).getText();
115            }
116        } catch (NoSuchElementException e) {
117            ret = "";
118        }
119        return ret.trim();
120    }
121
122    /**
123     * Gets the top bar navigation sub page.
124     */
125    public HeaderLinksSubPage getHeaderLinks() {
126        assertNotNull(userServicesForm);
127        return asPage(HeaderLinksSubPage.class);
128    }
129
130    /**
131     * Returns the fancy box content web element.
132     *
133     * @since 5.7
134     */
135    public static WebElement getFancyBoxContent() {
136        // make sure the fancybox content is loaded
137        WebElement fancyBox = findElementWithTimeout(By.id("fancybox-content"));
138        FluentWait<WebDriver> wait = Locator.getFluentWait();
139        wait.until(ExpectedConditions.visibilityOf(fancyBox));
140        return fancyBox;
141    }
142
143    /**
144     * Closes current fancy box.
145     *
146     * @since 8.3
147     */
148    public static void closeFancyBox() {
149        AjaxRequestManager arm = new AjaxRequestManager(AbstractTest.driver);
150        arm.begin();
151        findElementWaitUntilEnabledAndClick(By.id("fancybox-close"));
152        arm.end();
153        waitForFancyBoxClosed();
154    }
155
156    /**
157     * Waits for the fancybox to be fully closed.
158     *
159     * @since 8.3
160     */
161    public static void waitForFancyBoxClosed() {
162        // make sure the fancybox content is not loaded anymore
163        FluentWait<WebDriver> wait = Locator.getFluentWait();
164        wait.withTimeout(AbstractTest.AJAX_TIMEOUT_SECONDS, TimeUnit.SECONDS);
165        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("fancybox-overlay")));
166    }
167
168    /**
169     * Finds the first {@link WebElement} using the given method, with a timeout.
170     *
171     * @param by the locating mechanism
172     * @param timeout the timeout in milliseconds
173     * @return the first matching element on the current page, if found
174     * @throws NoSuchElementException when not found
175     */
176    public WebElement findElementWithTimeout(By by, int timeout) throws NoSuchElementException {
177        return Locator.findElementWithTimeout(by, timeout);
178    }
179
180    /**
181     * Finds the first {@link WebElement} using the given method, with a timeout.
182     *
183     * @param by the locating mechanism
184     * @param timeout the timeout in milliseconds
185     * @param parentElement find from the element
186     * @return the first matching element on the current page, if found
187     * @throws NoSuchElementException when not found
188     */
189    public WebElement findElementWithTimeout(By by, int timeout, WebElement parentElement)
190            throws NoSuchElementException {
191        return Locator.findElementWithTimeout(by, timeout, parentElement);
192    }
193
194    /**
195     * Finds the first {@link WebElement} using the given method, with a timeout.
196     *
197     * @param by the locating mechanism
198     * @return the first matching element on the current page, if found
199     * @throws NoSuchElementException when not found
200     */
201    public static WebElement findElementWithTimeout(By by) throws NoSuchElementException {
202        return Locator.findElementWithTimeout(by);
203    }
204
205    /**
206     * Finds webelement list using the given method, with a timeout
207     */
208    public static List<WebElement> findElementsWithTimeout(By by) throws NoSuchElementException {
209        return Locator.findElementsWithTimeout(by);
210    }
211
212    /**
213     * Finds the first {@link WebElement} using the given method, with a timeout.
214     *
215     * @param by the locating mechanism
216     * @param parentElement find from the element
217     * @return the first matching element on the current page, if found
218     * @throws NoSuchElementException when not found
219     */
220    public static WebElement findElementWithTimeout(By by, WebElement parentElement) throws NoSuchElementException {
221        return Locator.findElementWithTimeout(by, parentElement);
222    }
223
224    /**
225     * Waits until an element is enabled, with a default timeout.
226     *
227     * @param element the element
228     */
229    public static void waitUntilEnabled(WebElement element) throws NotFoundException {
230        Locator.waitUntilEnabled(element);
231    }
232
233    /**
234     * Waits until an element is enabled, with a timeout.
235     *
236     * @param element the element
237     * @param waitUntilEnabledTimeout the timeout in milliseconds
238     * @since 8.3
239     */
240    public static void waitUntilEnabled(WebElement element, int waitUntilEnabledTimeout) throws NotFoundException {
241        Locator.waitUntilEnabled(element, waitUntilEnabledTimeout);
242    }
243
244    /**
245     * Waits until an element is enabled, with a default timeout. Then clicks on the element.
246     *
247     * @param element the element
248     * @since 8.3
249     */
250    public static void waitUntilEnabledAndClick(WebElement element) throws NotFoundException {
251        Locator.waitUntilEnabledAndClick(element);
252    }
253
254    /**
255     * Waits until an element is enabled, with a timeout. Then clicks on the element.
256     *
257     * @param element the element
258     * @param waitUntilEnabledTimeout the timeout in milliseconds
259     * @since 8.3
260     */
261
262    public static void waitUntilEnabledAndClick(WebElement element, int waitUntilEnabledTimeout)
263            throws NotFoundException {
264        Locator.waitUntilEnabledAndClick(element, waitUntilEnabledTimeout);
265    }
266
267    /**
268     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
269     * the element is enabled, with a {@code waitUntilEnabledTimeout}.
270     *
271     * @param by the locating mechanism
272     * @param findElementTimeout the find element timeout in milliseconds
273     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
274     * @return the first matching element on the current page, if found
275     * @throws NotFoundException if the element is not found or not enabled
276     */
277    public static WebElement findElementAndWaitUntilEnabled(By by, int findElementTimeout, int waitUntilEnabledTimeout)
278            throws NotFoundException {
279        return Locator.findElementAndWaitUntilEnabled(by, findElementTimeout, waitUntilEnabledTimeout);
280    }
281
282    /**
283     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
284     * is enabled, with the default timeout.
285     *
286     * @param by the locating mechanism
287     * @return the first matching element on the current page, if found
288     * @throws NotFoundException if the element is not found or not enabled
289     */
290    public static WebElement findElementAndWaitUntilEnabled(By by) throws NotFoundException {
291        return Locator.findElementAndWaitUntilEnabled(by);
292    }
293
294    /**
295     * Finds the first {@link WebElement} using the given method, with a {@code findElementTimeout}. Then waits until
296     * the element is enabled, with a {@code waitUntilEnabledTimeout}. Then clicks on the element.
297     *
298     * @param by the locating mechanism
299     * @param findElementTimeout the find element timeout in milliseconds
300     * @param waitUntilEnabledTimeout the wait until enabled timeout in milliseconds
301     * @throws NotFoundException if the element is not found or not enabled
302     * @deprecated since 8.3, use {@link Locator#findElementWaitUntilEnabledAndClick(WebElement, By, int, int)}
303     */
304    @Deprecated
305    public static void findElementWaitUntilEnabledAndClick(By by, int findElementTimeout, int waitUntilEnabledTimeout)
306            throws NotFoundException {
307        Locator.findElementWaitUntilEnabledAndClick(by, findElementTimeout, waitUntilEnabledTimeout);
308    }
309
310    /**
311     * Finds the first {@link WebElement} using the given method, with the default timeout. Then waits until the element
312     * is enabled, with the default timeout. Then clicks on the element.
313     *
314     * @param by the locating mechanism
315     * @throws NotFoundException if the element is not found or not enabled
316     */
317    public static void findElementWaitUntilEnabledAndClick(By by) throws NotFoundException {
318        Locator.findElementWaitUntilEnabledAndClick(by);
319    }
320
321    /**
322     * Finds the first {@link WebElement} using the given method, with the default timeout, inside an optional
323     * {@code parentElement}. Then waits until the element is enabled, with the default timeout. Then clicks on the
324     * element.
325     *
326     * @param parentElement the parent element (can be null)
327     * @param by the locating mechanism
328     * @throws NotFoundException if the element is not found or not enabled
329     * @since 9.1
330     */
331    public static void findElementWaitUntilEnabledAndClick(WebElement parentElement, By by) throws NotFoundException {
332        Locator.findElementWaitUntilEnabledAndClick(parentElement, by);
333    }
334
335    /**
336     * Waits until the URL is different from the one given in parameter, with a timeout.
337     *
338     * @param url the URL to compare to
339     */
340    public void waitUntilURLDifferentFrom(String url) {
341        Locator.waitUntilURLDifferentFrom(url);
342    }
343
344    /**
345     * Selects item in drop down menu.
346     *
347     * @since 5.7
348     */
349    public void selectItemInDropDownMenu(WebElement selector, String optionLabel) {
350        Select select = new Select(selector);
351        select.selectByVisibleText(optionLabel);
352    }
353
354    /**
355     * Switch to given frame id.
356     *
357     * @since 5.7.3
358     */
359    public WebDriver switchToFrame(String id) {
360        driver.switchTo().defaultContent();
361        // you are now outside both frames
362        return driver.switchTo().frame(id);
363    }
364
365    /**
366     * Helper method to adapt tests behaviour when ajaxifying tabs.
367     *
368     * @since 7.10
369     */
370    public boolean useAjaxTabs() {
371        return true;
372    }
373
374    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement) {
375        clickOnTabIfNotSelected(tabPanelId, tabElement, useAjaxTabs());
376    }
377
378    protected void clickOnTabIfNotSelected(String tabPanelId, WebElement tabElement, boolean useAjax) {
379        WebElement selectedTab = findElementWithTimeout(
380                By.xpath("//div[@id='" + tabPanelId + "']//li[@class='selected']//a/span"));
381        if (!selectedTab.equals(tabElement)) {
382            if (useAjax) {
383                AjaxRequestManager arm = new AjaxRequestManager(driver);
384                arm.begin();
385                waitUntilEnabledAndClick(tabElement);
386                arm.end();
387            } else {
388                waitUntilEnabledAndClick(tabElement);
389            }
390        }
391    }
392
393    protected void clickOnTabIfNotSelected(String tabPanelId, String tabElementId) {
394        WebElement tabElement = findElementWithTimeout(
395                By.xpath("//div[@id='" + tabPanelId + "']//a[contains(@id,'" + tabElementId + "')]/span"));
396        clickOnTabIfNotSelected(tabPanelId, tabElement);
397    }
398
399}