Sailaja Thippabhotla
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);
}
}
Subscribe to:
Posts (Atom)