Java tutorial
/* ************************************************************************ ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* ************** CENTRE CANADIEN DE DONNES ASTRONOMIQUES ************** * * (c) 2016. (c) 2016. * Government of Canada Gouvernement du Canada * National Research Council Conseil national de recherches * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 * All rights reserved Tous droits rservs * * NRC disclaims any warranties, Le CNRC dnie toute garantie * expressed, implied, or nonce, implicite ou lgale, * statutory, of any kind with de quelque nature que ce * respect to the software, soit, concernant le logiciel, * including without limitation y compris sans restriction * any warranty of merchantability toute garantie de valeur * or fitness for a particular marchande ou de pertinence * purpose. NRC shall not be pour un usage particulier. * liable in any event for any Le CNRC ne pourra en aucun cas * damages, whether direct or tre tenu responsable de tout * indirect, special or general, dommage, direct ou indirect, * consequential or incidental, particulier ou gnral, * arising from the use of the accessoire ou fortuit, rsultant * software. Neither the name de l'utilisation du logiciel. Ni * of the National Research le nom du Conseil National de * Council of Canada nor the Recherches du Canada ni les noms * names of its contributors may de ses participants ne peuvent * be used to endorse or promote tre utiliss pour approuver ou * products derived from this promouvoir les produits drivs * software without specific prior de ce logiciel sans autorisation * written permission. pralable et particulire * par crit. * * This file is part of the Ce fichier fait partie du projet * OpenCADC project. OpenCADC. * * OpenCADC is free software: OpenCADC est un logiciel libre ; * you can redistribute it and/or vous pouvez le redistribuer ou le * modify it under the terms of modifier suivant les termes de * the GNU Affero General Public la GNU Affero General Public * License as published by the License? telle que publie * Free Software Foundation, par la Free Software Foundation * either version 3 of the : soit la version 3 de cette * License, or (at your option) licence, soit ( votre gr) * any later version. toute version ultrieure. * * OpenCADC is distributed in the OpenCADC est distribu * hope that it will be useful, dans lespoir quil vous * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE * without even the implied GARANTIE : sans mme la garantie * warranty of MERCHANTABILITY implicite de COMMERCIALISABILIT * or FITNESS FOR A PARTICULAR ni dADQUATION UN OBJECTIF * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence * General Public License for Gnrale Publique GNU Affero * more details. pour plus de dtails. * * You should have received Vous devriez avoir reu une * a copy of the GNU Affero copie de la Licence Gnrale * General Public License along Publique GNU Affero avec * with OpenCADC. If not, see OpenCADC ; si ce nest * <http://www.gnu.org/licenses/>. pas le cas, consultez : * best ide for debugging gradle projects <http://www.gnu.org/licenses/>. * * ************************************************************************ */ package ca.nrc.cadc; import org.openqa.selenium.*; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.Select; import ca.nrc.cadc.web.selenium.AbstractTestWebPage; import java.util.List; import static org.openqa.selenium.By.xpath; public class UserStorageBrowserPage extends AbstractTestWebPage { private static final String ROOT_FOLDER_NAME = "ROOT"; // Strings for matching against prompt messages and buttons private static final String DELETE_CONFIRMATION_TEXT = "Are you sure you wish to delete the selected items?"; private static final String SUCCESSFUL = "successful"; private static final String ALREADY_EXISTS = "already exists"; private static final String CONFIRMATION_MSG = "New folder added successfully"; private static final String OK = "Ok"; private static final String YES = "Yes"; private static final String CLOSE = "Close"; private static final String SAVE = "Save"; // Define in here what elements are mode indicators // Elements always on the page @FindBy(id = "beacon_filter") private WebElement searchFilter; @FindBy(id = "beacon") private WebElement beaconTable; // element 'Showing x to y of z entries' line @FindBy(id = "beacon_info") private WebElement statusMessage; @FindBy(className = "beacon-progress") private WebElement progressBar; // header displaying name of current folder @FindBy(xpath = "//h2[@property='name']") private WebElement folderNameHeader; @FindBy(xpath = "//*[@id=\"navbar-functions\"]/ul") private WebElement navbarButtonList; @FindBy(xpath = "//*[@id=\"beacon\"]/tbody/tr[1]") private WebElement firstTableRow; // Elements present once user has navigated away from ROOT folder // Toobar buttons @FindBy(id = "level-up") private WebElement leveUpButton; @FindBy(id = "root") private WebElement rootButton; // class has 'disabled' in it for base case. @FindBy(id = "newdropdown") private WebElement newdropdownButton; // element of the list under newdropdown @FindBy(id = "newfolder") private WebElement newFolder; @FindBy(id = "download") private WebElement downloadButton; @FindBy(id = "delete") private WebElement deleteButton; @FindBy(id = "more_details") private WebElement moredetailsButton; // Login Form elements @FindBy(id = "username") private WebElement loginUsername; @FindBy(id = "password") private WebElement loginPassword; @FindBy(id = "submitLogin") private WebElement submitLoginButton; @FindBy(id = "logout") private WebElement logoutButton; private WebDriver driver = null; public UserStorageBrowserPage(final WebDriver driver) throws Exception { super(driver); this.driver = driver; // The beacon-progress bar displays "Transferring Data" while it's loading // the page. Firefox doesn't display whole list until the bar is green, and // that text is gone. Could be this test isn't sufficient but it works // to have intTestFirefox not fail. WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.textToBe(By.className("beacon-progress"), "")); PageFactory.initElements(driver, this); } // Transition functions public void clickButton(String promptText) throws Exception { WebElement button = find(xpath("//button[contains(text(),\"" + promptText + "\")]")); button.click(); } public void clickButtonWithClass(String promptText, String className) throws Exception { WebElement button = find( xpath("//button[contains(@class, '" + className + "') and contains(text(),'" + promptText + "')]")); button.click(); } public void enterSearch(final String searchString) throws Exception { sendKeys(searchFilter, searchString); } public void doLogin(String username, String password) throws Exception { sendKeys(loginUsername, username); sendKeys(loginPassword, password); click(submitLoginButton); waitForElementPresent(By.id("logout")); } public void doLogout() throws Exception { click(logoutButton); } // Folder Related Transition functions public void clickFolder(String folderName) { WebElement folder = (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable( xpath("//*[@id=\"beacon\"]/tbody/tr/td/a[text()[contains(.,'" + folderName + "')]]"))); System.out.println("Folder to be clicked: " + folder.getText()); folder.click(); } public void clickFolderForRow(int rowNum) throws Exception { WebElement firstCheckbox = (new WebDriverWait(driver, 10)).until(ExpectedConditions .elementToBeClickable(xpath("//*[@id=\"beacon\"]/tbody/tr[" + rowNum + "]/td[2]/a"))); click(firstCheckbox); } public int getNextAvailabileFolderRow(int startRow) throws Exception { // not all folders are clickable, go down the rows to find one boolean found = false; int rowNum = startRow; WebElement firstCheckbox = null; while (!found) { // This method throws an exception if the element is not found try { firstCheckbox = beaconTable .findElement(xpath("//*[@id=\"beacon\"]/tbody/tr[" + rowNum + "]/td[2]/a")); } catch (Exception e) { rowNum++; continue; } found = true; } return rowNum; } // CRUD for folders public void createNewFolder(String foldername) throws Exception { newdropdownButton.click(); newFolder.click(); WebElement newfolderInput = (new WebDriverWait(driver, 10)) .until(ExpectedConditions.elementToBeClickable(By.id("fname"))); sendKeys(newfolderInput, foldername); WebElement createFolderButton = find(xpath("//button[contains(text(),\"Create Folder\")]")); createFolderButton.click(); if (isJqiMsgShowing(CONFIRMATION_MSG)) { clickButton(OK); } else { throw new Exception("Could not create folder " + foldername); } } public void deleteFolder(String foldername) throws Exception { if (!isDisabled(deleteButton)) { deleteButton.click(); } // locate folder, select checkbox, select delete button if (isJqiMsgShowing(DELETE_CONFIRMATION_TEXT)) { clickButtonWithClass(YES, "btn-danger"); } else { throw new Exception("Could not delete folder " + foldername); } // confirm folder delete if (isJqiColourMsgShowing(SUCCESSFUL)) { clickButton(CLOSE); } else { throw new Exception("Folder delete not successful: " + foldername); } } public void clickEditIconForRow(int rowNum) throws Exception { WebElement editIcon = find(xpath("//span[contains(@class, 'glyphicon-edit')]")); editIcon.click(); } public String togglePublicAttributeForRow(int rowNum) throws Exception { String currentPermission = ""; WebElement editIcon = find(xpath("//span[contains(@class, 'glyphicon-edit')]")); editIcon.click(); WebElement permissionCheckbox = (new WebDriverWait(driver, 10)) .until(ExpectedConditions.elementToBeClickable(By.id("publicPermission"))); currentPermission = permissionCheckbox.getAttribute("checked"); click(permissionCheckbox); clickButton(SAVE); // confirm folder delete if (isJqiMsgShowing(SUCCESSFUL)) { clickButton(OK); } else { throw new Exception("Permissions editing not successful for row : " + rowNum); } return currentPermission; } /** * Gets row number for next row that has an edit icon after the row passed in. * Using this kind of function instead of a specific row tends to leave the * functions working even when the underlying data changes. * * @param startRow * @return int: row of first edit icon * @throws Exception */ public int getNextAvailableEditIconRow(int startRow) throws Exception { // not all folders have editable data for currently logged in user boolean found = false; int rowNum = startRow; WebElement firstEditIcon = null; while (!found) { // This method throws an exception if the element is not found try { firstEditIcon = beaconTable.findElement(xpath("//*[@id='beacon']/tbody/tr[" + rowNum + "]/td[2]/span[contains(@class, 'glyphicon-edit']")); } catch (Exception e) { rowNum++; continue; } found = true; } return rowNum; } // Checkbox related public void clickCheckboxForRow(int rowNum) throws Exception { WebElement firstCheckbox = (new WebDriverWait(driver, 10)).until(ExpectedConditions .elementToBeClickable(xpath("//*[@id=\"beacon\"]/tbody/tr[" + rowNum + "]/td[1]"))); click(firstCheckbox); } public void clickCheckboxForFolder(String folderName) throws Exception { WebElement folder = find(xpath("//*[@id=\"beacon\"]/tbody/tr/td/a[contains(text()," + folderName + ")]")); WebElement folderParent = folder.findElement(xpath("..")); WebElement folderCheckbox = folderParent.findElement(xpath("//div[contains(@class=\"select-checkbox\")]")); folderCheckbox.click(); } // Navigation functions public void navToRoot() throws Exception { // opting for sendKeys because chromedriver // doesn't work for click() function for some reason. :( rootButton.sendKeys(Keys.ENTER); } public void navUpLevel() throws Exception { click(leveUpButton); } // Inspection functions public WebElement getProgressBar() throws Exception { System.out.println(progressBar.getText()); return progressBar; } int getTableRowCount() throws Exception { List<WebElement> tableRows = beaconTable.findElements(By.tagName("tr")); return tableRows.size(); } boolean verifyFolderName(int rowNum, String expectedValue) throws Exception { List<WebElement> tableRows = beaconTable.findElements(By.tagName("tr")); WebElement selectedRow = tableRows.get(rowNum); WebElement namecolumn = selectedRow.findElement(By.cssSelector("a:nth-of-type(1)")); System.out.println(namecolumn.getText()); return expectedValue.equals(namecolumn.getText()); } boolean verifyFolderSize(int rowNum) throws Exception { List<WebElement> tableRows = beaconTable.findElements(By.tagName("tr")); WebElement selectedRow = tableRows.get(rowNum); List<WebElement> columns = selectedRow.findElements(By.tagName("td")); String sizeString = columns.get(2).getText(); return sizeString != null; } public String getFolderName(int rowNum) throws Exception { List<WebElement> tableRows = beaconTable.findElements(By.tagName("tr")); WebElement selectedRow = tableRows.get(rowNum); WebElement namecolumn = selectedRow.findElement(By.cssSelector("a:nth-of-type(1)")); System.out.println("Foldername to be returned: " + namecolumn.getText()); return namecolumn.getText(); } public String getHeaderText() throws Exception { System.out.println("Header text: " + folderNameHeader.getText()); return folderNameHeader.getText(); } public String getValueForRowCol(int rowNum, int colNum) { String val = ""; try { WebElement el = find(xpath("//*[@id='beacon']/tbody/tr[" + rowNum + "]/td[" + colNum + "]/a")); val = el.getText(); } catch (Exception e) { // element not found, return empty string val = ""; } return val; } boolean isLoggedIn() { try { logoutButton.isDisplayed(); return true; } catch (NoSuchElementException e) { return false; } } private boolean isDisabled(WebElement webEl) { return webEl.getAttribute("class").contains("disabled"); } public boolean isReadAccess() { // need to check class of these buttons, look for 'disabled' in there if (isDisabled(downloadButton) && isDisabled(newdropdownButton) && !isDisabled(searchFilter) && !isDisabled(leveUpButton) && !isDisabled(rootButton)) { return true; } else { return false; } } public boolean isSubFolder(String folderName) throws Exception { // Verify folder name if (!(getHeaderText().contains(folderName))) { return false; } // Check number of elements in button bar if (navbarButtonList.findElements(xpath("//*[@id=\"navbar-functions\"]/ul")).size() == 6) { return true; } // Check state of buttons if (leveUpButton.isDisplayed() && deleteButton.isDisplayed() && rootButton.isDisplayed() && newdropdownButton.isDisplayed() && moredetailsButton.isDisplayed()) { return true; } else { return false; } } public boolean isRootFolder() throws Exception { // Verify folder name if (!(getHeaderText().contains(ROOT_FOLDER_NAME))) { return false; } // navigation buttons are NOT displayed in root // folder. This will change as functionality is added // Currently the navbar only has one child, and it's ID is if (navbarButtonList.findElements(xpath("//*[@id=\"navbar-functions\"]/ul")).size() == 1) { return true; } return false; } public boolean isFileSelectedMode(int rowNumber) { // Class of selected row is different: // visually it will be different, but for now the change // in css class is enough to check //*[@id="beacon"]/tbody/tr[1] WebElement selectedRow = beaconTable.findElement(xpath("//*[@id=\"beacon\"]/tbody/tr[" + rowNumber + "]")); if (!selectedRow.getAttribute("class").contains("selected")) { return false; } // Behaviour is different if person is logged in or not if (isLoggedIn()) { if (!(isDisabled(deleteButton) && isDisabled(downloadButton))) { return true; } } else { // There will need to be a check for publicly available for download or not? if (isDisabled(deleteButton) && !isDisabled(downloadButton)) { return true; } } return false; } public boolean isDefaultSort() { // Name column asc is default sort when page loads WebElement nameColHeader = beaconTable.findElement( xpath("//*[@id=\"beacon_wrapper\"]/div[2]/div/div[1]/div[1]/div/table/thead/tr/th[2]")); if (nameColHeader.getAttribute("class").equals("sorting_asc")) { return true; } return false; } // Impromptu convenience functions public boolean isJqiMsgShowing(String message) { try { WebElement jqiMsg = (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable( xpath("//div[contains(@class, \"jqimessage\") and contains(text(), \"" + message + "\")]"))); return true; } catch (Exception e) { return false; } } public boolean isJqiColourMsgShowing(String message) { try { WebElement jqiMsg = (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable( xpath("//div[contains(@class, 'jqimessage')]/span[contains(text(), '" + message + "')]"))); return true; } catch (Exception e) { return false; } } public boolean isTableEmpty() { boolean isEmpty = false; try { WebElement columnList = find(xpath("//td[contains(@class,'dataTables_empty')]")); isEmpty = true; } catch (Exception e) { isEmpty = false; } return isEmpty; } }