├── .gitignore ├── LICENSE ├── README.md ├── docker-compose.yaml ├── pom.xml ├── src ├── main │ ├── java │ │ └── com │ │ │ └── automation │ │ │ ├── annotations │ │ │ └── FrameworkAnnotation.java │ │ │ ├── config │ │ │ ├── ConfigFactory.java │ │ │ ├── FrameworkConfig.java │ │ │ └── converter │ │ │ │ ├── StringToBrowserRemoteModeTypeConverter.java │ │ │ │ ├── StringToRunTypeConverter.java │ │ │ │ └── StringToUrlConverter.java │ │ │ ├── constants │ │ │ ├── FrameworkConstants.java │ │ │ └── StringConstants.java │ │ │ ├── driver │ │ │ ├── Driver.java │ │ │ ├── abstraction │ │ │ │ └── IDriver.java │ │ │ ├── entity │ │ │ │ └── DriverData.java │ │ │ ├── factory │ │ │ │ ├── DriverFactory.java │ │ │ │ ├── local │ │ │ │ │ ├── LocalDriverFactory.java │ │ │ │ │ └── LocalDriverImpl.java │ │ │ │ └── remote │ │ │ │ │ ├── RemoteDriverFactory.java │ │ │ │ │ ├── RemoteDriverImpl.java │ │ │ │ │ ├── SeleniumGridFactory.java │ │ │ │ │ └── SelenoidFactory.java │ │ │ └── manager │ │ │ │ ├── DriverManager.java │ │ │ │ ├── local │ │ │ │ ├── ChromeManager.java │ │ │ │ ├── EdgeManager.java │ │ │ │ └── FirefoxManager.java │ │ │ │ └── remote │ │ │ │ ├── seleniumgrid │ │ │ │ ├── SeleniumGridChromeManager.java │ │ │ │ ├── SeleniumGridEdgeManager.java │ │ │ │ └── SeleniumGridFirefoxManager.java │ │ │ │ └── selenoid │ │ │ │ ├── SelenoidChromeManager.java │ │ │ │ └── SelenoidFirefoxManager.java │ │ │ ├── enums │ │ │ ├── Authors.java │ │ │ ├── BrowserRemoteModeType.java │ │ │ ├── BrowserType.java │ │ │ ├── CategoryType.java │ │ │ ├── ConfigJson.java │ │ │ ├── ConfigProperties.java │ │ │ ├── RunType.java │ │ │ └── WaitStrategy.java │ │ │ ├── exceptions │ │ │ ├── BrowserInvocationFailedException.java │ │ │ ├── DriverInitializationFailedException.java │ │ │ ├── FrameworkException.java │ │ │ ├── InvalidPathForFilesException.java │ │ │ ├── JsonFileUsageException.java │ │ │ ├── PropertyFileUsageException.java │ │ │ └── ReportInitializationFailedException.java │ │ │ ├── factories │ │ │ └── WaitFactory.java │ │ │ ├── fixtures │ │ │ └── addusers │ │ │ │ ├── entity │ │ │ │ └── UserData.java │ │ │ │ └── templates │ │ │ │ └── AddUserTemplate.java │ │ │ ├── listeners │ │ │ ├── AnnotationTransformer.java │ │ │ ├── CustomListener.java │ │ │ ├── MethodInterceptor.java │ │ │ └── RetryFailedTests.java │ │ │ ├── pages │ │ │ ├── amazon │ │ │ │ ├── AmazonHamburgerMenuPage.java │ │ │ │ ├── AmazonHomePage.java │ │ │ │ └── AmazonLaptopPage.java │ │ │ ├── base │ │ │ │ └── BasePage.java │ │ │ ├── googlesearch │ │ │ │ ├── GoogleSearchPage.java │ │ │ │ └── GoogleSearchResultPage.java │ │ │ └── orangehrm │ │ │ │ ├── AddUsersPredicateFactory.java │ │ │ │ ├── HomePage.java │ │ │ │ ├── HomePageAssert.java │ │ │ │ ├── LoginPage.java │ │ │ │ ├── SystemUsersPage.java │ │ │ │ ├── enums │ │ │ │ ├── AddUsersScenarioType.java │ │ │ │ └── topmenucomponent │ │ │ │ │ ├── MenuType.java │ │ │ │ │ └── SubMenuType.java │ │ │ │ ├── pagecomponents │ │ │ │ ├── adduserspage │ │ │ │ │ ├── AddUserComponent.java │ │ │ │ │ ├── SearchComponent.java │ │ │ │ │ └── UserListComponent.java │ │ │ │ └── homepage │ │ │ │ │ └── TopMenuComponent.java │ │ │ │ └── validator │ │ │ │ └── HomePageValidator.java │ │ │ ├── reports │ │ │ ├── ExtentLogger.java │ │ │ ├── ExtentManager.java │ │ │ └── ExtentReport.java │ │ │ └── utils │ │ │ ├── configloader │ │ │ ├── JsonUtils.java │ │ │ └── PropertyUtils.java │ │ │ ├── dataprovider │ │ │ ├── DataProviderUtils.java │ │ │ └── ExcelUtils.java │ │ │ ├── decoder │ │ │ └── DecodeUtils.java │ │ │ ├── dynamicselector │ │ │ └── DynamicXpathUtils.java │ │ │ ├── screenshot │ │ │ ├── ScreenshotService.java │ │ │ └── ScreenshotUtils.java │ │ │ └── zerocell │ │ │ ├── ExcelReader.java │ │ │ └── TestData.java │ └── resources │ │ └── log4j.properties └── test │ ├── java │ └── com │ │ └── automation │ │ ├── base │ │ └── BaseTest.java │ │ └── tests │ │ ├── AmazonDemoTest.java │ │ ├── GooglePageTests.java │ │ └── OrangeHRMTests.java │ └── resources │ ├── chaintest.properties │ ├── config │ ├── config.json │ ├── config.properties │ ├── dev-config.properties │ └── staging-config.properties │ └── data │ └── testdata.xlsx ├── testng.xml ├── testngGoogleTest.xml └── testngOrangeHrmTest.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /extent-test-output 2 | /.idea 3 | /target 4 | /cm.exe -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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" -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | Selenium_Java 7 | WebAutomationFramework 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | Selenium - Web Automation Framework 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 21 17 | 21 18 | 3.11.0 19 | 3.5.2 20 | 5.4.0 21 | 3.27.3 22 | 3.1.0 23 | 2.6.0 24 | 5.1.2 25 | 2.18.2 26 | 1.18.36 27 | 1.9.1 28 | 1.0.12 29 | 4.29.0 30 | 7.11.0 31 | 2.3.0 32 | 0.5.1 33 | 2.1.0-alpha1 34 | 3.0.0-beta2 35 | 2.18.0 36 | 2.13.1 37 | 2.2.0 38 | 1.0.11 39 | 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-compiler-plugin 46 | ${maven-compiler-plugin.version} 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-surefire-plugin 52 | ${maven-surefire-plugin.version} 53 | 54 | 0 55 | false 56 | 57 | 58 | ${suiteXmlFile} 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.testng 69 | testng 70 | ${testng.version} 71 | 72 | 73 | 74 | 75 | com.aventstack 76 | extentreports 77 | ${extent-reports.version} 78 | 79 | 80 | 81 | 82 | com.fasterxml.jackson.core 83 | jackson-databind 84 | ${jackson.version} 85 | 86 | 87 | 88 | 89 | com.fasterxml.jackson.core 90 | jackson-core 91 | ${jackson.version} 92 | 93 | 94 | 95 | org.seleniumhq.selenium 96 | selenium-java 97 | ${selenium-java.version} 98 | 99 | 100 | 101 | org.assertj 102 | assertj-core 103 | ${assertj-core} 104 | 105 | 106 | 107 | 108 | org.assertj 109 | assertj-joda-time 110 | ${assertj-joda-time.version} 111 | test 112 | 113 | 114 | 115 | 116 | joda-time 117 | joda-time 118 | ${joda-time.version} 119 | 120 | 121 | 122 | 123 | 124 | org.apache.poi 125 | poi 126 | ${apache-poi} 127 | 128 | 129 | 130 | 131 | org.apache.poi 132 | poi-ooxml 133 | ${apache-poi} 134 | 135 | 136 | 137 | 138 | commons-io 139 | commons-io 140 | ${commons-io.version} 141 | 142 | 143 | 144 | 145 | org.projectlombok 146 | lombok 147 | ${lombok.version} 148 | 149 | 150 | 151 | 152 | com.machinezoo.noexception 153 | noexception 154 | ${noexception.version} 155 | 156 | 157 | 158 | org.aeonbits.owner 159 | owner 160 | ${owner.version} 161 | 162 | 163 | 164 | io.github.sskorol 165 | test-data-supplier 166 | ${test-data-supplier.version} 167 | 168 | 169 | 170 | 171 | com.creditdatamw.labs 172 | zerocell-core 173 | ${zerocell.version} 174 | 175 | 176 | 177 | 178 | br.com.six2six 179 | fixture-factory 180 | ${fixture-factory.version} 181 | 182 | 183 | 184 | 185 | org.slf4j 186 | slf4j-api 187 | ${slf4j.version} 188 | 189 | 190 | 191 | 192 | org.slf4j 193 | slf4j-log4j12 194 | ${slf4j.version} 195 | 196 | 197 | 198 | org.apache.logging.log4j 199 | log4j-api 200 | ${log4j.version} 201 | 202 | 203 | 204 | org.apache.logging.log4j 205 | log4j-core 206 | ${log4j.version} 207 | 208 | 209 | 210 | com.aventstack 211 | chaintest-testng 212 | ${chaintest.testng.version} 213 | 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/ConfigJson.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum ConfigJson { 4 | 5 | URL 6 | } 7 | -------------------------------------------------------------------------------- /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/enums/RunType.java: -------------------------------------------------------------------------------- 1 | package com.automation.enums; 2 | 3 | public enum RunType { 4 | LOCAL, 5 | REMOTE 6 | } 7 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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