Test Analysis

package sailpoint.qa.austin.modeledpages.classic; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.PageFactory; import org.testng.Assert; import sailpoint.qa.austin.listeners.RetryAnalyzer; import sailpoint.qa.austin.modeledpages.ModeledPageBase; import sailpoint.qa.austin.modeledpages.classic.auth.MFAProviderSelectAndAuthPage; import sailpoint.qa.austin.tests.TestBase; import sailpoint.qa.austin.utilities.Util; import sailpoint.qa.austin.utilities.WaitUtil; import java.util.ArrayList; /** * @author sean.graham */ /** * This is the Selenium modeled class for the Login page */ public class LoginPage extends ModeledPageBase { /** * Elements on page */ private static String accountIDXpath = "loginForm:accountId"; private String passwordXpath = "loginForm:password"; private String loginXpath = "loginForm:loginButton"; private String forgotPasswordLinkXpath = "forgotPassButtonLink"; private String unlockAccountButtonLinkXpath = "unlockAccountButtonLink"; private String loginErrorMessageXpath = "loginForm:loginErrors"; private String passwordExpiredErrorMessageXpath = "//div[contains(@class,'text-danger')]/ul/li"; public String newUserRegistrationLinkXpath = "registrationLinkLink"; private String lockedAccountErrorMessageXpath = "//*[contains(text(), 'Your identity has been locked. Try again after some time or consult your system administrator.')]"; private String errorMessageXpath = "//div[contains(@class, 'text-danger')]//*[contains(text(), '%s')]"; private String urlInputXpath = "//input[@name='inputurl']"; private String loadButtonXpath = "//*[@value='Load']"; private String errorListXpath = "//*[@id=\"expiredForm\"]/section/div/div[6]"; // Reset Password elements private String currentPasswordFieldXpath = "expiredForm:currentPassword"; private String newPasswordFieldXpath = "expiredForm:newPassword"; private String confirmPasswordFieldXpath = "expiredForm:confirmPassword"; private String expiredPasswordChangeButtonXpath = "expiredForm:changeButton"; private String expiredPasswordCancelButtonXpath = "expiredForm:cancelButton"; private String registrationFormHeaderXpath = "//*[contains(text(), 'Self-service Registration Form')]"; public static final String loginPageUrl = "/login.jsf"; public static final String expiredPageUrl = "/expiredPassword.jsf"; // Login error messages public static final String invalidUserPassError = "Invalid username or password"; public static final String identityLockedError = "Your identity has been locked"; public static final String identityExpiredError = "Your IdentityIQ password has expired and must be changed."; public static final String identityConfirmDoesntMatchError = "The password and confirmation password do not match."; public static final String invalidCurrentPassError = "You have entered an invalid current password."; // Home page visibility indicator private String homePageVisibleTitle = "//h1[contains(@class, 'ng-binding')]"; private String formTextXpath = "//div[@class='panel-body']"; private String usernameErrorId = "loginForm:usernameErrors"; public static enum LoginErrorTypes { INVALID, LOCKED, EXPIRED, CONFIRM_DOESNT_MATCH, INVALID_CURRENT_PWD } /** * Constructor */ public LoginPage(WebDriver d) { driver = d; } public static LoginPage initPage(WebDriver driver) { LoginPage result; result = PageFactory.initElements(driver, LoginPage.class); return result; } /** * Open a login page using the "?prompt=true" suffix. This method * is used for "normal" logins to the application. * @param baseURL the application base URL * @param driver the WebDriver * @return and instance of the LoginPage class */ public static LoginPage openPage(String baseURL, WebDriver driver) { return openUrl(driver, baseURL + loginPageUrl + "?prompt=true"); } /** * Open a login page without using the "?prompt=true" suffix. This method * is used for SSO logins. * @param baseURL the application base URL * @param driver the WebDriver * @return and instance of the LoginPage class */ public static LoginPage openPageSSOEnabled(String baseURL, WebDriver driver) { return openUrl(driver, baseURL + loginPageUrl); } /** * Verify is the username error is present and get the text of the error message */ public String getUsernameError() throws Exception { Util.isElementPresent(driver,usernameErrorId); return Util.getElementText(driver, usernameErrorId); } /** * Opens a "deep link" login page. * @param destUrl the URL of the "deep link" page * @param driver the Webdriver * @return and instance of the LoginPage class */ public static LoginPage openPageDeepLink(String destUrl, WebDriver driver) { LoginPage loginPage = openUrl(driver, destUrl); try { WaitUtil.waitUntilCurrentURLIs(driver, "login.jsf", 10); } catch(TimeoutException te) { // Set loginPage again if timeout occurs loginPage = openUrl(driver, destUrl); WaitUtil.waitUntilCurrentURLIs(driver, "login.jsf", 10); } return loginPage; } /** * Perform a valid login. Expect to land on the Home page * @param id the user id * @param pwd the password */ public void doLogin(String id, String pwd) { Util.profileStart("LoginPage.doLogin()"); login(id, pwd); // Wait for the Home page visible title to be displayed and translated - KEEP // Until this is visible, the page is transient and menubar items can shift location. try { WaitUtil.waitForElementPresentAndVisible(driver, homePageVisibleTitle, 60); } catch(TimeoutException te) { // If the login times out getting to the Home page, let's retry the test, // because 60 seconds ought to be enough time to see the home page. // TODO: maybe remove this at some point? RetryAnalyzer.retryTestDueToLoginTimeout(); throw te; } Util.profileStop("LoginPage.doLogin()"); } /** * Perform a MFA login. Expect to land on the MFA page * @param id the user id * @param pwd the password * @param isWithMfaDuo is with choosing auth provider MFA DUO */ public void doMFALogin(String id, String pwd, boolean isWithMfaDuo) { login(id, pwd); if (isWithMfaDuo) { doMFALoginWithDUOPush(); // occasionally there is a delay on UI after removing MFA configs with looping to login page int loginAttempts = 10; while(!new HomePage(driver).isHomePageDisplayed()) { login(id, pwd); loginAttempts --; if(loginAttempts == 0) { throw new AssertionError(id + " was not logged"); } } } } public void doMFALogin(String id, String password) { doMFALogin(id, password, false); } public void doMFALogin(String id, String password, String expectedTitle){ login(id, password); doMFALoginWithDUOPush(); WaitUtil.waitForTitleToContain(driver, expectedTitle, 10); } /** * Do MFA login using DUO Push */ private void doMFALoginWithDUOPush(){ MFAProviderSelectAndAuthPage mfaProviderSelectAndAuthPage = new MFAProviderSelectAndAuthPage(driver); if(mfaProviderSelectAndAuthPage.isProviderPageOpened()) { mfaProviderSelectAndAuthPage.selectDuoRadioButton(); mfaProviderSelectAndAuthPage.clickMfaSubmit(); } if(mfaProviderSelectAndAuthPage.isAuthPageOpened()) { mfaProviderSelectAndAuthPage.enterMultiFactorAuthSelections("DUO Push"); } } /** * Perform a deepLink login which can land on any page. Wait for the expected page header string. * @param id the user id * @param pwd the password * @param expectedHeader the expected header string on the resulting page */ public void doDeepLinkLogin(String id, String pwd, String expectedHeader) { login(id, pwd); driver.get(driver.getCurrentUrl().replace("http://", "http://" + id + ":" + pwd + "@")); // Let's make sure we landed on the correct page WaitUtil.waitForTitleToContain(driver, expectedHeader, 30); } /** * Wait for the "Invalid username or password" message to appear on the login screen */ public void waitForInvalidUsernameOrPasswordLoginFailure() { WaitUtil.waitForElementPresentAndVisible(driver, "loginForm:loginErrors", 5); } /** * Wait for the "Password is required" message to appear on the login screen */ public void waitForPasswordIsRequiredLoginFailure() { WaitUtil.waitForElementPresentAndVisible(driver, "loginForm:passwordErrors", 5); } /** * Perform a failure login. * @param id the user id * @param pwd the password */ public void doInvalidLoginAndAssert(String id, String pwd) { login(id, pwd); // Assert the login page is still displayed and not some other page // If we're on the wrong URL, print it out so we can see it. String currentUrl = Util.getCurrentUrl(driver); if(!currentUrl.contains(loginPageUrl)) { System.out.println("URL should contain '" + loginPageUrl + "' but does not: " + currentUrl); Assert.fail("Did not stay at the login page after login failed"); } // Wait for login error message element to be displayed WaitUtil.waitForElementPresentAndVisible(driver, loginErrorMessageXpath, 5); } /** * Perform failure during login because of expiration of password * @param id identity name * @param pwd correct passwod */ public void doInvalidLoginAndAssertPwdExpired(String id, String pwd) { login(id, pwd); // Assert the expired password page is displayed and not some other page String currentUrl = Util.getCurrentUrl(driver); if(!currentUrl.contains(expiredPageUrl)) { System.out.println("URL should contain '" + expiredPageUrl + "' but does not: " + currentUrl); Assert.fail("Did not stay at the expired pwd page after login failed"); } // Wait for login error message element to be displayed WaitUtil.waitForElementPresentAndVisible(driver, passwordExpiredErrorMessageXpath, 5); } /** * Click the "Forgot Password" link on the login screen. * This link will only appear if an application for pass-through auth has been set. * @param id the user id */ public void clickForgotPasswordLink(String id) { Util.setInputFieldToValue(driver, accountIDXpath, id); Util.click(driver, forgotPasswordLinkXpath); } /** * Click the "Unlock Account" link on the login screen. * This link will only appear if an application for pass-through auth has been set * and account unlock option is checked. * @param id the user id */ public void clickUnlockAccountLink(String id) { Util.setInputFieldToValue(driver, accountIDXpath, id); Util.click(driver, unlockAccountButtonLinkXpath); } /** * Verify expected login error message * * @param user User name * @param pass Password * @param error Expected login error type * @return boolean true if the actual error message matches the expected error message, else false */ public boolean verifyLoginErrorMessage(String user, String pass, LoginErrorTypes error) { doInvalidLoginAndAssert(user, pass); return isErrorMessageContains(error); } /** * Identify whether error message contains error text or not * @param error type of excepted error * @return */ public boolean isErrorMessageContains(LoginErrorTypes error){ switch (error) { case INVALID: return Util.getElementText(driver, loginErrorMessageXpath).contains(invalidUserPassError); case LOCKED: return Util.getElementText(driver, loginErrorMessageXpath).contains(identityLockedError); case EXPIRED: return Util.getElementText(driver, passwordExpiredErrorMessageXpath).contains(identityExpiredError); case CONFIRM_DOESNT_MATCH: return Util.getElementText(driver, passwordExpiredErrorMessageXpath).contains(identityConfirmDoesntMatchError); case INVALID_CURRENT_PWD: return Util.getElementText(driver, passwordExpiredErrorMessageXpath).contains(invalidCurrentPassError); default: return false; } } /** * Update expired system password on login * * @param id user ID * @param pwd expired user password * @param newPass new user password * @param confirmPass confirm new user password * @throws Exception if a exception is thrown */ public void updateExpiredPasswordOnLogin(String id, String pwd, String newPass, String confirmPass) throws Exception { login(id, pwd); // Complete the expired password change process if(Util.isElementDisplayed(driver, currentPasswordFieldXpath)) completeExpiredPassword(pwd, newPass, confirmPass); else completeExpiredPassword(newPass, confirmPass); } /** * Complete the Expired password change process when the Current Password field is not present. * @param newPass new user password * @param confirmPass confirm new user password */ public void completeExpiredPassword(String newPass, String confirmPass) { Util.setInputFieldToValue(driver, newPasswordFieldXpath, newPass); Util.setInputFieldToValue(driver, confirmPasswordFieldXpath, confirmPass); Util.click(driver, expiredPasswordChangeButtonXpath); } /** * Complete the Expired password change process when Current Password field is present. * @param currPass * @param newPass * @param confirmPass */ public void completeExpiredPassword(String currPass, String newPass, String confirmPass) { Util.setInputFieldToValue(driver, currentPasswordFieldXpath, currPass); Util.setInputFieldToValue(driver, newPasswordFieldXpath, newPass); Util.setInputFieldToValue(driver, confirmPasswordFieldXpath, confirmPass); Util.click(driver, expiredPasswordChangeButtonXpath); } /** * Click on the new user registration link * @throws Exception if a exception is thrown */ public void clickNewUserRegistration() throws Exception { // Sometimes the login screen is in transition, where the "New User Registration" // is visible but is not clickable when we try to click it. So, let's wait. WaitUtil.waitForElementToBeClickable(driver, newUserRegistrationLinkXpath, 10); // KEEP Util.click(driver, newUserRegistrationLinkXpath); } /** * Try to log in using an account that has been locked. * @param id the userId * @param pwd the password */ public void loginLockedAccount(String id, String pwd) { login(id, pwd); WaitUtil.waitForElementPresentAndVisible(driver, lockedAccountErrorMessageXpath, 10); } //*********************************************************************** //* Private helper methods //*********************************************************************** /** * Private helper method to do a "standard" login - type in in a userId, * password, and then click the login button. * @param id the userId * @param pwd the password */ private void login(String id, String pwd) { Util.setInputFieldToValue(driver, accountIDXpath, id); Util.setInputFieldToValue(driver, passwordXpath, pwd); Util.click(driver, loginXpath); } /** * Private helper method to open a URL (typically a login URL) and return * an instance of the LoginPage class. * @param driver the WebDriver * @param destUrl the destination URL to open * @return an instance of the LoginPage class */ public static LoginPage openUrl(WebDriver driver, String destUrl) { Util.profileStart("LoginPage.openUrl()"); // We need to make sure the login screen gets refreshed to make sure things like // forgot password or unlock account show up once those settings have been made in the app. TestBase.gotoURL(driver, destUrl); Util.profileStop("LoginPage.openUrl()"); return PageFactory.initElements(driver, LoginPage.class); } /** * Get the xpath of the Username field on the login screen. * @return */ public static String getUserNameXpath() { return accountIDXpath; } /** * Get text from form which is displayed on page * @return */ public String getFormText() { return Util.getElementText(driver, formTextXpath); } /** * Perform a failure login. * @param id - the user id * @param pwd - the password * @param errorMessage - message of Error that's expected to be seen * @throws Exception if a exception is thrown */ public void doInvalidLoginAssertError(String id, String pwd, String errorMessage) throws Exception { login(id, pwd); // Assert the login page is still displayed and not some other page // If we're on the wrong URL, print it out so we can see it. String currentUrl = Util.getCurrentUrl(driver); if(!currentUrl.contains(loginPageUrl)) { System.out.println("URL should contain '" + loginPageUrl + "' but does not: " + currentUrl); Assert.fail("Did not stay at the login page after login failed"); } // Wait for login error message element to be displayed WaitUtil.waitForElementPresentAndVisible(driver, String.format("//span[contains(text(), '%s')]", errorMessage), 5); } /** * Try invalid login to account until account is locked * @param userName to log in * @param invalidPassword password to log in * @param maxAttempts count of attempts to log in */ public void doLoginUntilLocked(String userName, String invalidPassword, int maxAttempts) { int loginRetry = 0; boolean identityUnlocked = true; while(identityUnlocked) { if (verifyLoginErrorMessage(userName, invalidPassword, LoginErrorTypes.LOCKED)) identityUnlocked = false; else { loginRetry++; } // Adding assert to prevent a loop in case of an unexpected system config error Assert.assertFalse((loginRetry == maxAttempts), "Exceeded expected max login attempts."); } } /** * Assert that expected error message is present on the page * @param errorText - text of error expected to be displayed */ public void assertErrorMessagePresence(String errorText) { Assert.assertTrue(Util.isElementPresent(driver, String.format(errorMessageXpath, errorText)), "Error message [" + errorText + "] is not present on the login page"); } /** * Verify if the error message is in the list of errors * @param errorList - list of error expected to be displayed */ public void verifyErrorMessagesList (ArrayList errorList) throws Exception { if (errorList.size() > 0) { ArrayList policyConstraints = Util.getElementTextAsList(driver, errorListXpath); for (String s : errorList) { Assert.assertTrue(policyConstraints.contains(s), "Expected constraint [" + s + "] was not present in the list."); } } } /** * Do a simple Login in the app * @param id - user id * @param pwd - user password */ public void simpleLogin(String id, String pwd) { Util.setInputFieldToValue(driver, accountIDXpath, id); Util.setInputFieldToValue(driver, passwordXpath, pwd); Util.click(driver, loginXpath); } /** * Click the cancel button in expired password page * */ public void clickExpiredPasswordCancelButton() throws Exception { Util.click(driver, expiredPasswordCancelButtonXpath); } /** * Assert that the forgot password button is displayed * */ public boolean isForgotPasswordLinkDisplayed() { return Util.isElementDisplayed(driver, forgotPasswordLinkXpath); } /** * Verify username field is selected */ public void verifyLoginInputFieldIsEnabled() { Assert.assertTrue(Util.isElementEnabled(driver, accountIDXpath), "Username field is not selected"); } /** * Verify password field is selected */ public void verifyPasswordInputFieldIsEnabled() { Assert.assertTrue(Util.isElementEnabled(driver, passwordXpath), "Password field is not selected"); } /** * Verify 'Forgot password' button is selected */ public void verifyForgotPasswordButtonIsEnabled() { Assert.assertTrue(Util.isElementEnabled(driver, forgotPasswordLinkXpath), "'Forgot password' link is not selected"); } /** * Verify login button is selected */ public void verifyLoginButtonIsEnabled() { Assert.assertTrue(Util.isElementEnabled(driver, loginXpath), "Login button is not selected"); } /** * Set value for 'URL' input * @param urlValue - value that should be specified for 'URL' input field */ public void inputUrlOnClickjackingPageAndPressLoad(String urlValue) { Util.setInputFieldToValue(driver, urlInputXpath, urlValue); Util.click(driver, loadButtonXpath); } }

Welcome!!