├── .gitignore ├── src ├── test │ ├── resources │ │ ├── config │ │ │ ├── dev-config.properties │ │ │ ├── staging-config.properties │ │ │ ├── config.json │ │ │ └── config.properties │ │ ├── data │ │ │ └── testdata.xlsx │ │ └── chaintest.properties │ └── java │ │ └── com │ │ └── automation │ │ ├── base │ │ └── BaseTest.java │ │ └── tests │ │ ├── AmazonDemoTest.java │ │ ├── GooglePageTests.java │ │ └── OrangeHRMTests.java └── main │ ├── java │ └── com │ │ └── automation │ │ ├── enums │ │ ├── ConfigJson.java │ │ ├── Authors.java │ │ ├── RunType.java │ │ ├── BrowserType.java │ │ ├── CategoryType.java │ │ ├── BrowserRemoteModeType.java │ │ ├── WaitStrategy.java │ │ └── ConfigProperties.java │ │ ├── pages │ │ ├── orangehrm │ │ │ ├── pagecomponents │ │ │ │ ├── adduserspage │ │ │ │ │ ├── SearchComponent.java │ │ │ │ │ ├── UserListComponent.java │ │ │ │ │ └── AddUserComponent.java │ │ │ │ └── homepage │ │ │ │ │ └── TopMenuComponent.java │ │ │ ├── validator │ │ │ │ └── HomePageValidator.java │ │ │ ├── enums │ │ │ │ ├── topmenucomponent │ │ │ │ │ ├── SubMenuType.java │ │ │ │ │ └── MenuType.java │ │ │ │ └── AddUsersScenarioType.java │ │ │ ├── SystemUsersPage.java │ │ │ ├── LoginPage.java │ │ │ ├── AddUsersPredicateFactory.java │ │ │ ├── HomePageAssert.java │ │ │ └── HomePage.java │ │ ├── amazon │ │ │ ├── AmazonLaptopPage.java │ │ │ ├── AmazonHomePage.java │ │ │ └── AmazonHamburgerMenuPage.java │ │ ├── googlesearch │ │ │ ├── GoogleSearchResultPage.java │ │ │ └── GoogleSearchPage.java │ │ └── base │ │ │ └── BasePage.java │ │ ├── driver │ │ ├── abstraction │ │ │ └── IDriver.java │ │ ├── manager │ │ │ ├── local │ │ │ │ ├── EdgeManager.java │ │ │ │ ├── ChromeManager.java │ │ │ │ └── FirefoxManager.java │ │ │ ├── remote │ │ │ │ ├── seleniumgrid │ │ │ │ │ ├── SeleniumGridChromeManager.java │ │ │ │ │ ├── SeleniumGridEdgeManager.java │ │ │ │ │ └── SeleniumGridFirefoxManager.java │ │ │ │ └── selenoid │ │ │ │ │ ├── SelenoidChromeManager.java │ │ │ │ │ └── SelenoidFirefoxManager.java │ │ │ └── DriverManager.java │ │ ├── factory │ │ │ ├── local │ │ │ │ ├── LocalDriverImpl.java │ │ │ │ └── LocalDriverFactory.java │ │ │ ├── remote │ │ │ │ ├── RemoteDriverImpl.java │ │ │ │ ├── SelenoidFactory.java │ │ │ │ ├── RemoteDriverFactory.java │ │ │ │ └── SeleniumGridFactory.java │ │ │ └── DriverFactory.java │ │ ├── entity │ │ │ └── DriverData.java │ │ └── Driver.java │ │ ├── config │ │ ├── ConfigFactory.java │ │ ├── converter │ │ │ ├── StringToUrlConverter.java │ │ │ ├── StringToRunTypeConverter.java │ │ │ └── StringToBrowserRemoteModeTypeConverter.java │ │ └── FrameworkConfig.java │ │ ├── utils │ │ ├── decoder │ │ │ └── DecodeUtils.java │ │ ├── screenshot │ │ │ ├── ScreenshotService.java │ │ │ └── ScreenshotUtils.java │ │ ├── dynamicselector │ │ │ └── DynamicXpathUtils.java │ │ ├── zerocell │ │ │ ├── ExcelReader.java │ │ │ └── TestData.java │ │ ├── configloader │ │ │ ├── JsonUtils.java │ │ │ └── PropertyUtils.java │ │ └── dataprovider │ │ │ ├── DataProviderUtils.java │ │ │ └── ExcelUtils.java │ │ ├── constants │ │ ├── StringConstants.java │ │ └── FrameworkConstants.java │ │ ├── fixtures │ │ └── addusers │ │ │ ├── entity │ │ │ └── UserData.java │ │ │ └── templates │ │ │ └── AddUserTemplate.java │ │ ├── exceptions │ │ ├── FrameworkException.java │ │ ├── PropertyFileUsageException.java │ │ ├── InvalidPathForFilesException.java │ │ ├── JsonFileUsageException.java │ │ ├── BrowserInvocationFailedException.java │ │ ├── DriverInitializationFailedException.java │ │ └── ReportInitializationFailedException.java │ │ ├── listeners │ │ ├── RetryFailedTests.java │ │ ├── AnnotationTransformer.java │ │ ├── MethodInterceptor.java │ │ └── CustomListener.java │ │ ├── reports │ │ ├── ExtentManager.java │ │ ├── ExtentLogger.java │ │ └── ExtentReport.java │ │ ├── annotations │ │ └── FrameworkAnnotation.java │ │ └── factories │ │ └── WaitFactory.java │ └── resources │ └── log4j.properties ├── testngGoogleTest.xml ├── testngOrangeHrmTest.xml ├── testng.xml ├── LICENSE ├── docker-compose.yaml ├── README.md └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /extent-test-output 2 | /.idea 3 | /target 4 | /cm.exe -------------------------------------------------------------------------------- /src/test/resources/config/dev-config.properties: -------------------------------------------------------------------------------- 1 | dev.url=https://amazon.in -------------------------------------------------------------------------------- /src/test/resources/config/staging-config.properties: -------------------------------------------------------------------------------- 1 | staging.url=https://amazon.in -------------------------------------------------------------------------------- /src/test/resources/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "http://localhost:4444/" 3 | } 4 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/ConfigJson.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum ConfigJson { 4 | 5 | URL 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/Authors.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum Authors { 4 | 5 | USER_1, USER_2 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/RunType.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum RunType { 4 | LOCAL, 5 | REMOTE 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/data/testdata.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thangarajtk/selenium-automation-framework/HEAD/src/test/resources/data/testdata.xlsx -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/BrowserType.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum BrowserType { 4 | CHROME, 5 | EDGE, 6 | FIREFOX 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/CategoryType.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | 4 | public enum CategoryType { 5 | 6 | REGRESSION, 7 | SMOKE, 8 | SANITY 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/BrowserRemoteModeType.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum BrowserRemoteModeType { 4 | 5 | SELENIUMGRID, 6 | SELENOID 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/WaitStrategy.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum WaitStrategy { 4 | 5 | CLICKABLE, 6 | PRESENCE, 7 | VISIBLE, 8 | NONE 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/pagecomponents/adduserspage/SearchComponent.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.pagecomponents.adduserspage; 2 | 3 | public class SearchComponent { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/abstraction/IDriver.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.abstraction; 2 | 3 | import com.automation.driver.entity.DriverData; 4 | import org.openqa.selenium.WebDriver; 5 | 6 | public interface IDriver { 7 | 8 | WebDriver getDriver(DriverData driverData); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/amazon/AmazonLaptopPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.amazon; 2 | 3 | import com.automation.pages.base.BasePage; 4 | 5 | public final class AmazonLaptopPage extends BasePage { 6 | 7 | public String getTitle() { 8 | return getPageTitle(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=INFO, stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.Target=System.out 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.stdout.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n -------------------------------------------------------------------------------- /src/main/java/com/automation/enums/ConfigProperties.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum ConfigProperties { 4 | 5 | URL, 6 | OVERRIDE_REPORTS, 7 | PASSED_STEP_SCREENSHOTS, 8 | FAILED_STEP_SCREENSHOTS, 9 | SKIPPED_STEP_SCREENSHOTS, 10 | RETRY_FAILED_TESTS, 11 | RETRY_COUNT, 12 | RUN_MODE 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/validator/HomePageValidator.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.validator; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | @Builder 8 | public class HomePageValidator { 9 | 10 | private String headerName; 11 | private boolean isMarketPlaceLinkPresent; 12 | private String logoSourceText; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/googlesearch/GoogleSearchResultPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.googlesearch; 2 | 3 | import com.automation.driver.manager.DriverManager; 4 | import com.automation.pages.base.BasePage; 5 | 6 | public class GoogleSearchResultPage extends BasePage { 7 | 8 | public String getSearchResultsPageTitle() { 9 | return DriverManager.getDriver().getTitle(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/automation/config/ConfigFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.config; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | import org.aeonbits.owner.ConfigCache; 6 | 7 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 8 | public class ConfigFactory { 9 | 10 | public static FrameworkConfig getConfig() { 11 | return ConfigCache.getOrCreate(FrameworkConfig.class); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/enums/topmenucomponent/SubMenuType.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.enums.topmenucomponent; 2 | 3 | public enum SubMenuType { 4 | 5 | USER_MANAGEMENT("User Management"), 6 | USERS("Users"); 7 | 8 | private final String name; 9 | 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | SubMenuType(String name) { 15 | this.name = name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/decoder/DecodeUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.decoder; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.util.Base64; 7 | 8 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 9 | public final class DecodeUtils { 10 | 11 | public static String getDecodedString(String encodedString) { 12 | return new String(Base64.getDecoder().decode(encodedString.getBytes())); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/local/EdgeManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.local; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.edge.EdgeDriver; 7 | 8 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 9 | public class EdgeManager { 10 | 11 | public static WebDriver getDriver() { 12 | return new EdgeDriver(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /testngGoogleTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/enums/topmenucomponent/MenuType.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.enums.topmenucomponent; 2 | 3 | public enum MenuType { 4 | 5 | ADMIN("Admin"), 6 | PIM("PIM"), 7 | LEAVE("Leave"), 8 | TIME("Time"); 9 | 10 | private final String name; 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | MenuType(String name) { 17 | this.name = name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/local/ChromeManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.local; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.chrome.ChromeDriver; 7 | 8 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 9 | public class ChromeManager { 10 | 11 | public static WebDriver getDriver() { 12 | return new ChromeDriver(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/local/FirefoxManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.local; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | 8 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 9 | public class FirefoxManager { 10 | 11 | public static WebDriver getDriver() { 12 | return new FirefoxDriver(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/automation/config/converter/StringToUrlConverter.java: -------------------------------------------------------------------------------- 1 | package com.automation.config.converter; 2 | 3 | import lombok.SneakyThrows; 4 | import org.aeonbits.owner.Converter; 5 | import java.lang.reflect.Method; 6 | import java.net.URL; 7 | 8 | public class StringToUrlConverter implements Converter { 9 | 10 | @SneakyThrows 11 | @Override 12 | public URL convert(Method method, String remoteUrl) { 13 | 14 | return new URL(remoteUrl); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/screenshot/ScreenshotService.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.screenshot; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | 6 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 7 | public final class ScreenshotService { 8 | 9 | // Abstract layer to handle the change in business requirement 10 | public static String getScreenshotAsBase64() { 11 | return ScreenshotUtils.captureScreenshotAsBase64(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/constants/StringConstants.java: -------------------------------------------------------------------------------- 1 | package com.automation.constants; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | 6 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 7 | public final class StringConstants { 8 | 9 | public static final String ORANGEHRM_PAGE_TITLE = "OrangeHRM"; 10 | public static final String GOOGLE_SEARCH_RESULTS_PAGE_TITLE = "Google Search"; 11 | public static final String SELECTED_MENU_ITEM = "Laptops"; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/local/LocalDriverImpl.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.local; 2 | 3 | import com.automation.driver.abstraction.IDriver; 4 | import com.automation.driver.entity.DriverData; 5 | import org.openqa.selenium.WebDriver; 6 | 7 | public class LocalDriverImpl implements IDriver { 8 | 9 | @Override 10 | public WebDriver getDriver(DriverData driverData) { 11 | return LocalDriverFactory.getDriver(driverData.getBrowserType()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/remote/RemoteDriverImpl.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.remote; 2 | 3 | import com.automation.driver.abstraction.IDriver; 4 | import com.automation.driver.entity.DriverData; 5 | import org.openqa.selenium.WebDriver; 6 | 7 | public class RemoteDriverImpl implements IDriver { 8 | 9 | @Override 10 | public WebDriver getDriver(DriverData driverData) { 11 | return RemoteDriverFactory.getDriver(driverData.getBrowserRemoteModeType(), driverData.getBrowserType()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/entity/DriverData.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.entity; 2 | 3 | import com.automation.enums.BrowserRemoteModeType; 4 | import com.automation.enums.BrowserType; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | 8 | /** 9 | * Builder pattern helps in creating immutable classes with a large set of state attributes 10 | * 11 | */ 12 | @Builder 13 | @Getter 14 | public class DriverData { 15 | 16 | private BrowserType browserType; 17 | private BrowserRemoteModeType browserRemoteModeType; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/dynamicselector/DynamicXpathUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.dynamicselector; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | 6 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 7 | public final class DynamicXpathUtils { 8 | 9 | public static String getXpath(String xpath, String value) { 10 | return String.format(xpath, value); 11 | } 12 | 13 | public static String getXpath(String xpath, String value1, String value2) { 14 | return String.format(xpath, value1,value2); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/automation/fixtures/addusers/entity/UserData.java: -------------------------------------------------------------------------------- 1 | package com.automation.fixtures.addusers.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | @Getter 11 | @ToString 12 | public class UserData { 13 | 14 | private String userRole; 15 | private String employeeName; 16 | private String userName; 17 | private String status; 18 | private String password; 19 | private String message; 20 | } -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/amazon/AmazonHomePage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.amazon; 2 | 3 | import com.automation.enums.WaitStrategy; 4 | import com.automation.pages.base.BasePage; 5 | import org.openqa.selenium.By; 6 | 7 | public final class AmazonHomePage extends BasePage { 8 | 9 | private final By menuHamburger = By.id("nav-hamburger-menu"); 10 | 11 | public AmazonHamburgerMenuPage clickHamburger() { 12 | click(menuHamburger, WaitStrategy.CLICKABLE, "Hamburger menu"); 13 | return new AmazonHamburgerMenuPage(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/pagecomponents/adduserspage/UserListComponent.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.pagecomponents.adduserspage; 2 | 3 | import com.automation.enums.WaitStrategy; 4 | import com.automation.pages.base.BasePage; 5 | import org.openqa.selenium.By; 6 | 7 | public class UserListComponent extends BasePage { 8 | 9 | private static final By BUTTON_ADD = By.id("btnAdd"); 10 | 11 | public AddUserComponent setAddButton() { 12 | click(BUTTON_ADD, WaitStrategy.PRESENCE, "Add button"); 13 | return new AddUserComponent(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/googlesearch/GoogleSearchPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.googlesearch; 2 | 3 | import com.automation.enums.WaitStrategy; 4 | import com.automation.pages.base.BasePage; 5 | import org.openqa.selenium.By; 6 | 7 | public class GoogleSearchPage extends BasePage { 8 | 9 | private final By txtFieldSearch = By.xpath("//input[@aria-label='Search']"); 10 | 11 | public GoogleSearchResultPage performSearch(String searchText) { 12 | sendKeysAndPressEnter(txtFieldSearch, searchText, WaitStrategy.PRESENCE,"Search text box"); 13 | return new GoogleSearchResultPage(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/remote/seleniumgrid/SeleniumGridChromeManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.remote.seleniumgrid; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.SneakyThrows; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.chrome.ChromeOptions; 7 | import org.openqa.selenium.remote.RemoteWebDriver; 8 | 9 | public class SeleniumGridChromeManager { 10 | 11 | private SeleniumGridChromeManager() {} 12 | 13 | @SneakyThrows 14 | public static WebDriver getDriver() { 15 | return new RemoteWebDriver(ConfigFactory.getConfig().seleniumGridUrl(), new ChromeOptions()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/FrameworkException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class FrameworkException extends RuntimeException{ 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public FrameworkException(String message) { 10 | super(message); 11 | } 12 | /** 13 | * 14 | * @param message Details about the exception or custom message 15 | * @param cause Pass the enriched stacktrace or customised stacktrace 16 | */ 17 | public FrameworkException(String message,Throwable cause) { 18 | super(message,cause); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/automation/config/converter/StringToRunTypeConverter.java: -------------------------------------------------------------------------------- 1 | package com.automation.config.converter; 2 | 3 | import com.automation.enums.RunType; 4 | import org.aeonbits.owner.Converter; 5 | import java.lang.reflect.Method; 6 | import java.util.Map; 7 | 8 | public class StringToRunTypeConverter implements Converter { 9 | 10 | @Override 11 | public RunType convert(Method method, String runType) { 12 | Map stringRunTypeMap = Map. 13 | of("LOCAL", RunType.LOCAL, 14 | "REMOTE", RunType.REMOTE); 15 | 16 | return stringRunTypeMap.getOrDefault(runType.toUpperCase(), RunType.LOCAL); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testngOrangeHrmTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/java/com/automation/listeners/RetryFailedTests.java: -------------------------------------------------------------------------------- 1 | package com.automation.listeners; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import org.testng.IRetryAnalyzer; 5 | import org.testng.ITestResult; 6 | 7 | public class RetryFailedTests implements IRetryAnalyzer { 8 | 9 | private int count = 0; 10 | private final int maxRetry = ConfigFactory.getConfig().retry_count(); 11 | 12 | @Override 13 | public boolean retry(ITestResult result) { 14 | boolean value = false; 15 | if (ConfigFactory.getConfig().retry_failed_tests()) { 16 | value = count < maxRetry; 17 | count++; 18 | } 19 | return value; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/com/automation/reports/ExtentManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.reports; 2 | 3 | import com.aventstack.extentreports.ExtentTest; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | 7 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 8 | public class ExtentManager { 9 | 10 | private static final ThreadLocal extTest = new ThreadLocal<>() ; 11 | 12 | public static ExtentTest getExtentTest() { //default --> it can be only accessed within the package --> private packages 13 | return extTest.get(); 14 | } 15 | 16 | static void setExtentTest(ExtentTest test) { 17 | extTest.set(test); 18 | } 19 | 20 | static void unload() { 21 | extTest.remove(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/PropertyFileUsageException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class PropertyFileUsageException extends FrameworkException{ 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public PropertyFileUsageException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * @param message Details about the exception or custom message 15 | * @param cause Pass the enriched stacktrace or customised stacktrace 16 | */ 17 | public PropertyFileUsageException(String message,Throwable cause) { 18 | super(message,cause); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/SystemUsersPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm; 2 | 3 | import com.automation.pages.base.BasePage; 4 | import com.automation.pages.orangehrm.pagecomponents.adduserspage.SearchComponent; 5 | import com.automation.pages.orangehrm.pagecomponents.adduserspage.UserListComponent; 6 | import lombok.Getter; 7 | 8 | public final class SystemUsersPage extends BasePage { 9 | 10 | private final SearchComponent searchComponent; 11 | @Getter 12 | private final UserListComponent userListComponent; 13 | 14 | public SystemUsersPage() { 15 | this.userListComponent = new UserListComponent(); 16 | this.searchComponent = new SearchComponent(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/InvalidPathForFilesException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class InvalidPathForFilesException extends FrameworkException{ 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public InvalidPathForFilesException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * 15 | * @param message Details about the exception or custom message 16 | * @param cause Pass the enriched stacktrace or customised stacktrace 17 | */ 18 | public InvalidPathForFilesException(String message,Throwable cause) { 19 | super(message,cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/remote/seleniumgrid/SeleniumGridEdgeManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.remote.seleniumgrid; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import lombok.SneakyThrows; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.edge.EdgeOptions; 9 | import org.openqa.selenium.remote.RemoteWebDriver; 10 | 11 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 12 | public class SeleniumGridEdgeManager { 13 | 14 | @SneakyThrows 15 | public static WebDriver getDriver() { 16 | return new RemoteWebDriver(ConfigFactory.getConfig().seleniumGridUrl(), new EdgeOptions()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/JsonFileUsageException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class JsonFileUsageException extends FrameworkException { 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public JsonFileUsageException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * @param message Details about the exception or custom message 15 | * @param cause Pass the enriched stacktrace or customised stacktrace 16 | */ 17 | public JsonFileUsageException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/remote/seleniumgrid/SeleniumGridFirefoxManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.remote.seleniumgrid; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import lombok.SneakyThrows; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.firefox.FirefoxOptions; 9 | import org.openqa.selenium.remote.RemoteWebDriver; 10 | 11 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 12 | public class SeleniumGridFirefoxManager { 13 | 14 | @SneakyThrows 15 | public static WebDriver getDriver() { 16 | return new RemoteWebDriver(ConfigFactory.getConfig().seleniumGridUrl(), new FirefoxOptions()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/BrowserInvocationFailedException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class BrowserInvocationFailedException extends FrameworkException { 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public BrowserInvocationFailedException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * 15 | * @param message Details about the exception or custom message 16 | * @param cause Pass the enriched stacktrace or customised stacktrace 17 | */ 18 | public BrowserInvocationFailedException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/DriverInitializationFailedException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class DriverInitializationFailedException extends FrameworkException { 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public DriverInitializationFailedException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * 15 | * @param message Details about the exception or custom message 16 | * @param cause Pass the enriched stacktrace or customised stacktrace 17 | */ 18 | public DriverInitializationFailedException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/automation/exceptions/ReportInitializationFailedException.java: -------------------------------------------------------------------------------- 1 | package com.automation.exceptions; 2 | 3 | public class ReportInitializationFailedException extends FrameworkException { 4 | 5 | /** 6 | * Pass the message that needs to be appended to the stacktrace 7 | * @param message Details about the exception or custom message 8 | */ 9 | public ReportInitializationFailedException(String message) { 10 | super(message); 11 | } 12 | 13 | /** 14 | * 15 | * @param message Details about the exception or custom message 16 | * @param cause Pass the enriched stacktrace or customised stacktrace 17 | */ 18 | public ReportInitializationFailedException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/DriverManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.NoArgsConstructor; 5 | import org.openqa.selenium.WebDriver; 6 | 7 | /** 8 | * DriverManager class helps to achieve thread safety for the driver instance. 9 | * @author Administrator 10 | */ 11 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 12 | public final class DriverManager { 13 | 14 | private static final ThreadLocal threadLocalDriver = new ThreadLocal<>(); 15 | 16 | public static WebDriver getDriver() { 17 | return threadLocalDriver.get(); 18 | } 19 | 20 | public static void setDriver(WebDriver driver) { 21 | threadLocalDriver.set(driver); 22 | } 23 | 24 | public static void unload() { 25 | threadLocalDriver.remove(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/zerocell/ExcelReader.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.zerocell; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.creditdatamw.zerocell.Reader; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.io.File; 10 | import java.util.List; 11 | 12 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 13 | public final class ExcelReader { 14 | 15 | @Getter 16 | private static final List testDataList; 17 | 18 | static { 19 | testDataList = Reader.of(TestData.class) 20 | .from(new File(FrameworkConstants.TEST_DATA_EXCEL_PATH)) 21 | .sheet(FrameworkConstants.DATA_SHEET) 22 | .skipHeaderRow(true) 23 | .list(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/zerocell/TestData.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.zerocell; 2 | 3 | import com.creditdatamw.zerocell.annotation.Column; 4 | import lombok.Getter; 5 | import lombok.ToString; 6 | 7 | @Getter 8 | @ToString 9 | public class TestData { 10 | 11 | //POJO 12 | @Column(name = "TestName", index = 0) 13 | private String TestName; 14 | 15 | @Column(name = "Execute", index = 1) 16 | private String Execute; 17 | 18 | @Column(name = "browser", index = 2) 19 | private String browser; 20 | 21 | @Column(name = "version", index = 3) 22 | private String version; 23 | 24 | @Column(name = "username", index = 4) 25 | private String username; 26 | 27 | @Column(name = "password", index = 5) 28 | private String password; 29 | 30 | @Column(name = "MenuToSelect", index = 6) 31 | private String MenuToSelect; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/remote/SelenoidFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.remote; 2 | 3 | import com.automation.driver.manager.remote.selenoid.SelenoidChromeManager; 4 | import com.automation.driver.manager.remote.selenoid.SelenoidFirefoxManager; 5 | import com.automation.enums.BrowserType; 6 | import lombok.AccessLevel; 7 | import lombok.NoArgsConstructor; 8 | import org.openqa.selenium.WebDriver; 9 | 10 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 11 | final class SelenoidFactory { 12 | 13 | public static WebDriver getDriver(BrowserType browserType) { 14 | return isChromeBrowser(browserType) ? SelenoidChromeManager.getDriver() : 15 | SelenoidFirefoxManager.getDriver(); 16 | } 17 | 18 | private static boolean isChromeBrowser(BrowserType browserType) { 19 | return browserType == BrowserType.CHROME; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/automation/config/converter/StringToBrowserRemoteModeTypeConverter.java: -------------------------------------------------------------------------------- 1 | package com.automation.config.converter; 2 | 3 | import com.automation.enums.BrowserRemoteModeType; 4 | import org.aeonbits.owner.Converter; 5 | import java.lang.reflect.Method; 6 | import java.util.Map; 7 | 8 | public class StringToBrowserRemoteModeTypeConverter implements Converter { 9 | 10 | @Override 11 | public BrowserRemoteModeType convert(Method method, String browserRemoteModeType) { 12 | Map stringBrowserRemoteModeTypeMap = Map. 13 | of("SELENOID", BrowserRemoteModeType.SELENOID, 14 | "SELENIUMGRID", BrowserRemoteModeType.SELENIUMGRID); 15 | 16 | return stringBrowserRemoteModeTypeMap.getOrDefault(browserRemoteModeType.toUpperCase(), 17 | BrowserRemoteModeType.SELENOID); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/automation/listeners/AnnotationTransformer.java: -------------------------------------------------------------------------------- 1 | package com.automation.listeners; 2 | 3 | import com.automation.utils.dataprovider.DataProviderUtils; 4 | import org.testng.IAnnotationTransformer; 5 | import org.testng.annotations.ITestAnnotation; 6 | 7 | import java.lang.reflect.Constructor; 8 | import java.lang.reflect.Method; 9 | 10 | public class AnnotationTransformer implements IAnnotationTransformer { 11 | 12 | /** 13 | * Helps in setting the dataprovider, dataprovider class and retry analyser annotation to all the test methods 14 | * at run time. 15 | */ 16 | @Override 17 | public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { 18 | annotation.setDataProvider("getDataUsingZeroCell"); 19 | annotation.setDataProviderClass(DataProviderUtils.class); 20 | annotation.setRetryAnalyzer(RetryFailedTests.class); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/DriverFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory; 2 | 3 | import com.automation.driver.abstraction.IDriver; 4 | import com.automation.driver.factory.local.LocalDriverImpl; 5 | import com.automation.driver.factory.remote.RemoteDriverImpl; 6 | import com.automation.enums.RunType; 7 | import lombok.AccessLevel; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.util.EnumMap; 11 | import java.util.Map; 12 | import java.util.function.Supplier; 13 | 14 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 15 | public final class DriverFactory { 16 | 17 | private static final Map> WEB = new EnumMap<>(RunType.class); 18 | 19 | static { 20 | WEB.put(RunType.LOCAL, LocalDriverImpl::new); 21 | WEB.put(RunType.REMOTE, RemoteDriverImpl::new); 22 | } 23 | 24 | public static IDriver getDriver(RunType runType) { 25 | 26 | return WEB.get(runType).get(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/test/resources/config/config.properties: -------------------------------------------------------------------------------- 1 | environment=staging 2 | 3 | # Please provide the key in lowercase 4 | url=https://amazon.in 5 | 6 | # Dynamic reports yes or no 7 | #if no, report will have name as current time+index.html 8 | #if yes, report will have name as index.html 9 | override_report=yes 10 | 11 | # Provides an option to capture screenshot for passed steps 12 | passed_step_screenshots=false 13 | 14 | # Provides an option to capture screenshot for failed steps 15 | failed_step_screenshots=true 16 | 17 | # Provides an option to capture screenshot for skipped steps 18 | skipped_step_screenshots=false 19 | 20 | # Provides an option to retry failed tests 21 | retry_failed_tests=false 22 | retry_count=1 23 | 24 | #Runmode Local or Remote 25 | run_mode=local 26 | 27 | # Remote execution options - seleniumgrid or selenoid 28 | remote_mode=selenoid 29 | 30 | # Remote URL 31 | seleniumGridUrl=http://localhost:4444/ 32 | 33 | selenoidUrl=http://localhost:4444/wd/hub -------------------------------------------------------------------------------- /src/main/java/com/automation/annotations/FrameworkAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.automation.annotations; 2 | 3 | import static java.lang.annotation.ElementType.METHOD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import com.automation.enums.Authors; 11 | import com.automation.enums.CategoryType; 12 | 13 | /** 14 | * Framework Annotation is user built annotation which is annotated on top of test methods to log the author details and 15 | * category details to the extent report. 16 | * 17 | * Runtime retention value indicate that this annotation will be available at run time for reflection operations. 18 | * 19 | * @author Administrator 20 | */ 21 | @Retention(RUNTIME) 22 | @Target(METHOD) 23 | @Documented 24 | public @interface FrameworkAnnotation { 25 | 26 | Authors[] author(); 27 | 28 | CategoryType[] category(); 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/automation/base/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.automation.base; 2 | 3 | import com.automation.driver.Driver; 4 | import com.automation.enums.BrowserType; 5 | import com.automation.utils.zerocell.TestData; 6 | import lombok.AccessLevel; 7 | import lombok.NoArgsConstructor; 8 | import org.testng.annotations.AfterMethod; 9 | import org.testng.annotations.BeforeMethod; 10 | 11 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 12 | public class BaseTest { 13 | 14 | // @BeforeSuite 15 | // protected void loadFixtureTemplate() { 16 | // FixtureFactoryLoader.loadTemplates("com.automation.fixtures.addusers"); 17 | // } 18 | 19 | @BeforeMethod 20 | protected void setUp(Object[] data) { 21 | TestData testData = (TestData) data[0]; 22 | Driver.initDriver(BrowserType.valueOf(testData.getBrowser().toUpperCase())); 23 | } 24 | 25 | @AfterMethod 26 | protected void tearDown() { 27 | Driver.quitDriver(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/remote/RemoteDriverFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.remote; 2 | 3 | import com.automation.enums.BrowserRemoteModeType; 4 | import com.automation.enums.BrowserType; 5 | import lombok.AccessLevel; 6 | import lombok.NoArgsConstructor; 7 | import org.openqa.selenium.WebDriver; 8 | import java.util.EnumMap; 9 | import java.util.Map; 10 | import java.util.function.Function; 11 | 12 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 13 | final class RemoteDriverFactory { 14 | 15 | private static final Map> 16 | MAP = new EnumMap<>(BrowserRemoteModeType.class); 17 | 18 | static { 19 | MAP.put(BrowserRemoteModeType.SELENIUMGRID, SeleniumGridFactory::getDriver); 20 | MAP.put(BrowserRemoteModeType.SELENOID, SelenoidFactory::getDriver); 21 | } 22 | 23 | public static WebDriver getDriver(BrowserRemoteModeType browserRemoteMode, BrowserType browserType) { 24 | return MAP.get(browserRemoteMode).apply(browserType); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/local/LocalDriverFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.local; 2 | 3 | import com.automation.driver.manager.local.ChromeManager; 4 | import com.automation.driver.manager.local.EdgeManager; 5 | import com.automation.driver.manager.local.FirefoxManager; 6 | import com.automation.enums.BrowserType; 7 | import lombok.AccessLevel; 8 | import lombok.NoArgsConstructor; 9 | import org.openqa.selenium.WebDriver; 10 | 11 | import java.util.EnumMap; 12 | import java.util.Map; 13 | import java.util.function.Supplier; 14 | 15 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 16 | final class LocalDriverFactory { 17 | 18 | private static final Map> MAP = new EnumMap<>(BrowserType.class); 19 | 20 | static { 21 | MAP.put(BrowserType.CHROME, ChromeManager::getDriver); 22 | MAP.put(BrowserType.FIREFOX, FirefoxManager::getDriver); 23 | MAP.put(BrowserType.EDGE, EdgeManager::getDriver); 24 | } 25 | 26 | public static WebDriver getDriver(BrowserType browserType) { 27 | return MAP.get(browserType).get(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/enums/AddUsersScenarioType.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.enums; 2 | 3 | import br.com.six2six.fixturefactory.Fixture; 4 | import com.automation.fixtures.addusers.entity.UserData; 5 | import com.automation.pages.orangehrm.AddUsersPredicateFactory; 6 | import com.automation.pages.orangehrm.pagecomponents.adduserspage.AddUserComponent; 7 | import lombok.Getter; 8 | 9 | import java.util.function.BiPredicate; 10 | 11 | @Getter 12 | public enum AddUsersScenarioType { 13 | VALID(AddUsersPredicateFactory.getPredicate("valid") , 14 | Fixture.from(UserData.class).gimme("valid")) , 15 | 16 | JUST_EMPLOYEE_NAME(AddUsersPredicateFactory.getPredicate("just_employee_name") 17 | , Fixture.from(UserData.class).gimme("just_employee_name")); 18 | 19 | private final BiPredicate predicate; 20 | private final UserData userData; 21 | 22 | AddUsersScenarioType(BiPredicate predicate, UserData userData) { 23 | this.predicate = predicate; 24 | this.userData = userData; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Thangaraj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/test/java/com/automation/tests/AmazonDemoTest.java: -------------------------------------------------------------------------------- 1 | package com.automation.tests; 2 | 3 | import com.automation.annotations.FrameworkAnnotation; 4 | import com.automation.base.BaseTest; 5 | import com.automation.enums.Authors; 6 | import com.automation.enums.CategoryType; 7 | import com.automation.pages.amazon.AmazonHomePage; 8 | import com.automation.utils.zerocell.TestData; 9 | import lombok.AccessLevel; 10 | import lombok.NoArgsConstructor; 11 | import org.testng.annotations.Test; 12 | 13 | import java.util.Objects; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | 18 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 19 | public final class AmazonDemoTest extends BaseTest { 20 | 21 | @Test 22 | @FrameworkAnnotation(author = {Authors.USER_1, Authors.USER_2}, 23 | category = {CategoryType.REGRESSION, CategoryType.SANITY}) 24 | public void amazonTest(TestData data) { 25 | String title = Objects.requireNonNull(new AmazonHomePage().clickHamburger() 26 | .clickComputer() 27 | .clickOnSubMenuItem(data.getMenuToSelect())) 28 | .getTitle(); 29 | 30 | assertThat(title).isNotNull(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/remote/selenoid/SelenoidChromeManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.remote.selenoid; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import lombok.SneakyThrows; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.remote.DesiredCapabilities; 9 | import org.openqa.selenium.remote.RemoteWebDriver; 10 | 11 | import java.util.Map; 12 | 13 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 14 | public final class SelenoidChromeManager { 15 | 16 | @SneakyThrows 17 | public static WebDriver getDriver() { 18 | DesiredCapabilities capabilities = new DesiredCapabilities(); 19 | capabilities.setCapability("browserName", "chrome"); 20 | capabilities.setCapability("browserVersion", "101.0"); 21 | capabilities.setCapability("selenoid:options", Map.of( 22 | "enableVNC", true, 23 | "enableVideo", true 24 | )); 25 | return new RemoteWebDriver(ConfigFactory.getConfig() 26 | .selenoidUrl(), capabilities); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/manager/remote/selenoid/SelenoidFirefoxManager.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.manager.remote.selenoid; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import lombok.SneakyThrows; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.remote.DesiredCapabilities; 9 | import org.openqa.selenium.remote.RemoteWebDriver; 10 | 11 | import java.util.Map; 12 | 13 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 14 | public final class SelenoidFirefoxManager { 15 | 16 | @SneakyThrows 17 | public static WebDriver getDriver() { 18 | DesiredCapabilities capabilities = new DesiredCapabilities(); 19 | capabilities.setCapability("browserName", "firefox"); 20 | capabilities.setCapability("browserVersion", "99.0"); 21 | capabilities.setCapability("selenoid:options", Map.of( 22 | "enableVNC", true, 23 | "enableVideo", true 24 | )); 25 | return new RemoteWebDriver(ConfigFactory.getConfig() 26 | .selenoidUrl(), capabilities); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/automation/fixtures/addusers/templates/AddUserTemplate.java: -------------------------------------------------------------------------------- 1 | package com.automation.fixtures.addusers.templates; 2 | 3 | import br.com.six2six.fixturefactory.Fixture; 4 | import br.com.six2six.fixturefactory.Rule; 5 | import br.com.six2six.fixturefactory.loader.TemplateLoader; 6 | import com.automation.fixtures.addusers.entity.UserData; 7 | 8 | public class AddUserTemplate implements TemplateLoader { 9 | 10 | @Override 11 | public void load() { 12 | Fixture.of(UserData.class).addTemplate("valid", new Rule() {{ 13 | add("userRole", random("ESS", "Admin")); 14 | add("employeeName", uniqueRandom("User-1", "User-2")); 15 | add("userName", random("test_user")); 16 | add("status", random("Enabled", "Disabled")); 17 | add("password", random("testPassword@123")); 18 | add("errorMessage", "Success message is not displayed"); 19 | }}); 20 | 21 | Fixture.of(UserData.class).addTemplate("just_employee_name", new Rule() {{ 22 | add("employeeName", random("test_user")); 23 | add("message", "Error message is not displayed"); 24 | }}); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/screenshot/ScreenshotUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.screenshot; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.automation.driver.manager.DriverManager; 5 | import lombok.AccessLevel; 6 | import lombok.NoArgsConstructor; 7 | import lombok.SneakyThrows; 8 | import org.apache.commons.io.FileUtils; 9 | import org.openqa.selenium.OutputType; 10 | import org.openqa.selenium.TakesScreenshot; 11 | import java.io.File; 12 | 13 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 14 | public final class ScreenshotUtils { 15 | 16 | // This class is to handle the change in third party library 17 | @SneakyThrows 18 | public static void captureScreenshotAsFile(String testCaseName) { 19 | File source = ((TakesScreenshot) DriverManager.getDriver()).getScreenshotAs(OutputType.FILE); 20 | File destination = new File(FrameworkConstants.SCREENSHOT_PATH + File.separator + testCaseName + ".png"); 21 | FileUtils.copyFile(source, destination); 22 | } 23 | 24 | public static String captureScreenshotAsBase64() { 25 | return ((TakesScreenshot) DriverManager.getDriver()).getScreenshotAs(OutputType.BASE64); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/automation/listeners/MethodInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.automation.listeners; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.testng.IMethodInstance; 8 | import org.testng.IMethodInterceptor; 9 | import org.testng.ITestContext; 10 | 11 | import com.automation.constants.FrameworkConstants; 12 | import com.automation.utils.dataprovider.ExcelUtils; 13 | 14 | public class MethodInterceptor implements IMethodInterceptor { 15 | 16 | @Override 17 | public List intercept(List methods, ITestContext context) { 18 | 19 | List> list = ExcelUtils.getTestDetails(FrameworkConstants.RUN_MANAGER_SHEET); 20 | List result = new ArrayList<>(); 21 | 22 | for (IMethodInstance method : methods) { 23 | for (Map map : list) { 24 | if (method.getMethod().getMethodName().equalsIgnoreCase(map.get("TestName")) && 25 | map.get("Execute").equalsIgnoreCase("yes")) { 26 | method.getMethod().setDescription((map.get("Description"))); 27 | result.add(method); 28 | } 29 | } 30 | } 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/amazon/AmazonHamburgerMenuPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.amazon; 2 | 3 | import com.automation.constants.StringConstants; 4 | import com.automation.factories.WaitFactory; 5 | import com.automation.pages.base.BasePage; 6 | import org.openqa.selenium.By; 7 | import com.automation.enums.WaitStrategy; 8 | import com.automation.utils.dynamicselector.DynamicXpathUtils; 9 | 10 | public final class AmazonHamburgerMenuPage extends BasePage { 11 | 12 | private final By linkComputers = By.xpath("//div[text()='Mobiles, Computers']/parent::a"); 13 | private String linkSubMenu = "//a[text()='%s']"; 14 | 15 | public AmazonHamburgerMenuPage clickComputer() { 16 | WaitFactory.performExplicitWait(WaitStrategy.VISIBLE, linkComputers); 17 | click(linkComputers, WaitStrategy.CLICKABLE, "Mobiles and Computers"); 18 | return this; 19 | } 20 | 21 | public AmazonLaptopPage clickOnSubMenuItem(String menuItem) { 22 | By findSubMenu = By.xpath(DynamicXpathUtils.getXpath(linkSubMenu, menuItem)); 23 | WaitFactory.performExplicitWait(WaitStrategy.PRESENCE, findSubMenu); 24 | clickUsingJSExecutor(findSubMenu); 25 | 26 | return menuItem.contains(StringConstants.SELECTED_MENU_ITEM) ? new AmazonLaptopPage() : null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/automation/tests/GooglePageTests.java: -------------------------------------------------------------------------------- 1 | package com.automation.tests; 2 | 3 | import com.automation.annotations.FrameworkAnnotation; 4 | import com.automation.base.BaseTest; 5 | import com.automation.constants.StringConstants; 6 | import com.automation.enums.Authors; 7 | import com.automation.enums.CategoryType; 8 | import com.automation.pages.googlesearch.GoogleSearchPage; 9 | import lombok.AccessLevel; 10 | import lombok.NoArgsConstructor; 11 | import org.testng.annotations.Test; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 16 | public final class GooglePageTests extends BaseTest { 17 | 18 | @Test 19 | @FrameworkAnnotation(author = {Authors.USER_1}, category = {CategoryType.SANITY}) 20 | public void googleSearchTest() { 21 | String title = new GoogleSearchPage() 22 | .performSearch("Automation") 23 | .getSearchResultsPageTitle(); 24 | 25 | assertThat(title) 26 | .as("Object is actually null").isNotNull() 27 | .as("It does not contains expected text").containsIgnoringCase("google search") 28 | .matches("\\w.*" + StringConstants.GOOGLE_SEARCH_RESULTS_PAGE_TITLE) 29 | .hasSizeBetween(15, 100); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/factory/remote/SeleniumGridFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver.factory.remote; 2 | 3 | import com.automation.driver.manager.remote.seleniumgrid.SeleniumGridChromeManager; 4 | import com.automation.driver.manager.remote.seleniumgrid.SeleniumGridEdgeManager; 5 | import com.automation.driver.manager.remote.seleniumgrid.SeleniumGridFirefoxManager; 6 | import com.automation.enums.BrowserType; 7 | import lombok.AccessLevel; 8 | import lombok.NoArgsConstructor; 9 | import org.openqa.selenium.WebDriver; 10 | 11 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 12 | final class SeleniumGridFactory { 13 | 14 | public static WebDriver getDriver(BrowserType browserType) { 15 | if (isChromeBrowser(browserType)) { 16 | return SeleniumGridChromeManager.getDriver(); 17 | } 18 | else { 19 | if (isFirefoxBrowser(browserType)) 20 | return SeleniumGridFirefoxManager.getDriver(); 21 | return SeleniumGridEdgeManager.getDriver(); 22 | } 23 | } 24 | 25 | private static boolean isChromeBrowser(BrowserType browserType) { 26 | return browserType == BrowserType.CHROME; 27 | } 28 | 29 | private static boolean isFirefoxBrowser(BrowserType browserType) { 30 | return browserType == BrowserType.FIREFOX; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/LoginPage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm; 2 | 3 | import com.automation.pages.base.BasePage; 4 | import org.openqa.selenium.By; 5 | 6 | import com.automation.enums.WaitStrategy; 7 | import com.automation.utils.decoder.DecodeUtils; 8 | 9 | public final class LoginPage extends BasePage { 10 | 11 | private static final By TEXT_BOX_USERNAME = By.id("txtUsername"); 12 | private static final By TEXT_BOX_PASSWORD = By.xpath("//input[@id='txtPassword' and @type='password']"); 13 | private static final By BUTTON_LOGIN = By.id("btnLogin"); 14 | 15 | private LoginPage enterUserName(String username) { 16 | sendKeys(TEXT_BOX_USERNAME, username, WaitStrategy.PRESENCE, "Username"); 17 | return this; 18 | } 19 | 20 | private LoginPage enterPassWord(String password) { 21 | sendKeys(TEXT_BOX_PASSWORD, DecodeUtils.getDecodedString(password), WaitStrategy.PRESENCE, "Password"); 22 | return this; 23 | } 24 | private HomePage clickLogin() { 25 | click(BUTTON_LOGIN, WaitStrategy.PRESENCE, "Login Button"); 26 | return new HomePage(); 27 | } 28 | 29 | public HomePage loginToApplication(String username, String password) { 30 | return enterUserName(username) 31 | .enterPassWord(password) 32 | .clickLogin(); 33 | } 34 | 35 | public String getTitle() { 36 | return getPageTitle(); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # To execute this docker-compose yml file use `docker-compose -f docker-compose-v3.yml up` 2 | # Add the `-d` flag at the end for detached execution 3 | # To stop the execution, hit Ctrl+C, and then `docker-compose -f docker-compose-v3.yml down` 4 | version: "3" 5 | services: 6 | chrome: 7 | image: selenium/node-chrome:4.1.2-20220217 8 | shm_size: 2gb 9 | depends_on: 10 | - selenium-hub 11 | environment: 12 | - SE_EVENT_BUS_HOST=selenium-hub 13 | - SE_EVENT_BUS_PUBLISH_PORT=4442 14 | - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 15 | restart: on-failure 16 | 17 | edge: 18 | image: selenium/node-edge:4.1.2-20220217 19 | shm_size: 2gb 20 | depends_on: 21 | - selenium-hub 22 | environment: 23 | - SE_EVENT_BUS_HOST=selenium-hub 24 | - SE_EVENT_BUS_PUBLISH_PORT=4442 25 | - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 26 | restart: on-failure 27 | 28 | firefox: 29 | image: selenium/node-firefox:4.1.2-20220217 30 | shm_size: 2gb 31 | depends_on: 32 | - selenium-hub 33 | environment: 34 | - SE_EVENT_BUS_HOST=selenium-hub 35 | - SE_EVENT_BUS_PUBLISH_PORT=4442 36 | - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 37 | restart: on-failure 38 | 39 | selenium-hub: 40 | image: selenium/hub:4.1.2-20220217 41 | container_name: selenium-hub 42 | restart: always 43 | ports: 44 | - "4442:4442" 45 | - "4443:4443" 46 | - "4444:4444" -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/configloader/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.configloader; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Objects; 8 | import com.automation.constants.FrameworkConstants; 9 | import com.automation.enums.ConfigJson; 10 | import com.automation.exceptions.JsonFileUsageException; 11 | import com.fasterxml.jackson.core.type.TypeReference; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | import lombok.AccessLevel; 14 | import lombok.NoArgsConstructor; 15 | 16 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 17 | public final class JsonUtils { 18 | 19 | private static final Map map; 20 | 21 | static { 22 | try { 23 | map = new ObjectMapper().readValue(new File(FrameworkConstants.JSON_CONFIG_FILE_PATH), 24 | new TypeReference>() { 25 | }); 26 | 27 | } catch (IOException e) { 28 | throw new JsonFileUsageException("IOException occurred while reading Json file in the specified path"); 29 | } 30 | } 31 | 32 | public static String get(ConfigJson key) { 33 | if (Objects.isNull(key) || Objects.isNull(map.get(key.name().toLowerCase()))) { 34 | throw new JsonFileUsageException("Property name " + key + " is not found. Please check config.json"); 35 | } 36 | return map.get(key.name().toLowerCase()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/pagecomponents/homepage/TopMenuComponent.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.pagecomponents.homepage; 2 | 3 | import com.automation.enums.WaitStrategy; 4 | import com.automation.pages.base.BasePage; 5 | import com.automation.pages.orangehrm.enums.topmenucomponent.MenuType; 6 | import com.automation.pages.orangehrm.enums.topmenucomponent.SubMenuType; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | public class TopMenuComponent extends BasePage { 11 | 12 | private static final String MENU = "//b[text()='%s']/parent::a"; 13 | private static final By LOGO = By.xpath("//img[@alt='OrangeHRM']"); 14 | private static final By LINK_MARKET_PLACE = By.id("MP_LINK"); 15 | 16 | public TopMenuComponent clickMenuItem(MenuType menuType) { 17 | String xpath = String.format(MENU, menuType); 18 | click(By.xpath(xpath), WaitStrategy.PRESENCE, menuType.toString()); 19 | return this; 20 | } 21 | 22 | public TopMenuComponent clickSubMenuItem(SubMenuType subMenuType) { 23 | String xpath = String.format(MENU, subMenuType); 24 | click(By.xpath(xpath), WaitStrategy.PRESENCE, subMenuType.toString()); 25 | return this; 26 | } 27 | 28 | public String getLogoSourceString() { 29 | return getAttribute(LOGO, e -> e.getAttribute("src")); 30 | } 31 | 32 | public boolean isMarketPlaceLinkPresent() { 33 | return isPresent(LINK_MARKET_PLACE, WebElement::isDisplayed); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/configloader/PropertyUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.configloader; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.automation.enums.ConfigProperties; 5 | import com.automation.exceptions.PropertyFileUsageException; 6 | import com.machinezoo.noexception.Exceptions; 7 | import lombok.AccessLevel; 8 | import lombok.NoArgsConstructor; 9 | import java.io.FileInputStream; 10 | import java.util.Objects; 11 | import java.util.Properties; 12 | 13 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 14 | public final class PropertyUtils { 15 | 16 | private static Properties property; 17 | 18 | // Singleton design pattern 19 | public static Properties getInstance() { 20 | if (property == null) { 21 | property = new Properties(); 22 | } 23 | return property; 24 | } 25 | 26 | static void loadProperties(String propertyFilePath) { 27 | Exceptions.wrap(e -> new PropertyFileUsageException("Exception occurred while loading Property file in the specified path - " + propertyFilePath)) 28 | .run(() -> getInstance().load(new FileInputStream(propertyFilePath))); 29 | } 30 | 31 | public static String get(ConfigProperties key) { 32 | loadProperties(FrameworkConstants.CONFIG_PROPERTIES_FILE_PATH); 33 | if (Objects.isNull(property.getProperty(key.name().toLowerCase()))) { 34 | throw new PropertyFileUsageException("Property name - " + key + " is not found. Please check the config.properties"); 35 | } 36 | return property.getProperty(key.name().toLowerCase()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/resources/chaintest.properties: -------------------------------------------------------------------------------- 1 | # chaintest configuration 2 | chaintest.project.name=default 3 | 4 | # storage 5 | chaintest.storage.service.enabled=false 6 | # [azure-blob, aws-s3] 7 | chaintest.storage.service=azure-blob 8 | # s3 bucket or azure container name 9 | chaintest.storage.service.container-name= 10 | 11 | # generators: 12 | ## chainlp 13 | chaintest.generator.chainlp.enabled=false 14 | chaintest.generator.chainlp.class-name=com.aventstack.chaintest.generator.ChainLPGenerator 15 | chaintest.generator.chainlp.host.url=http://localhost/ 16 | chaintest.generator.chainlp.client.request-timeout-s=30 17 | chaintest.generator.chainlp.client.expect-continue=false 18 | chaintest.generator.chainlp.client.max-retries=3 19 | chaintest.generator.chainlp.persist-embeds=true 20 | 21 | ## simple 22 | chaintest.generator.simple.enabled=true 23 | chaintest.generator.simple.document-title=chaintest 24 | chaintest.generator.simple.class-name=com.aventstack.chaintest.generator.ChainTestSimpleGenerator 25 | chaintest.generator.simple.output-file=target/chaintest/Index.html 26 | chaintest.generator.simple.offline=false 27 | chaintest.generator.simple.dark-theme=true 28 | chaintest.generator.simple.datetime-format=yyyy-MM-dd hh:mm:ss a 29 | chaintest.generator.simple.js= 30 | chaintest.generator.simple.css= 31 | 32 | ## email 33 | chaintest.generator.email.enabled=true 34 | chaintest.generator.email.class-name=com.aventstack.chaintest.generator.ChainTestEmailGenerator 35 | chaintest.generator.email.output-file=target/chaintest/Email.html 36 | chaintest.generator.email.datetime-format=yyyy-MM-dd hh:mm:ss a -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/AddUsersPredicateFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm; 2 | 3 | import com.automation.fixtures.addusers.entity.UserData; 4 | import com.automation.pages.orangehrm.pagecomponents.adduserspage.AddUserComponent; 5 | import java.util.Map; 6 | import java.util.function.BiPredicate; 7 | 8 | public class AddUsersPredicateFactory { 9 | 10 | private static final BiPredicate VALID_PREDICATE = (userData, addUserComponent) -> { 11 | addUserComponent.setUserRoleDropDown(userData.getUserRole()) 12 | .setUserNameTextBox(userData.getUserName()) 13 | .setPasswordTextBox(userData.getPassword()) 14 | .setConfirmPasswordTextBox(userData.getPassword()) 15 | .setStatusDropDown(userData.getStatus()) 16 | .setEmployeeNameTextBox(userData.getEmployeeName()); 17 | return addUserComponent.isSuccessMessageDisplayed(); 18 | }; 19 | 20 | private static final BiPredicate JUST_EMPLOYEE_NAME_PREDICATE = (userData, addUserComponent) -> { 21 | addUserComponent.setEmployeeNameTextBox(userData.getEmployeeName()); 22 | return addUserComponent.isErrorDisplayedForEmployeeName(); 23 | }; 24 | 25 | private static final Map> MAP = Map.of( 26 | "valid", VALID_PREDICATE, 27 | "just_employee_name", JUST_EMPLOYEE_NAME_PREDICATE 28 | ); 29 | 30 | public static BiPredicate getPredicate(String value){ 31 | return MAP.get(value); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/automation/driver/Driver.java: -------------------------------------------------------------------------------- 1 | package com.automation.driver; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import com.automation.driver.entity.DriverData; 5 | import com.automation.driver.manager.DriverManager; 6 | import com.automation.enums.BrowserType; 7 | import com.automation.driver.factory.DriverFactory; 8 | import lombok.AccessLevel; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.util.Objects; 12 | 13 | /** 14 | * Driver class is responsible for invoking and closing the browsers. 15 | *

