001/*
002 * (C) Copyright 2011 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 <stan@nuxeo.com>
018 *     Antoine Taillefer
019 */
020package org.nuxeo.functionaltests.pages;
021
022import static org.junit.Assert.assertEquals;
023
024import java.util.ArrayList;
025import java.util.List;
026
027import org.apache.commons.lang.StringUtils;
028import org.nuxeo.functionaltests.AjaxRequestManager;
029import org.nuxeo.functionaltests.Locator;
030import org.nuxeo.functionaltests.Required;
031import org.nuxeo.functionaltests.fragment.AddAllToCollectionForm;
032import org.nuxeo.functionaltests.fragment.AddToCollectionForm;
033import org.nuxeo.functionaltests.pages.actions.ContextualActions;
034import org.nuxeo.functionaltests.pages.admincenter.AdminCenterBasePage;
035import org.nuxeo.functionaltests.pages.search.SearchPage;
036import org.nuxeo.functionaltests.pages.tabs.CollectionContentTabSubPage;
037import org.nuxeo.functionaltests.pages.tabs.ContentTabSubPage;
038import org.nuxeo.functionaltests.pages.tabs.EditTabSubPage;
039import org.nuxeo.functionaltests.pages.tabs.HistoryTabSubPage;
040import org.nuxeo.functionaltests.pages.tabs.ManageTabSubPage;
041import org.nuxeo.functionaltests.pages.tabs.PermissionsSubPage;
042import org.nuxeo.functionaltests.pages.tabs.RelationTabSubPage;
043import org.nuxeo.functionaltests.pages.tabs.SummaryTabSubPage;
044import org.nuxeo.functionaltests.pages.tabs.WorkflowTabSubPage;
045import org.nuxeo.functionaltests.pages.tabs.WorkspacesContentTabSubPage;
046import org.openqa.selenium.By;
047import org.openqa.selenium.NoSuchElementException;
048import org.openqa.selenium.StaleElementReferenceException;
049import org.openqa.selenium.WebDriver;
050import org.openqa.selenium.WebElement;
051import org.openqa.selenium.support.FindBy;
052
053import com.google.common.base.Function;
054
055/**
056 * The nuxeo main document base page
057 *
058 * @author Sun Seng David TAN <stan@nuxeo.com>
059 */
060public class DocumentBasePage extends AbstractPage {
061
062    /**
063     * Exception occurred a user is expected to be connected but it isn't.
064     */
065    public class UserNotConnectedException extends Exception {
066        /**
067         *
068         */
069        private static final long serialVersionUID = 1L;
070
071        public UserNotConnectedException(String username) {
072            super("The user " + username + " is expected to be connected but isn't");
073        }
074    }
075
076    @FindBy(xpath = "//form[@id='breadcrumbForm']")
077    public WebElement breadcrumbForm;
078
079    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Content']")
080    public WebElement contentTabLink;
081
082    public ContextualActions contextualActions;
083
084    @FindBy(className = "creator")
085    public WebElement currentDocumentContributor;
086
087    @FindBy(className = "documentDescription")
088    public WebElement currentDocumentDescription;
089
090    @FindBy(xpath = "//form[@id='document_header_layout_form']//h1")
091    public WebElement currentDocumentTitle;
092
093    @FindBy(className = "currentDocumentDescription")
094    public WebElement currentFolderishDescription;
095
096    @FindBy(linkText = "WORKSPACE")
097    public WebElement documentManagementLink;
098
099    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Edit']")
100    public WebElement editTabLink;
101
102    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Permissions']")
103    public WebElement permissionsTabLink;
104
105    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='History']")
106    public WebElement historyTabLink;
107
108    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Manage']")
109    public WebElement manageTabLink;
110
111    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Relations']")
112    public WebElement relationTabLink;
113
114    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Summary']")
115    public WebElement summaryTabLink;
116
117    @Required
118    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']")
119    public WebElement tabsBar;
120
121    @FindBy(xpath = "//div[@id='nxw_documentTabs_panel']//a/span[text()='Workflow']")
122    public WebElement workflowLink;
123
124    @Required
125    @FindBy(id = "nxw_userMenuActions_panel")
126    public WebElement userMenuActions;
127
128    @Required
129    @FindBy(linkText = "HOME")
130    public WebElement homePageLink;
131
132    @Required
133    @FindBy(linkText = "SEARCH")
134    public WebElement searchPageLink;
135
136    public DocumentBasePage(WebDriver driver) {
137        super(driver);
138    }
139
140    /**
141     * Check if the title of the current document page is equal to the {@code expectedTitle}.
142     *
143     * @param expectedTitle the expected title
144     */
145    public void checkDocTitle(String expectedTitle) {
146        assertEquals(expectedTitle, getCurrentDocumentTitle());
147    }
148
149    /**
150     * Check if the user is connected by looking for an element with the {@code username} as a class.
151     *
152     * @param username
153     * @throws UserNotConnectedException
154     */
155    public void checkUserConnected(String username) throws UserNotConnectedException {
156        try {
157            findElementWithTimeout(By.cssSelector("span." + username));
158        } catch (NoSuchElementException e) {
159            throw new UserNotConnectedException(username);
160        }
161    }
162
163    /**
164     * @since 7.10
165     */
166    public void clickOnDocumentTabLink(WebElement tabLink) {
167        clickOnDocumentTabLink(tabLink, useAjaxTabs());
168    }
169
170    /**
171     * Clicks on given tab element, detecting begin and end of potential ajax request.
172     *
173     * @since 8.1
174     */
175    public void clickOnDocumentTabLink(WebElement tabLink, boolean useAjax) {
176        clickOnTabIfNotSelected("nxw_documentTabs_panel", tabLink, useAjax);
177    }
178
179    public AdminCenterBasePage getAdminCenter() {
180        findElementWithTimeout(By.linkText("ADMIN")).click();
181        return asPage(AdminCenterBasePage.class);
182    }
183
184    /**
185     * Click on the content tab and return the subpage of this page.
186     */
187    public ContentTabSubPage getContentTab() {
188        return getContentTab(ContentTabSubPage.class);
189    }
190
191    public <T extends ContentTabSubPage> T getContentTab(Class<T> tabClass) {
192        clickOnDocumentTabLink(contentTabLink);
193        return asPage(tabClass);
194    }
195
196    public CollectionContentTabSubPage getCollectionContentTab() {
197        return getContentTab(CollectionContentTabSubPage.class);
198    }
199
200    public ContextualActions getContextualActions() {
201        return asPage(ContextualActions.class);
202    }
203
204    /**
205     * @since 7.3
206     */
207    public List<WebElement> getBlobActions(int index) {
208        return findElementsWithTimeout(By.xpath("(//div[@class='actionsColumn'])[" + (index + 1) + "]//a"));
209    }
210
211    public String getCurrentContributors() {
212        return currentDocumentContributor.getText();
213    }
214
215    public String getCurrentDocumentDescription() {
216        return currentDocumentDescription.getText();
217    }
218
219    public String getCurrentDocumentTitle() {
220        return currentDocumentTitle.getText();
221    }
222
223    public String getCurrentFolderishDescription() {
224        return currentFolderishDescription.getText();
225    }
226
227    public List<String> getCurrentStates() {
228        List<WebElement> states = findElementsWithTimeout(By.className("sticker"));
229        List<String> stateLabels = new ArrayList<String>();
230        for (WebElement state : states) {
231            stateLabels.add(state.getText());
232        }
233        return stateLabels;
234    }
235
236    /**
237     * @deprecated since 7.3: use {@link #goToWorkspaces()} instead
238     */
239    public DocumentBasePage getDocumentManagement() {
240        return goToWorkspaces();
241    }
242
243    public EditTabSubPage getEditTab() {
244        clickOnDocumentTabLink(editTabLink);
245        return asPage(EditTabSubPage.class);
246    }
247
248    public PermissionsSubPage getPermissionsTab() {
249        // not ajaxified
250        clickOnDocumentTabLink(permissionsTabLink, false);
251        return asPage(PermissionsSubPage.class);
252    }
253
254    public HistoryTabSubPage getHistoryTab() {
255        clickOnDocumentTabLink(historyTabLink);
256        return asPage(HistoryTabSubPage.class);
257    }
258
259    public ManageTabSubPage getManageTab() {
260        clickOnDocumentTabLink(manageTabLink);
261        return asPage(ManageTabSubPage.class);
262    }
263
264    public NavigationSubPage getNavigationSubPage() {
265        return asPage(NavigationSubPage.class);
266    }
267
268    public RelationTabSubPage getRelationTab() {
269        clickOnDocumentTabLink(relationTabLink);
270        return asPage(RelationTabSubPage.class);
271    }
272
273    public SummaryTabSubPage getSummaryTab() {
274        clickOnDocumentTabLink(summaryTabLink);
275        return asPage(SummaryTabSubPage.class);
276    }
277
278    /**
279     * @since 5.7
280     */
281    public UserHomePage getUserHome() {
282        findElementWithTimeout(By.linkText("HOME")).click();
283        UserHomePage page = asPage(UserHomePage.class);
284        // make sure we're back on the dashboard tab
285        return page.goToDashboard();
286    }
287
288    public WorkflowTabSubPage getWorkflow() {
289        clickOnDocumentTabLink(workflowLink);
290        return asPage(WorkflowTabSubPage.class);
291    }
292
293    /**
294     * For workspace type, the content tab is a bit different.
295     */
296    public WorkspacesContentTabSubPage getWorkspacesContentTab() {
297        clickOnDocumentTabLink(contentTabLink);
298        return asPage(WorkspacesContentTabSubPage.class);
299    }
300
301    public DocumentBasePage goToDocumentByBreadcrumb(String documentTitle) {
302        breadcrumbForm.findElement(By.linkText(documentTitle)).click();
303        return asPage(DocumentBasePage.class);
304    }
305
306    private static final String ADD_TO_COLLECTION_UPPER_ACTION_ID = "nxw_addToCollectionAction_form:nxw_documentActionsUpperButtons_addToCollectionAction_subview:nxw_documentActionsUpperButtons_addToCollectionAction_link";
307
308    private static final String ADD_ALL_TO_COLLECTION_ACTION_ID = "document_content_buttons:nxw_addSelectedToCollectionAction_form:nxw_cvButton_addSelectedToCollectionAction_subview:nxw_cvButton_addSelectedToCollectionAction_link";
309
310    @FindBy(id = ADD_TO_COLLECTION_UPPER_ACTION_ID)
311    private WebElement addToCollectionUpperAction;
312
313    @FindBy(id = ADD_ALL_TO_COLLECTION_ACTION_ID)
314    private WebElement addAllToCollectionAction;
315
316    /**
317     * @since 5.9.3
318     */
319    public AddToCollectionForm getAddToCollectionPopup() {
320        AjaxRequestManager arm = new AjaxRequestManager(driver);
321        arm.begin();
322        addToCollectionUpperAction.click();
323        arm.end();
324        Locator.waitUntilElementPresent(By.id("fancybox-content"));
325        return getWebFragment(By.id("fancybox-content"), AddToCollectionForm.class);
326    }
327
328    /**
329     * @since 5.9.3
330     */
331    public AddAllToCollectionForm getAddAllToCollectionPopup() {
332        Locator.waitUntilGivenFunctionIgnoring(new Function<WebDriver, Boolean>() {
333            @Override
334            public Boolean apply(WebDriver driver) {
335                return StringUtils.isBlank(driver.findElement(By.id(ADD_ALL_TO_COLLECTION_ACTION_ID)).getAttribute(
336                        "disabled"));
337            }
338        }, StaleElementReferenceException.class);
339        AjaxRequestManager arm = new AjaxRequestManager(driver);
340        arm.begin();
341        driver.findElement(By.id(ADD_ALL_TO_COLLECTION_ACTION_ID)).click();
342        arm.end();
343        Locator.waitUntilElementPresent(By.id("fancybox-content"));
344        return getWebFragment(By.id("fancybox-content"), AddAllToCollectionForm.class);
345    }
346
347    public boolean isAddToCollectionUpperActionAvailable() {
348        try {
349            driver.findElement(By.id(ADD_TO_COLLECTION_UPPER_ACTION_ID));
350            return true;
351        } catch (final NoSuchElementException e) {
352            return false;
353        }
354    }
355
356    /**
357     * @since 5.9.3
358     */
359    public void popupUserMenuActions() {
360        userMenuActions.findElement(By.id("nxw_userMenuActions_dropDownMenu")).click();
361        Locator.waitUntilGivenFunctionIgnoring(new Function<WebDriver, Boolean>() {
362            @Override
363            public Boolean apply(WebDriver driver) {
364                return !userMenuActions.findElement(By.xpath("//ul[@class='actionSubList']"))
365                                       .getAttribute("style")
366                                       .equals("display: none;");
367            }
368        }, StaleElementReferenceException.class);
369    }
370
371    /**
372     * @since 5.9.3
373     */
374    public DocumentBasePage switchToPersonalWorkspace() {
375        popupUserMenuActions();
376        driver.findElement(By.linkText("Personal Workspace")).click();
377        return asPage(DocumentBasePage.class);
378    }
379
380    /**
381     * @since 5.9.3
382     */
383    public DocumentBasePage switchToDocumentBase() {
384        popupUserMenuActions();
385        driver.findElement(By.linkText("Back to Document Base")).click();
386        return asPage(DocumentBasePage.class);
387    }
388
389    /**
390     * @since 5.9.3
391     */
392    public HomePage goToHomePage() {
393        homePageLink.click();
394        return asPage(HomePage.class);
395    }
396
397    /**
398     * @since 6.0
399     */
400    public SearchPage goToSearchPage() {
401        searchPageLink.click();
402        return asPage(SearchPage.class);
403    }
404
405    /**
406     * @since 7.3
407     */
408    public DocumentBasePage goToWorkspaces() {
409        documentManagementLink.click();
410        return asPage(DocumentBasePage.class);
411    }
412
413    /**
414     * Returns true if given element representing a main tab is selected in UI.
415     *
416     * @since 7.3
417     */
418    public boolean isMainTabSelected(WebElement tab) {
419        WebElement elt = Locator.findParentTag(tab, "li");
420        String css = elt.getAttribute("class");
421        if (css != null && css.contains("selected")) {
422            return true;
423        }
424        return false;
425    }
426
427}