16 | * It is also responsible for setting the driver variable to DriverManager which handles the thread safety for the webdriver instance. 17 | * 18 | * @author Administrator 19 | */ 20 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 21 | public final class Driver { 22 | 23 | public static void initDriver(BrowserType browser) { 24 | DriverData driverData = DriverData.builder() 25 | .browserType(browser) 26 | .browserRemoteModeType(ConfigFactory.getConfig().remote_mode()) 27 | .build(); 28 | 29 | if (Objects.isNull(DriverManager.getDriver())) { 30 | DriverManager.setDriver(DriverFactory 31 | .getDriver(ConfigFactory.getConfig().run_mode()) 32 | .getDriver(driverData)); 33 | } 34 | DriverManager.getDriver().get(ConfigFactory.getConfig().url()); 35 | DriverManager.getDriver().manage().window().maximize(); 36 | } 37 | 38 | public static void quitDriver() { 39 | if (Objects.nonNull(DriverManager.getDriver())) { 40 | DriverManager.getDriver().quit(); 41 | DriverManager.unload(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/HomePageAssert.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm; 2 | 3 | import com.automation.pages.orangehrm.validator.HomePageValidator; 4 | import org.assertj.core.api.AbstractAssert; 5 | import org.assertj.core.api.SoftAssertions; 6 | 7 | public class HomePageAssert extends AbstractAssert { 8 | 9 | private final SoftAssertions softAssertions; 10 | 11 | private HomePageAssert(HomePageValidator homePageValidator) { 12 | super(homePageValidator, HomePageAssert.class); 13 | softAssertions = new SoftAssertions(); 14 | } 15 | 16 | public static HomePageAssert assertThat(HomePageValidator homePageValidator) { 17 | return new HomePageAssert(homePageValidator); 18 | } 19 | 20 | public HomePageAssert headerNameEquals(String expectedHeaderName) { 21 | String actualHeaderName = actual.getHeaderName(); 22 | softAssertions.assertThat(actualHeaderName) 23 | .isEqualTo(expectedHeaderName); 24 | return this; 25 | } 26 | 27 | public HomePageAssert logoSourceStringContains(String expectedLogoSourceString) { 28 | String actualLogoSourceText = actual.getLogoSourceText(); 29 | softAssertions.assertThat(actualLogoSourceText) 30 | .isEqualTo(expectedLogoSourceString); 31 | return this; 32 | } 33 | 34 | public HomePageAssert isMarketPlaceLinkPresent() { 35 | softAssertions.assertThat(actual.isMarketPlaceLinkPresent()) 36 | .withFailMessage(()->"Market Place link not present") 37 | .isTrue(); 38 | return this; 39 | } 40 | 41 | public void assertAll() { 42 | softAssertions.assertAll(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/dataprovider/DataProviderUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.dataprovider; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.automation.utils.zerocell.ExcelReader; 5 | import lombok.AccessLevel; 6 | import lombok.NoArgsConstructor; 7 | import org.testng.annotations.DataProvider; 8 | import java.lang.reflect.Method; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.function.Predicate; 13 | 14 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 15 | public final class DataProviderUtils { 16 | 17 | private static List> list = new ArrayList<>(); 18 | 19 | @DataProvider 20 | public static Object[] getData(Method method) { 21 | String testName = method.getName(); 22 | if (list.isEmpty()) { 23 | list = ExcelUtils.getTestDetails(FrameworkConstants.DATA_SHEET); 24 | } 25 | List> smallList = new ArrayList<>(list); 26 | 27 | Predicate> isTestNameNotMatching = map -> !map.get("TestName").equalsIgnoreCase(testName); 28 | Predicate> isExecuteColumnNo = map -> map.get("Execute").equalsIgnoreCase("no"); 29 | smallList.removeIf(isTestNameNotMatching.or(isExecuteColumnNo)); 30 | 31 | return smallList.toArray(); 32 | } 33 | 34 | @DataProvider 35 | public static Object[] getDataUsingZeroCell(Method method) { 36 | 37 | return ExcelReader.getTestDataList() 38 | .stream() 39 | .filter(map -> map.getTestName().equalsIgnoreCase(method.getName())) 40 | .filter(map -> map.getExecute().equalsIgnoreCase("yes")) 41 | .toArray(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/HomePage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm; 2 | 3 | import com.automation.pages.base.BasePage; 4 | import com.automation.pages.orangehrm.enums.topmenucomponent.MenuType; 5 | import com.automation.pages.orangehrm.enums.topmenucomponent.SubMenuType; 6 | import com.automation.pages.orangehrm.pagecomponents.homepage.TopMenuComponent; 7 | import com.automation.pages.orangehrm.validator.HomePageValidator; 8 | import lombok.Getter; 9 | import org.openqa.selenium.By; 10 | import com.automation.enums.WaitStrategy; 11 | import org.openqa.selenium.WebElement; 12 | 13 | public final class HomePage extends BasePage { 14 | 15 | private final By linkWelcome = By.id("welcome"); 16 | private final By linkLogout = By.xpath("//a[text()='Logout']"); 17 | private static final By HEADER = By.xpath("//h1"); 18 | 19 | @Getter 20 | private final TopMenuComponent topMenuComponent; 21 | 22 | public HomePage() { 23 | this.topMenuComponent = new TopMenuComponent(); 24 | } 25 | 26 | public SystemUsersPage navigateToSystemUsersPage() { 27 | topMenuComponent.clickMenuItem(MenuType.ADMIN) 28 | .clickSubMenuItem(SubMenuType.USER_MANAGEMENT) 29 | .clickSubMenuItem(SubMenuType.USERS); 30 | 31 | return new SystemUsersPage(); 32 | } 33 | 34 | public HomePageValidator getHomePageValidator() { 35 | return HomePageValidator.builder() 36 | .isMarketPlaceLinkPresent(topMenuComponent.isMarketPlaceLinkPresent()) 37 | .logoSourceText(topMenuComponent.getLogoSourceString()) 38 | .headerName(getAttribute(HEADER, WebElement::getText)) 39 | .build(); 40 | } 41 | 42 | public HomePage clickWelcome() { 43 | click(linkWelcome, WaitStrategy.PRESENCE, "Welcome link"); 44 | return this; 45 | } 46 | 47 | public LoginPage clickLogout() { 48 | click(linkLogout, WaitStrategy.CLICKABLE, "Logout button"); 49 | return new LoginPage(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/automation/config/FrameworkConfig.java: -------------------------------------------------------------------------------- 1 | package com.automation.config; 2 | 3 | import com.automation.config.converter.StringToBrowserRemoteModeTypeConverter; 4 | import com.automation.config.converter.StringToRunTypeConverter; 5 | import com.automation.config.converter.StringToUrlConverter; 6 | import com.automation.enums.BrowserRemoteModeType; 7 | import com.automation.enums.RunType; 8 | import org.aeonbits.owner.Config; 9 | import java.net.URL; 10 | 11 | @Config.LoadPolicy(Config.LoadType.MERGE) // Search for the provided key from any of the file and system variable mentioned in Config.Sources 12 | @Config.Sources({ 13 | "system:properties", 14 | "system:env", 15 | "file:${user.dir}/src/test/resources/config/config.properties", 16 | "file:${user.dir}/src/test/resources/config/dev-config.properties", 17 | "file:${user.dir}/src/test/resources/config/staging-config.properties", 18 | "file:${user.dir}/src/test/resources/config/${myConfig}.properties" 19 | }) 20 | public interface FrameworkConfig extends Config { 21 | 22 | @DefaultValue("staging") 23 | String environment(); 24 | 25 | @Key("${environment}.url") 26 | String url(); 27 | 28 | String override_report(); 29 | 30 | boolean passed_step_screenshots(); 31 | 32 | boolean failed_step_screenshots(); 33 | 34 | boolean skipped_step_screenshots(); 35 | 36 | boolean retry_failed_tests(); 37 | 38 | int retry_count(); 39 | 40 | @DefaultValue("LOCAL") 41 | @ConverterClass(StringToRunTypeConverter.class) 42 | RunType run_mode(); 43 | 44 | @DefaultValue("SELENOID") 45 | @ConverterClass(StringToBrowserRemoteModeTypeConverter.class) 46 | BrowserRemoteModeType remote_mode(); 47 | 48 | @ConverterClass(StringToUrlConverter.class) 49 | URL seleniumGridUrl(); 50 | 51 | @ConverterClass(StringToUrlConverter.class) 52 | URL selenoidUrl(); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/automation/utils/dataprovider/ExcelUtils.java: -------------------------------------------------------------------------------- 1 | package com.automation.utils.dataprovider; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.automation.exceptions.FrameworkException; 5 | import com.automation.exceptions.InvalidPathForFilesException; 6 | import lombok.AccessLevel; 7 | import lombok.NoArgsConstructor; 8 | import org.apache.poi.xssf.usermodel.XSSFSheet; 9 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 19 | public final class ExcelUtils { 20 | 21 | public static List> getTestDetails(String sheetName) { 22 | List> list; 23 | 24 | try (FileInputStream fs = new FileInputStream(FrameworkConstants.TEST_DATA_EXCEL_PATH)) { 25 | XSSFWorkbook workbook = new XSSFWorkbook(fs); 26 | XSSFSheet sheet = workbook.getSheet(sheetName); 27 | 28 | int lastRowNum = sheet.getLastRowNum(); 29 | int lastColNum = sheet.getRow(0).getLastCellNum(); 30 | 31 | Map map; 32 | list = new ArrayList<>(); 33 | 34 | for (int i = 1; i <= lastRowNum; i++) { 35 | map = new HashMap<>(); 36 | for (int j = 0; j < lastColNum; j++) { 37 | String key = sheet.getRow(0).getCell(j).getStringCellValue(); 38 | String value = sheet.getRow(i).getCell(j).getStringCellValue(); 39 | map.put(key, value); 40 | } 41 | list.add(map); 42 | } 43 | } catch (FileNotFoundException e) { 44 | throw new InvalidPathForFilesException("Excel File you trying to read is not found"); 45 | } catch (IOException e) { 46 | throw new FrameworkException("IOException happened while reading excel file"); 47 | } 48 | return list; 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/com/automation/constants/FrameworkConstants.java: -------------------------------------------------------------------------------- 1 | package com.automation.constants; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * Holds all the constant values used within the framework. 11 | * If some value needs to be changed often, then it should be stored in the property files 12 | * 13 | * @author Administrator 14 | */ 15 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 16 | public final class FrameworkConstants { 17 | 18 | public static final String PROJECT_PATH = System.getProperty("user.dir"); 19 | 20 | public static final int EXPLICIT_WAIT = 10; 21 | public static final String RESOURCES_PATH = PROJECT_PATH + File.separator + "src/test/resources"; 22 | public static final String CONFIG_PROPERTIES_FILE_PATH = RESOURCES_PATH + File.separator + "config/config.properties"; 23 | public static final String JSON_CONFIG_FILE_PATH = RESOURCES_PATH + File.separator + "config" + File.separator + "config.json"; 24 | public static final String EXTENT_REPORTS_FOLDER_PATH = PROJECT_PATH + File.separator + "extent-test-output/"; 25 | public static final String TEST_DATA_EXCEL_PATH = RESOURCES_PATH + File.separator + "data" + File.separator + "testdata.xlsx"; 26 | public static final String RUN_MANAGER_SHEET = "RUNMANAGER"; 27 | public static final String DATA_SHEET = "DATA"; 28 | public static final String SCREENSHOT_PATH = PROJECT_PATH + File.separator + "screenshots"; 29 | 30 | private static String extentReportFilePath = ""; 31 | 32 | public static String getExtentReportFilePath() { 33 | if (extentReportFilePath.isEmpty()) { 34 | extentReportFilePath = createReportPath(); 35 | } 36 | return extentReportFilePath; 37 | } 38 | 39 | private static String createReportPath() { 40 | if (ConfigFactory.getConfig().override_report().equalsIgnoreCase("no")) { 41 | return EXTENT_REPORTS_FOLDER_PATH + File.separator + System.currentTimeMillis() + File.separator + "index.html"; 42 | } else { 43 | return EXTENT_REPORTS_FOLDER_PATH + File.separator + "index.html"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/automation/listeners/CustomListener.java: -------------------------------------------------------------------------------- 1 | package com.automation.listeners; 2 | 3 | import com.automation.annotations.FrameworkAnnotation; 4 | import com.automation.driver.manager.DriverManager; 5 | import com.automation.reports.ExtentLogger; 6 | import com.automation.reports.ExtentReport; 7 | import org.testng.*; 8 | 9 | public class CustomListener implements ITestListener, ISuiteListener { 10 | 11 | private static final String TEST = "Test - "; 12 | 13 | @Override 14 | public void onStart(ISuite suite) { 15 | ExtentReport.initReports(); 16 | } 17 | 18 | @Override 19 | public void onFinish(ISuite suite) { 20 | ExtentReport.flushReports(); 21 | } 22 | 23 | @Override 24 | public void onTestStart(ITestResult result) { 25 | ExtentReport.createTest(result.getMethod().getDescription()); 26 | ExtentReport.addAuthors(result.getMethod().getConstructorOrMethod().getMethod() 27 | .getAnnotation(FrameworkAnnotation.class).author()); 28 | ExtentReport.addCategories(result.getMethod().getConstructorOrMethod().getMethod() 29 | .getAnnotation(FrameworkAnnotation.class).category()); 30 | ExtentReport.addBrowsers(); 31 | ExtentLogger.info(ExtentReport.getBrowserDetails(DriverManager.getDriver())); 32 | ExtentLogger.pass(TEST + result.getMethod().getMethodName() + " is started"); 33 | } 34 | 35 | @Override 36 | public void onTestSuccess(ITestResult result) { 37 | ExtentLogger.pass(TEST + result.getMethod().getMethodName() + " is passed"); 38 | } 39 | 40 | @Override 41 | public void onTestFailure(ITestResult result) { 42 | ExtentLogger.fail(TEST + result.getMethod().getMethodName() + " is failed", result.getThrowable()); 43 | } 44 | 45 | @Override 46 | public void onTestSkipped(ITestResult result) { 47 | ExtentLogger.skip(TEST + result.getMethod().getMethodName() + " is skipped"); 48 | } 49 | 50 | @Override 51 | public void onTestFailedButWithinSuccessPercentage(ITestResult result) { 52 | 53 | } 54 | 55 | @Override 56 | public void onStart(ITestContext context) { 57 | 58 | } 59 | 60 | @Override 61 | public void onFinish(ITestContext context) { 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/automation/reports/ExtentLogger.java: -------------------------------------------------------------------------------- 1 | package com.automation.reports; 2 | 3 | import com.automation.config.ConfigFactory; 4 | import com.automation.utils.screenshot.ScreenshotService; 5 | import com.aventstack.chaintest.plugins.ChainTestListener; 6 | import com.aventstack.extentreports.MediaEntityBuilder; 7 | import com.aventstack.extentreports.Status; 8 | import com.aventstack.extentreports.markuputils.ExtentColor; 9 | import com.aventstack.extentreports.markuputils.MarkupHelper; 10 | import lombok.AccessLevel; 11 | import lombok.NoArgsConstructor; 12 | 13 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 14 | public final class ExtentLogger { 15 | 16 | public static void pass(String message) { 17 | if (ConfigFactory.getConfig().passed_step_screenshots()) { 18 | ExtentManager.getExtentTest().pass(message, 19 | MediaEntityBuilder.createScreenCaptureFromBase64String(ScreenshotService.getScreenshotAsBase64()).build()); 20 | } else { 21 | ExtentManager.getExtentTest().pass(MarkupHelper.createLabel(message, ExtentColor.GREEN)); 22 | } 23 | } 24 | 25 | public static void fail(String message, Throwable t) { 26 | if (ConfigFactory.getConfig().failed_step_screenshots()) { 27 | ExtentManager.getExtentTest().fail(MarkupHelper.createLabel(message, ExtentColor.RED)) 28 | .fail(MediaEntityBuilder.createScreenCaptureFromBase64String(ScreenshotService.getScreenshotAsBase64()).build()) 29 | .fail(t); 30 | ChainTestListener.embed(ScreenshotService.getScreenshotAsBase64(), "image/png"); 31 | } else { 32 | ExtentManager.getExtentTest().fail(message).fail(t); 33 | } 34 | } 35 | 36 | public static void skip(String message) { 37 | if (ConfigFactory.getConfig().skipped_step_screenshots()) { 38 | ExtentManager.getExtentTest().skip(message, 39 | MediaEntityBuilder.createScreenCaptureFromBase64String(ScreenshotService.getScreenshotAsBase64()).build()); 40 | } else { 41 | ExtentManager.getExtentTest().log(Status.SKIP, message); 42 | } 43 | } 44 | 45 | public static void info(String message) { 46 | 47 | ExtentManager.getExtentTest().info("" + message + ""); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/automation/factories/WaitFactory.java: -------------------------------------------------------------------------------- 1 | package com.automation.factories; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import org.openqa.selenium.By; 7 | import org.openqa.selenium.WebElement; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | import org.openqa.selenium.support.ui.WebDriverWait; 10 | 11 | import com.automation.driver.manager.DriverManager; 12 | import com.automation.enums.WaitStrategy; 13 | 14 | import java.time.Duration; 15 | import java.util.EnumMap; 16 | import java.util.Map; 17 | import java.util.function.Function; 18 | 19 | import static com.automation.enums.WaitStrategy.*; 20 | 21 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 22 | public final class WaitFactory { 23 | 24 | private static final Map> WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP = 25 | new EnumMap<>(WaitStrategy.class); 26 | 27 | private static final Function CLICKABLE_ELEMENT_BY = by -> 28 | new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(FrameworkConstants.EXPLICIT_WAIT)) 29 | .until(ExpectedConditions.elementToBeClickable(by)); 30 | private static final Function PRESENCE_OF_ELEMENT_BY = by -> 31 | new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(FrameworkConstants.EXPLICIT_WAIT)) 32 | .until(ExpectedConditions.presenceOfElementLocated(by)); 33 | private static final Function VISIBILITY_OF_ELEMENT_BY = by -> 34 | new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(FrameworkConstants.EXPLICIT_WAIT)) 35 | .until(ExpectedConditions.visibilityOfElementLocated(by)); 36 | private static final Function NO_MATCH_BY = by -> DriverManager.getDriver().findElement(by); 37 | 38 | static { 39 | WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP.put(CLICKABLE, CLICKABLE_ELEMENT_BY); 40 | WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP.put(PRESENCE, PRESENCE_OF_ELEMENT_BY); 41 | WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP.put(VISIBLE, VISIBILITY_OF_ELEMENT_BY); 42 | WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP.put(NONE, NO_MATCH_BY); 43 | } 44 | 45 | public static WebElement performExplicitWait(WaitStrategy waitstrategy, By by) { 46 | return WAIT_FOR_ELEMENT_LOCATED_BY_FUNCTION_MAP.get(waitstrategy).apply(by); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/automation/tests/OrangeHRMTests.java: -------------------------------------------------------------------------------- 1 | package com.automation.tests; 2 | 3 | import br.com.six2six.fixturefactory.loader.FixtureFactoryLoader; 4 | import com.automation.annotations.FrameworkAnnotation; 5 | import com.automation.base.BaseTest; 6 | import com.automation.constants.StringConstants; 7 | import com.automation.enums.Authors; 8 | import com.automation.enums.CategoryType; 9 | import com.automation.pages.orangehrm.HomePageAssert; 10 | import com.automation.pages.orangehrm.LoginPage; 11 | import com.automation.pages.orangehrm.enums.AddUsersScenarioType; 12 | import com.automation.pages.orangehrm.validator.HomePageValidator; 13 | import io.github.sskorol.core.DataSupplier; 14 | import lombok.AccessLevel; 15 | import lombok.NoArgsConstructor; 16 | import org.assertj.core.api.Assertions; 17 | import org.testng.annotations.Test; 18 | 19 | import java.util.Map; 20 | import java.util.stream.Stream; 21 | 22 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 23 | public final class OrangeHRMTests extends BaseTest { 24 | 25 | @Test 26 | @FrameworkAnnotation(author = {Authors.USER_1, Authors.USER_2}, 27 | category = {CategoryType.REGRESSION, CategoryType.SANITY}) 28 | public void loginLogoutTest(Map data) { 29 | String title = new LoginPage() 30 | .loginToApplication(data.get("username"), data.get("password")) 31 | .clickWelcome() 32 | .clickLogout() 33 | .getTitle(); 34 | 35 | Assertions.assertThat(title).isEqualTo(StringConstants.ORANGEHRM_PAGE_TITLE); 36 | } 37 | 38 | @DataSupplier(runInParallel = true) 39 | public Stream getData() { 40 | FixtureFactoryLoader.loadTemplates("com.automation.fixtures.addusers"); 41 | return Stream.of(AddUsersScenarioType.values()); 42 | } 43 | 44 | @Test(dataProvider = "getData", enabled = false) 45 | @FrameworkAnnotation(author = {Authors.USER_1, Authors.USER_2}, 46 | category = {CategoryType.REGRESSION, CategoryType.SANITY}) 47 | public void testAddUsers(AddUsersScenarioType addUsersScenarioType) { 48 | boolean isMsgDisplayed = new LoginPage() 49 | .loginToApplication("Admin", "admin123") 50 | .navigateToSystemUsersPage() 51 | .getUserListComponent() 52 | .setAddButton() 53 | .fillDetails(addUsersScenarioType.getUserData(), addUsersScenarioType.getPredicate()); 54 | 55 | Assertions.assertThat(isMsgDisplayed) 56 | .withFailMessage(() -> addUsersScenarioType.getUserData().getMessage()) 57 | .isTrue(); 58 | } 59 | 60 | @Test 61 | @FrameworkAnnotation(author = {Authors.USER_1, Authors.USER_2}, 62 | category = {CategoryType.REGRESSION, CategoryType.SANITY}) 63 | public void testHomePageComponents() { 64 | HomePageValidator homePageValidator = new LoginPage() 65 | .loginToApplication("Admin", "admin123") 66 | .getHomePageValidator(); 67 | 68 | HomePageAssert.assertThat(homePageValidator) 69 | .isMarketPlaceLinkPresent() 70 | .headerNameEquals("Dashboard") 71 | .logoSourceStringContains("/images/logo.png") 72 | .assertAll(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/orangehrm/pagecomponents/adduserspage/AddUserComponent.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.orangehrm.pagecomponents.adduserspage; 2 | 3 | import com.automation.driver.manager.DriverManager; 4 | import com.automation.enums.WaitStrategy; 5 | import com.automation.fixtures.addusers.entity.UserData; 6 | import com.automation.pages.base.BasePage; 7 | import org.openqa.selenium.By; 8 | 9 | import java.util.function.BiPredicate; 10 | 11 | public class AddUserComponent extends BasePage { 12 | 13 | private static final By DROP_DOWN_USER_ROLE = By.xpath("//label[text()='User Role']/following-sibling::select"); 14 | private static final By DROP_DOWN_STATUS = By.xpath("//label[text()='Status']/following-sibling::select"); 15 | private static final By TEXT_BOX_EMPLOYEE_NAME = By.xpath("//label[text()='Employee Name']/following-sibling::input"); 16 | private static final By TEXT_BOX_USER_NAME = By.xpath("//label[text()='Username']/following-sibling::input"); 17 | private static final By TEXT_BOX_PASSWORD = By.xpath("//label[text()='Password']/following-sibling::input"); 18 | private static final By TEXT_BOX_CONFIRM_PASSWORD = By.xpath("//label[text()='Confirm Password']/following-sibling::input"); 19 | private static final By ERROR_MESSAGE_FOR_EMPLOYEE_NAME = By.xpath("//span[@for='systemUser_employeeName_empName']"); 20 | 21 | public AddUserComponent setUserRoleDropDown(String userRole) { 22 | select(DROP_DOWN_USER_ROLE, e -> e.selectByVisibleText(userRole)); 23 | return this; 24 | } 25 | 26 | public AddUserComponent setStatusDropDown(String status) { 27 | select(DROP_DOWN_STATUS, e -> e.selectByVisibleText(status)); 28 | return this; 29 | } 30 | 31 | public AddUserComponent setEmployeeNameTextBox(String employeeName) { 32 | sendKeys(TEXT_BOX_EMPLOYEE_NAME, employeeName, WaitStrategy.VISIBLE, "Employee name"); 33 | return this; 34 | } 35 | 36 | public AddUserComponent setUserNameTextBox(String userName) { 37 | sendKeys(TEXT_BOX_USER_NAME, userName, WaitStrategy.VISIBLE, "Username"); 38 | return this; 39 | } 40 | 41 | public AddUserComponent setPasswordTextBox(String password) { 42 | sendKeys(TEXT_BOX_PASSWORD, password, WaitStrategy.VISIBLE, "Password"); 43 | return this; 44 | } 45 | 46 | public AddUserComponent setConfirmPasswordTextBox(String password) { 47 | sendKeys(TEXT_BOX_CONFIRM_PASSWORD, password, WaitStrategy.VISIBLE, "Confirm Password"); 48 | return this; 49 | } 50 | 51 | public boolean isErrorDisplayedForEmployeeName() { 52 | return DriverManager.getDriver().findElement(ERROR_MESSAGE_FOR_EMPLOYEE_NAME).getText() 53 | .equalsIgnoreCase("Employee does not exist"); 54 | } 55 | 56 | public boolean isSuccessMessageDisplayed() { 57 | return true; 58 | } 59 | 60 | public boolean fillDetails(UserData userData, BiPredicate predicate) { 61 | // setUserNameTextBox(userData.getUserName()) 62 | // .setPasswordTextBox(userData.getPassword()) 63 | // .setConfirmPasswordTextBox(userData.getPassword()) 64 | // .setStatusDropDown(userData.getStatus()) 65 | // .setEmployeeNameTextBox(userData.getEmployeeName()); 66 | 67 | return predicate.test(userData, this); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Selenium - Web Automation Framework 2 | Test automation framework for web applications using Selenium 4 and Java 3 | 4 | ![WebDriver-W3C-Protocol-1](https://user-images.githubusercontent.com/48508827/155773516-432123c9-a3fe-40d0-8c95-1aaea1c7ec91.png) 5 | 6 | ## :rocket: Quick Start 7 | 1) Install [Java JDK 21](https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html) 8 | 2) Download [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) 9 | 3) Download [Docker Desktop](https://docs.docker.com/desktop/windows/install/) 10 | 11 | ## :pushpin: Tech stack 12 | 13 | java 14 | 15 | selenium 16 | 17 | testng 18 | 19 | jenkins 20 | 21 | docker 22 | 23 | ## :pushpin: Running tests through testng xml 24 | :point_right: Create or Select the required testng xml -> Right click and select Run 25 | 26 | ## :pushpin: Running tests through Maven 27 | :point_right: Run test using command `mvn test -DsuiteXmlFile=` 28 | 29 | ## :pushpin: Key Features 30 | :point_right: Supports cross browser testing in local and remote. 31 | 32 | :point_right: Ability to execute tests in Selenium Grid or Selenoid using Docker. 33 | 34 | :point_right: Page object model design. 35 | 36 | :point_right: Supports parallel and sequential execution of tests. 37 | 38 | :point_right: Supports capturing screenshots for passed/failed/skipped steps which is configurable through `config.properties` 39 | 40 | :point_right: Ability to retry failed tests which is configurable through `config.properties` 41 | 42 | :point_right: Customised exception handling to provide the exceptions in a meaningful way. 43 | 44 | :point_right: Custom framework annotation to provide author name and category for each test. 45 | 46 | :point_right: Supports utilities to read test data from excel workbook and provides data to each test based on the test name. 47 | 48 | :point_right: Ability to configure and schedule jenkins job to build triggers automatically 49 | 50 | ## :rocket: Selenoid Quick Start Guide 51 | [Click here for Selenoid Quick Start Guide](https://aerokube.com/selenoid/latest/) 52 | 53 | ## Docker commands 54 | 55 | ### To Run Elasticsearch 56 | ``` 57 | docker run -p 9200:9200 -p 9300:9300 --name elasticsearch -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.11.1 58 | ``` 59 | 60 | ### To Run Kibana 61 | ``` 62 | docker run -p 5601:5601 --name kibana --link elasticsearch:elasticsearch docker.elastic.co/kibana/kibana:7.11.1 63 | ``` 64 | 65 | ### Credits 66 | This framework is built by following [Testing Mini Bytes](https://www.youtube.com/playlist?list=PL9ok7C7Yn9A_JZFMrhrgEwfqQGiuyvSkB) YouTube channel. -------------------------------------------------------------------------------- /src/main/java/com/automation/reports/ExtentReport.java: -------------------------------------------------------------------------------- 1 | package com.automation.reports; 2 | 3 | import com.automation.constants.FrameworkConstants; 4 | import com.automation.driver.manager.DriverManager; 5 | import com.automation.enums.Authors; 6 | import com.automation.enums.CategoryType; 7 | import com.automation.exceptions.ReportInitializationFailedException; 8 | import com.aventstack.extentreports.ExtentReports; 9 | import com.aventstack.extentreports.reporter.ExtentSparkReporter; 10 | import com.aventstack.extentreports.reporter.configuration.Theme; 11 | import lombok.AccessLevel; 12 | import lombok.NoArgsConstructor; 13 | import org.openqa.selenium.WebDriver; 14 | import org.openqa.selenium.remote.RemoteWebDriver; 15 | import java.awt.*; 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.net.InetAddress; 19 | import java.util.Objects; 20 | 21 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 22 | public final class ExtentReport { 23 | 24 | private static ExtentReports extentReports; 25 | private static final ExtentSparkReporter extentSparkReporter = new ExtentSparkReporter(FrameworkConstants.EXTENT_REPORTS_FOLDER_PATH); 26 | 27 | public static void initReports() { 28 | try { 29 | if (Objects.isNull(extentReports)) { 30 | extentReports = new ExtentReports(); 31 | extentReports.attachReporter(extentSparkReporter); 32 | InetAddress ip = InetAddress.getLocalHost(); 33 | String hostname = ip.getHostName(); 34 | extentReports.setSystemInfo("Host Name", hostname); 35 | extentReports.setSystemInfo("Environment", "Web Automation - Selenium"); 36 | extentReports.setSystemInfo("User Name", System.getProperty("user.name")); 37 | extentSparkReporter.config().setDocumentTitle("HTML Report"); 38 | extentSparkReporter.config().setReportName("Web Automation Testing"); 39 | extentSparkReporter.config().setTheme(Theme.DARK); 40 | } 41 | } catch (Exception e) { 42 | throw new ReportInitializationFailedException("Failed to initialize extent report", e); 43 | } 44 | } 45 | 46 | public static void flushReports() { 47 | if (Objects.nonNull(extentReports)) { 48 | extentReports.flush(); 49 | } 50 | ExtentManager.unload(); 51 | try { 52 | Desktop.getDesktop().browse(new File(FrameworkConstants.getExtentReportFilePath()).toURI()); 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | public static void createTest(String testName) { 59 | ExtentManager.setExtentTest(extentReports.createTest(testName)); 60 | } 61 | 62 | public static void addAuthors(Authors[] authors) { 63 | for (Authors author : authors) { 64 | ExtentManager.getExtentTest().assignAuthor(author.toString()); 65 | } 66 | } 67 | 68 | public static void addCategories(CategoryType[] categories) { 69 | for (CategoryType categoryType : categories) { 70 | ExtentManager.getExtentTest().assignCategory(categoryType.toString()); 71 | } 72 | } 73 | 74 | public static void addBrowsers() { 75 | ExtentManager.getExtentTest().assignDevice(getBrowserDetails(DriverManager.getDriver())); 76 | } 77 | 78 | public static String getBrowserDetails(WebDriver driver) { 79 | String browserName = ((RemoteWebDriver) driver).getCapabilities().getBrowserName().toUpperCase(); 80 | String browserVersion = ((RemoteWebDriver) driver).getCapabilities().getBrowserVersion(); 81 | 82 | return browserName + " - " + browserVersion; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/automation/pages/base/BasePage.java: -------------------------------------------------------------------------------- 1 | package com.automation.pages.base; 2 | 3 | import com.automation.driver.manager.DriverManager; 4 | import com.automation.enums.WaitStrategy; 5 | import com.automation.factories.WaitFactory; 6 | import com.automation.reports.ExtentLogger; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.JavascriptExecutor; 9 | import org.openqa.selenium.Keys; 10 | import org.openqa.selenium.WebElement; 11 | import org.openqa.selenium.support.PageFactory; 12 | import org.openqa.selenium.support.ui.Select; 13 | 14 | import java.util.List; 15 | import java.util.function.Consumer; 16 | import java.util.function.Function; 17 | import java.util.function.Predicate; 18 | 19 | public class BasePage { 20 | 21 | protected BasePage() { 22 | PageFactory.initElements(DriverManager.getDriver(), this); 23 | } 24 | 25 | protected void click(By by, WaitStrategy waitstrategy, String elementName) { 26 | WaitFactory.performExplicitWait(waitstrategy, by).click(); 27 | ExtentLogger.pass(elementName + " is clicked"); 28 | } 29 | 30 | protected void sendKeys(By by, String value, WaitStrategy waitstrategy, String elementName) { 31 | WaitFactory.performExplicitWait(waitstrategy, by).sendKeys(value); 32 | ExtentLogger.pass(value + " is entered successfully in " + elementName); 33 | } 34 | 35 | protected void sendKeysAndPressEnter(By by, String value, WaitStrategy waitstrategy, String elementName) { 36 | try { 37 | WaitFactory.performExplicitWait(waitstrategy, by) 38 | .sendKeys(value, Keys.ENTER); 39 | ExtentLogger.pass("Entered value - " + value + " in the field " + elementName + " and pressed enter"); 40 | } catch (Exception e) { 41 | ExtentLogger.fail("Exception caught while entering value", e); 42 | } 43 | } 44 | 45 | protected String getPageTitle() { 46 | return DriverManager.getDriver().getTitle(); 47 | } 48 | 49 | protected void select(By by, Consumer