├── .github └── workflows │ └── maven.yml ├── .gitignore ├── README.md ├── pom.xml ├── sample-report.html └── src ├── main ├── java │ └── com │ │ └── example │ │ └── app │ │ ├── CommonActions.java │ │ ├── DriverManager.java │ │ ├── ScenarioContext.java │ │ ├── SeleniumUtils.java │ │ ├── TestContext.java │ │ └── Wait.java └── resources │ ├── application.properties │ └── repo.yaml └── test ├── java └── com │ └── example │ └── app │ ├── RunCucumberTest.java │ └── stepdefs │ ├── CommonUISteps.java │ └── Hooks.java └── resources └── features └── Search.feature /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Java CI with Maven 10 | 11 | on: 12 | push: 13 | branches: [ "main" ] 14 | pull_request: 15 | branches: [ "main" ] 16 | 17 | jobs: 18 | build: 19 | 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Set up JDK 17 25 | uses: actions/setup-java@v3 26 | with: 27 | java-version: '17' 28 | distribution: 'temurin' 29 | cache: maven 30 | - name: Build with Maven 31 | run: mvn -B package --file pom.xml 32 | 33 | # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive 34 | - name: Update dependency graph 35 | uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 11 | .mvn/wrapper/maven-wrapper.jar 12 | 13 | # Eclipse m2e generated files 14 | # Eclipse Core 15 | .project 16 | # JDT-specific (Eclipse Java Development Tools) 17 | .classpath 18 | .settings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Selenium-Cucumber BDD Framework with Gherkin Reusable Steps 4 | 5 | ## Introduction 6 | 7 | Welcome to the Open Source Selenium-java and Cucumber Test Automation Framework! This project is designed to help test automation engineers quickly automate web UI applications across multiple browsers, including Chrome, Microsoft Edge, and Firefox. 8 | 9 | ## Features 10 | 11 | - **Cross-Browser Testing**: Supports automation on Chrome, Microsoft Edge, and Firefox. 12 | - **Ready-Made Boilerplate Code**: Comes with pre-configured Selenium, Java, and Cucumber setups. 13 | - **Reusable Steps**: Includes a library of reusable steps to simplify writing new test scenarios. 14 | - **Easy to Start**: Enables test automation engineers to begin automation from day one with minimal setup. 15 | - **Scalable and Maintainable**: Designed with best practices to ensure the framework is scalable and maintainable. 16 | 17 | ## Prerequisites 18 | 19 | Before running the tests, ensure that the following prerequisites are met: 20 | 21 | - **Java Development Kit (JDK):** Install JDK 8 or higher. 22 | - **Maven:** Ensure Maven is installed on your system. 23 | - **IDE (Integrated Development Environment):** Recommended IDEs include IntelliJ IDEA, Eclipse, or Visual Studio Code. 24 | - **Web Browser:** Chrome, Firefox and MSedge. 25 | 26 | ## Getting Started 27 | 28 | To get started with the project, follow these steps: 29 | 30 | 1. **Clone the Repository:** 31 | ``` 32 | git clone https://github.com/jameersayad/selenium-cucumber-framework.git 33 | ``` 34 | 35 | 2. **Navigate to Project Directory:** 36 | ``` 37 | cd selenium-cucumber-framework 38 | ``` 39 | 40 | 3. **Install Dependencies:** 41 | ``` 42 | mvn clean install 43 | ``` 44 | 45 | 4. **Run Tests:** 46 | ``` 47 | mvn test 48 | ``` 49 | 50 | ## Project Structure 51 | 52 | - **`src/test/java`:** Contains Java source files including step definitions and utility classes. 53 | - **`stepDefinitions`:** Contains step definition classes implementing reusable steps. 54 | - **`utils`:** Contains utility classes for common functionalities. 55 | - **`src/test/resources`:** Contains feature files written in Gherkin syntax. 56 | - **`features`:** Contains `.feature` files defining test scenarios. 57 | - **`pom.xml`:** Maven project configuration file specifying dependencies and build settings. 58 | 59 | ## Writing Feature Files 60 | 61 | Feature files are written in Gherkin syntax and are located in the `src/test/resources/features` directory. Each feature file represents a specific feature of the application and contains scenarios with given, when, and then steps. 62 | 63 | Example Feature File (`login.feature`): 64 | ```gherkin 65 | @Search 66 | Feature: Wikipedia Search Functionality 67 | 68 | Background: 69 | Given I open browser 70 | And navigate to application 71 | 72 | @tag1 73 | Scenario: Search for a existing term 74 | And I am on "Home" page 75 | And the title is "Wikipedia" 76 | When I enter "Selenium" in the "searchTextBox" 77 | And I select "English" from dropdown "searchLanguage" 78 | And I click on "searchButton" 79 | Then I am on "Content" page 80 | And text of "header" is "Selenium" 81 | And I take screenshot 82 | 83 | @tag2 84 | Scenario: Search for a non-existing term 85 | And I am on "Home" page 86 | And the title is "Wikipedia" 87 | When I enter "abcxyz123" in the "searchTextBox" 88 | And I select "English" from dropdown "searchLanguage" 89 | And I click on "searchButton" 90 | Then I am on "SearchResults" page 91 | And "firstResult" is not displayed 92 | And text of "searchResults" contains "There were no results matching the query." 93 | And I take screenshot 94 | 95 | @tag3 96 | Scenario: Search for a generic term 97 | And I am on "Home" page 98 | And the title is "Wikipedia" 99 | When I enter "uncommon word" in the "searchTextBox" 100 | And I select "English" from dropdown "searchLanguage" 101 | And I click on "searchButton" 102 | Then I am on "SearchResults" page 103 | And "firstResult" is displayed 104 | And text of "totalResults" is "5,499" 105 | And I take screenshot 106 | ``` 107 | ## Maintainers 108 | 109 | This project is maintained by: 110 | 111 | - [Jameer](https://github.com/jameersayad) 112 | - [Rameez](https://github.com/rameezhazra2022) 113 | - [Abhishek](https://github.com/myofficework000) 114 | 115 | ## Contributors 116 | 117 | Thanks to all the contributors who have helped make this project better! 118 | 119 | [![Contributors](https://contrib.rocks/image?repo=jameersayad/selenium-cucumber-framework)](https://github.com/jameersayad/selenium-cucumber-framework/graphs/contributors) 120 | 121 | You can see the full list of contributors [here](https://github.com/jameersayad/selenium-cucumber-framework/graphs/contributors). 122 | 123 | 124 | ## Contributing 125 | 126 | Contributions to this project are welcome! If you find any issues or have suggestions for improvements, feel free to open an issue or submit a pull request. 127 | 128 | ## License 129 | 130 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 131 | 132 | --- 133 | 134 | Feel free to customize this README according to your project's specific requirements and conventions. Happy testing! 135 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | com.example 6 | selenium-cucumber 7 | 0.0.1-SNAPSHOT 8 | selenium-cucumber 9 | Starting project for Selenium cucumber framework 10 | 11 | 12 | 1 13 | 11 14 | 11 15 | UTF-8 16 | 4.20.0 17 | 7.18.0 18 | 19 | 20 | 21 | org.seleniumhq.selenium 22 | selenium-java 23 | ${selenium.version} 24 | 25 | 26 | io.cucumber 27 | cucumber-java 28 | ${cucumber.version} 29 | 30 | 31 | io.cucumber 32 | cucumber-junit 33 | ${cucumber.version} 34 | 35 | 36 | 37 | org.json 38 | json 39 | 20240303 40 | 41 | 42 | org.yaml 43 | snakeyaml 44 | 2.2 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-compiler-plugin 53 | 54 | 14 55 | 14 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/CommonActions.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import java.io.File; 4 | import java.io.InputStream; 5 | import java.time.Duration; 6 | import java.util.*; 7 | 8 | import org.openqa.selenium.*; 9 | import org.openqa.selenium.interactions.Actions; 10 | import org.openqa.selenium.support.ui.ExpectedCondition; 11 | import org.openqa.selenium.support.ui.ExpectedConditions; 12 | import org.openqa.selenium.support.ui.Select; 13 | import org.openqa.selenium.support.ui.WebDriverWait; 14 | import org.yaml.snakeyaml.Yaml; 15 | 16 | public class CommonActions { 17 | private static Map> repository; 18 | private static Map currentPagelocators; 19 | 20 | public static void loadRepository() { 21 | Yaml yaml = new Yaml(); 22 | InputStream inputStream = CommonActions.class.getClassLoader().getResourceAsStream("repo.yaml"); 23 | repository = yaml.load(inputStream); 24 | } 25 | 26 | public static void loadCurrentPageLocators(String page) { 27 | currentPagelocators = repository.get(page); 28 | } 29 | 30 | public static By getXpath(String field) { 31 | return By.xpath(currentPagelocators.get(field)); 32 | } 33 | 34 | public static void navigateTo(String url) { 35 | DriverManager.getDriver().get(url); 36 | maximizeApplication(); 37 | } 38 | 39 | public static void closeApplication() { 40 | DriverManager.getDriver().close(); 41 | DriverManager.getDriver().quit(); 42 | DriverManager.setDriver(null); 43 | } 44 | 45 | public static void maximizeApplication() { 46 | DriverManager.getDriver().manage().window().maximize(); 47 | } 48 | 49 | public static byte[] takeScreenshot() { 50 | TakesScreenshot takesScreenshot = (TakesScreenshot) DriverManager.getDriver(); 51 | return takesScreenshot.getScreenshotAs(OutputType.BYTES); 52 | } 53 | 54 | 55 | private static WebElement findElement(String field) { 56 | return DriverManager.getDriver().findElement(getXpath(field)); 57 | } 58 | 59 | private static WebElement findElement(By xpath) { 60 | return DriverManager.getDriver().findElement(xpath); 61 | } 62 | 63 | private static List findElements(By xpath) { 64 | // TODO 65 | // waitUntilExpectedCondition(ExpectedConditions.numberOfElementsToBeMoreThan(xpath,0)); 66 | return DriverManager.getDriver().findElements(xpath); 67 | } 68 | 69 | 70 | public static void click(String field) { 71 | waitUntilExpectedCondition(ExpectedConditions.elementToBeClickable(getXpath(field))); 72 | findElement(getXpath(field)).click(); 73 | } 74 | 75 | public static void doubleClick() { 76 | // TODO 77 | } 78 | 79 | 80 | public static void enterText(String field, String text) { 81 | waitUntilExpectedCondition(ExpectedConditions.elementToBeClickable(getXpath(field))); 82 | findElement(getXpath(field)).sendKeys(text); 83 | } 84 | 85 | public static void clearText(String field, String text) { 86 | waitUntilExpectedCondition(ExpectedConditions.elementToBeClickable(getXpath(field))); 87 | findElement(getXpath(field)).clear(); 88 | } 89 | 90 | public static String getText(String field) { 91 | waitUntilExpectedCondition(ExpectedConditions.presenceOfElementLocated(getXpath(field))); 92 | return findElement(getXpath(field)).getText(); 93 | } 94 | 95 | private static V waitUntilExpectedCondition(ExpectedCondition expectedCondition) { 96 | WebDriverWait wait = new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(10)); 97 | return wait.until(expectedCondition); 98 | } 99 | 100 | private static V waitUntilExpectedCondition(ExpectedCondition expectedCondition, int timeoutInsSecs) { 101 | WebDriverWait wait = new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(timeoutInsSecs)); 102 | return wait.until(expectedCondition); 103 | } 104 | 105 | public static void selectTextFromDropDown(String field, String text) { 106 | waitUntilExpectedCondition(ExpectedConditions.presenceOfElementLocated(getXpath(field))); 107 | Select select = new Select(findElement(getXpath(field))); 108 | select.selectByVisibleText(text); 109 | } 110 | 111 | public static void selectValueFromDropDown(String field, String value) { 112 | waitUntilExpectedCondition(ExpectedConditions.presenceOfElementLocated(getXpath(field))); 113 | Select select = new Select(findElement(getXpath(field))); 114 | select.selectByValue(value); 115 | } 116 | 117 | public static void selectIndexFromDropDown(String field, int index) { 118 | waitUntilExpectedCondition(ExpectedConditions.presenceOfElementLocated(getXpath(field))); 119 | Select select = new Select(findElement(getXpath(field))); 120 | select.selectByIndex(index); 121 | } 122 | 123 | public static void deselectAllFromDropDown(String field) { 124 | waitUntilExpectedCondition(ExpectedConditions.presenceOfElementLocated(getXpath(field))); 125 | Select select = new Select(findElement(getXpath(field))); 126 | select.deselectAll(); 127 | } 128 | 129 | public static List getAllSelectedOptionsFromDropDown(String field) { 130 | waitUntilExpectedCondition(ExpectedConditions.visibilityOfElementLocated(getXpath(field))); 131 | Select select = new Select(findElement(getXpath(field))); 132 | return select.getAllSelectedOptions(); 133 | } 134 | 135 | public static List getAllOptionsFromDropDown(String field) { 136 | waitUntilExpectedCondition(ExpectedConditions.visibilityOfElementLocated(getXpath(field))); 137 | Select select = new Select(findElement(getXpath(field))); 138 | return select.getOptions(); 139 | } 140 | 141 | public static List getTextOfAllElements(List elements) { 142 | List elementsText = new ArrayList<>(); 143 | for (WebElement element : elements) { 144 | elementsText.add(element.getText()); 145 | } 146 | return elementsText; 147 | } 148 | 149 | public static boolean isElementDisplayed(String field) { 150 | try { 151 | return findElement(field).isDisplayed(); 152 | } catch (Exception e) { 153 | return false; 154 | } 155 | } 156 | 157 | public static boolean isElementEnabled(String field) { 158 | try { 159 | waitUntilExpectedCondition(ExpectedConditions.visibilityOfElementLocated(getXpath(field))); 160 | return findElement(field).isEnabled(); 161 | } catch (Exception e) { 162 | return false; 163 | } 164 | } 165 | 166 | public static boolean isElementDisabled(String field) { 167 | try { 168 | waitUntilExpectedCondition(ExpectedConditions.visibilityOfElementLocated(getXpath(field))); 169 | return !findElement(field).isEnabled(); 170 | } catch (Exception e) { 171 | return false; 172 | } 173 | } 174 | 175 | public static String getTitle() { 176 | return DriverManager.getDriver().getTitle(); 177 | } 178 | 179 | public static String getElementAttribute(String field, String attribute) { 180 | return findElement(field).getAttribute(attribute); 181 | } 182 | 183 | public static void switchToWindowByTitle(final String windowTitle) { 184 | if (!getTitle().equals(windowTitle)) { 185 | Set windowHandles = DriverManager.getDriver().getWindowHandles(); 186 | for (String windowHandle : windowHandles) { 187 | DriverManager.getDriver().switchTo().window(windowHandle); 188 | if (DriverManager.getDriver().getTitle().equals(windowTitle)) { 189 | break; 190 | } 191 | } 192 | if (DriverManager.getDriver().getTitle().equals(windowTitle)) { 193 | throw new NoSuchWindowException(String.format("no such window found from current session , with title", windowTitle)); 194 | } 195 | } 196 | } 197 | 198 | public static void refreshPage() { 199 | DriverManager.getDriver().navigate().refresh(); 200 | } 201 | 202 | public static String acceptAlert(){ 203 | waitUntilExpectedCondition(ExpectedConditions.alertIsPresent()); 204 | Alert alert=DriverManager.getDriver().switchTo().alert(); 205 | String text= alert.getText(); 206 | alert.accept(); 207 | return text; 208 | } 209 | 210 | public static String dismissAlert(){ 211 | waitUntilExpectedCondition(ExpectedConditions.alertIsPresent()); 212 | Alert alert=DriverManager.getDriver().switchTo().alert(); 213 | String text= alert.getText(); 214 | alert.dismiss(); 215 | return text; 216 | } 217 | 218 | public static void switchToFrame(String nameOrId){ 219 | waitUntilExpectedCondition(ExpectedConditions.frameToBeAvailableAndSwitchToIt(nameOrId)); 220 | DriverManager.getDriver().switchTo().frame(nameOrId); 221 | } 222 | 223 | public static void switchToFrame(int index){ 224 | waitUntilExpectedCondition(ExpectedConditions.frameToBeAvailableAndSwitchToIt(index)); 225 | DriverManager.getDriver().switchTo().frame(index); 226 | } 227 | 228 | public static void switchToFrame(By locator){ 229 | waitUntilExpectedCondition(ExpectedConditions.frameToBeAvailableAndSwitchToIt(locator)); 230 | DriverManager.getDriver().switchTo().frame(findElement(locator)); 231 | } 232 | 233 | public static void switchToParentFrame(){ 234 | DriverManager.getDriver().switchTo().parentFrame(); 235 | } 236 | 237 | public static String getRecentDownloadedFile() { 238 | String sdir=TestContext.getTestContext().getApplicationProperty("download.dir"); 239 | File dir = new File(sdir); 240 | if (dir.isDirectory()) { 241 | Optional opFile = Arrays.stream(dir.listFiles(File::isFile)) 242 | .max((f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified())); 243 | 244 | if (opFile.isPresent()){ 245 | return opFile.get().getName(); 246 | } 247 | } 248 | return null; 249 | } 250 | 251 | // Draws a red border around the found element. Does not set it back anyhow. 252 | public WebElement highLightElement(String field) { 253 | WebElement elem = findElement(field); 254 | // draw a border around the found element 255 | if (DriverManager.getDriver() instanceof JavascriptExecutor) { 256 | ((JavascriptExecutor)DriverManager.getDriver()).executeScript("arguments[0].style.border='3px solid red'", elem); 257 | } 258 | return elem; 259 | } 260 | 261 | public void scrollDown(){ 262 | executeJavaScript("window.scrollBy(0, 1000);"); 263 | } 264 | 265 | public void scrollToElement(String field){ 266 | WebElement element =findElement(field); 267 | executeJavaScript("arguments[0].scrollIntoView(true);", element); 268 | } 269 | public Object executeJavaScript(String javaScript){ 270 | JavascriptExecutor js = (JavascriptExecutor) DriverManager.getDriver(); 271 | return js.executeScript(javaScript); 272 | } 273 | 274 | public Object executeJavaScript(String javaScript, WebElement element){ 275 | JavascriptExecutor js = (JavascriptExecutor) DriverManager.getDriver(); 276 | return js.executeScript(javaScript, element); 277 | } 278 | //TODO 279 | //doAction 280 | public static void doAction(String locator, CommonActions.Events event){ 281 | Actions actions = new Actions(DriverManager.getDriver()); 282 | switch (event) { 283 | case CLICK: 284 | click(locator); 285 | break; 286 | case DOUBLE_CLICK: 287 | actions.doubleClick(findElement(locator)).build().perform(); 288 | break; 289 | case RIGHT_CLICK: 290 | actions.contextClick(findElement(locator)).build().perform(); 291 | break; 292 | case CTRL_CLICK: 293 | actions.keyDown(Keys.LEFT_CONTROL).click(findElement(locator)).keyUp(Keys.LEFT_CONTROL).build().perform(); 294 | break; 295 | case SHIFT_CLICK: 296 | actions.keyDown(Keys.LEFT_SHIFT).click(findElement(locator)).keyUp(Keys.LEFT_SHIFT).build().perform(); 297 | break; 298 | case MOUSE_HOVER: 299 | actions.moveToElement(findElement(locator)).build().perform(); 300 | break; 301 | case ENTER_KEY: 302 | actions.keyDown(findElement(locator),Keys.ENTER).build().perform(); 303 | break; 304 | case ESC_KEY: 305 | actions.keyDown(findElement(locator),Keys.ESCAPE).build().perform(); 306 | break; 307 | 308 | } 309 | } 310 | public static enum Events{ 311 | CLICK, 312 | DOUBLE_CLICK, 313 | CTRL_CLICK, 314 | RIGHT_CLICK, 315 | SHIFT_CLICK, 316 | MOUSE_UP, 317 | MOUSE_DOWN, 318 | MOUSE_HOVER, 319 | ENTER_KEY, 320 | ESC_KEY; 321 | 322 | private Events(){} 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/DriverManager.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import java.nio.file.Paths; 4 | import java.time.Duration; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import org.openqa.selenium.Capabilities; 9 | import org.openqa.selenium.WebDriver; 10 | import org.openqa.selenium.chrome.ChromeDriver; 11 | import org.openqa.selenium.chrome.ChromeOptions; 12 | import org.openqa.selenium.chromium.ChromiumOptions; 13 | import org.openqa.selenium.edge.EdgeDriver; 14 | import org.openqa.selenium.edge.EdgeOptions; 15 | import org.openqa.selenium.firefox.FirefoxDriver; 16 | import org.openqa.selenium.firefox.FirefoxOptions; 17 | import org.openqa.selenium.firefox.FirefoxProfile; 18 | import org.openqa.selenium.remote.DesiredCapabilities; 19 | 20 | public class DriverManager { 21 | 22 | private static WebDriver driver; 23 | 24 | public static WebDriver getDriver() { 25 | if (null == driver) { 26 | driver = createDriver(); 27 | } 28 | return driver; 29 | } 30 | 31 | public static void setDriver(WebDriver webdriver) { 32 | driver = webdriver; 33 | } 34 | 35 | private static WebDriver createDriver() { 36 | return createDriver("chrome"); 37 | } 38 | 39 | private static WebDriver createDriver(String browser) { 40 | var downloadDir = Paths.get("target").toAbsolutePath().toString(); 41 | 42 | /**CHROME/Edge Options */ 43 | // Create a map to set preferences 44 | Map prefs = new HashMap<>(); 45 | TestContext.getTestContext().getApplicationProperty(""); 46 | prefs.put("download.default_directory", downloadDir); // Change the path to your desired download directory 47 | prefs.put("download.prompt_for_download", false); 48 | prefs.put("download.directory_upgrade", true); 49 | prefs.put("plugins.always_open_pdf_externally", true); // Disable the built-in PDF viewer 50 | 51 | // Apply the preferences to ChromeOptions 52 | ChromiumOptions options = new ChromeOptions(); 53 | options.setExperimentalOption("prefs", prefs); 54 | 55 | /** FirefoxOptions */ 56 | // Create a new profile 57 | FirefoxProfile profile = new FirefoxProfile(); 58 | 59 | // Set preferences for the profile 60 | profile.setPreference("browser.download.dir", downloadDir); 61 | profile.setPreference("browser.download.folderList", 2); 62 | profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "application/pdf"); // MIME type 63 | profile.setPreference("pdfjs.disabled", true); // Disable the built-in PDF viewer 64 | 65 | // Apply the profile to FirefoxOptions 66 | FirefoxOptions firefoxOptions = new FirefoxOptions(); 67 | firefoxOptions.setProfile(profile); 68 | 69 | /** EdgeOptions */ 70 | 71 | driver = switch (browser) { 72 | case "firefox" -> new FirefoxDriver(firefoxOptions); 73 | case "edge" -> new EdgeDriver((EdgeOptions) options); 74 | default -> new ChromeDriver((ChromeOptions) options); 75 | }; 76 | driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); 77 | return driver; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/ScenarioContext.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | public class ScenarioContext { 4 | private static ScenarioContext scenarioContext; 5 | 6 | public static ScenarioContext getScenarioContext(){ 7 | if(scenarioContext == null) { 8 | scenarioContext = new ScenarioContext(); 9 | } 10 | return scenarioContext; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/SeleniumUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | import org.openqa.selenium.By; 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | import java.time.Duration; 8 | import java.util.List; 9 | 10 | public class SeleniumUtils { 11 | 12 | private WebDriver driver; 13 | private WebDriverWait wait; 14 | 15 | public SeleniumUtils(WebDriver driver, Duration timeout) { 16 | this.driver = driver; 17 | this.wait = new WebDriverWait(driver, timeout); 18 | } 19 | 20 | // Click an element 21 | public void clickElement(By locator) { 22 | wait.until(ExpectedConditions.elementToBeClickable(locator)).click(); 23 | } 24 | 25 | // Enter text in a text box 26 | public void enterText(By locator, String text) { 27 | WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); 28 | element.clear(); 29 | element.sendKeys(text); 30 | } 31 | 32 | // Wait for an element to be visible 33 | public WebElement waitForVisibility(By locator) { 34 | return wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); 35 | } 36 | 37 | // Get text from an element 38 | public String getElementText(By locator) { 39 | return wait.until(ExpectedConditions.visibilityOfElementLocated(locator)).getText(); 40 | } 41 | 42 | // Get a list of elements 43 | public List getElements(By locator) { 44 | return wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(locator)); 45 | } 46 | 47 | // Check if element is present 48 | public boolean isElementPresent(By locator) { 49 | try { 50 | driver.findElement(locator); 51 | return true; 52 | } catch (Exception e) { 53 | return false; 54 | } 55 | } 56 | 57 | // Wait for an element to be clickable 58 | public void waitForElementToBeClickable(By locator) { 59 | wait.until(ExpectedConditions.elementToBeClickable(locator)); 60 | } 61 | 62 | // Select a checkbox if not already selected 63 | public void selectCheckbox(By locator) { 64 | WebElement checkbox = wait.until(ExpectedConditions.elementToBeClickable(locator)); 65 | if (!checkbox.isSelected()) { 66 | checkbox.click(); 67 | } 68 | } 69 | 70 | // Deselect a checkbox if selected 71 | public void deselectCheckbox(By locator) { 72 | WebElement checkbox = wait.until(ExpectedConditions.elementToBeClickable(locator)); 73 | if (checkbox.isSelected()) { 74 | checkbox.click(); 75 | } 76 | } 77 | 78 | // Switch to frame by locator 79 | public void switchToFrame(By locator) { 80 | driver.switchTo().frame(wait.until(ExpectedConditions.visibilityOfElementLocated(locator))); 81 | } 82 | 83 | // Switch to default content 84 | public void switchToDefaultContent() { 85 | driver.switchTo().defaultContent(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/TestContext.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Properties; 8 | import io.cucumber.java.Scenario; 9 | 10 | public class TestContext { 11 | private static TestContext testContext; 12 | private Scenario scenario; 13 | private Properties properties; 14 | private Map dataWorld= new HashMap<>(); 15 | public static TestContext getTestContext(){ 16 | if(testContext == null) { 17 | testContext = new TestContext(); 18 | } 19 | return testContext; 20 | } 21 | 22 | public TestContext(){ 23 | loadApplicationProperties(); 24 | } 25 | 26 | private void loadApplicationProperties(){ 27 | InputStream inputStream = this.getClass() 28 | .getClassLoader() 29 | .getResourceAsStream("application.properties"); 30 | properties = new Properties(); 31 | try { 32 | properties.load(inputStream); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | System.exit(0); 36 | } 37 | } 38 | 39 | public void storeInDataWorld(String key, Object value){ 40 | dataWorld.put(key, value); 41 | } 42 | public void getFromDataWorld(String key, Object value){ 43 | dataWorld.get(key); 44 | } 45 | 46 | public String getApplicationProperty(String property){ 47 | return properties.getProperty(property); 48 | } 49 | 50 | public void setScenario(Scenario scenario) { 51 | this.scenario= scenario; 52 | }public Scenario getScenario() { 53 | return scenario; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/example/app/Wait.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import java.time.Duration; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.function.Function; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.support.ui.WebDriverWait; 9 | 10 | /** 11 | * The Wait class provides utility methods to wait for certain conditions 12 | * using Selenium WebDriver. 13 | */ 14 | public class Wait { 15 | 16 | /** 17 | * Waits until jQuery calls are done using the default timeout specified in the configuration. 18 | * 19 | * @param driver the WebDriver instance 20 | */ 21 | public static void untilJqueryIsDone(WebDriver driver){ 22 | untilJqueryIsDone(driver, Duration.ofSeconds(10)); 23 | } 24 | 25 | /** 26 | * Waits until jQuery calls are done using a specified timeout. 27 | * 28 | * @param driver the WebDriver instance 29 | * @param timeoutInSeconds the maximum time to wait in seconds 30 | */ 31 | public static void untilJqueryIsDone(WebDriver driver, Duration timeoutInSeconds){ 32 | until(driver, (d) -> { 33 | Boolean isJqueryCallDone = (Boolean)((JavascriptExecutor) driver).executeScript("return jQuery.active==0"); 34 | if (!isJqueryCallDone) System.out.println("JQuery call is in Progress"); 35 | return isJqueryCallDone; 36 | }, timeoutInSeconds); 37 | } 38 | 39 | /** 40 | * Waits until the page load is complete using the default timeout specified in the configuration. 41 | * 42 | * @param driver the WebDriver instance 43 | */ 44 | public static void untilPageLoadComplete(WebDriver driver) { 45 | untilPageLoadComplete(driver, 10L); 46 | } 47 | 48 | /** 49 | * Waits until the page load is complete using a specified timeout. 50 | * 51 | * @param driver the WebDriver instance 52 | * @param timeoutInSeconds the maximum time to wait in seconds 53 | */ 54 | public static void untilPageLoadComplete(WebDriver driver, Long timeoutInSeconds){ 55 | until(driver, (d) -> { 56 | Boolean isPageLoaded = (Boolean)((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"); 57 | if (!isPageLoaded) System.out.println("Document is loading"); 58 | return isPageLoaded; 59 | }, Duration.ofSeconds(10)); 60 | } 61 | 62 | /** 63 | * Waits for a specified condition to be true using the default timeout specified in the configuration. 64 | * 65 | * @param driver the WebDriver instance 66 | * @param waitCondition the condition to wait for 67 | */ 68 | public static void until(WebDriver driver, Function waitCondition){ 69 | until(driver, waitCondition, Duration.ofSeconds(10)); 70 | } 71 | 72 | /** 73 | * Waits for a specified condition to be true using a specified timeout. 74 | * 75 | * @param driver the WebDriver instance 76 | * @param waitCondition the condition to wait for 77 | * @param timeoutInSeconds the maximum time to wait in seconds 78 | */ 79 | private static void until(WebDriver driver, Function waitCondition, Duration timeoutInSeconds){ 80 | WebDriverWait webDriverWait = new WebDriverWait(driver, timeoutInSeconds); 81 | webDriverWait.withTimeout(timeoutInSeconds); 82 | try{ 83 | webDriverWait.until(waitCondition); 84 | } catch (Exception e){ 85 | System.out.println(e.getMessage()); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.url=https://www.wikipedia.org 2 | browser="Chrome" 3 | download.dir="target" 4 | #Browser e.g Chrome / Edge / Safari 5 | -------------------------------------------------------------------------------- /src/main/resources/repo.yaml: -------------------------------------------------------------------------------- 1 | Home: 2 | header: "//h1/span[contains(text(),'Wikipedia')]" 3 | searchTextBox: "//input[@id='searchInput']" 4 | searchLanguage: "//select[@id='searchLanguage']" 5 | searchButton: "//button/i[text()='Search']" 6 | SearchResults: 7 | header: "//h1[text()='Search results']" 8 | searchResults: "//div[contains(@class,'searchresults')]" 9 | firstResult: "//*[@class='mw-search-results']//li[1]" 10 | totalResults: "//div[@class='results-info']/strong[2]" 11 | Content: 12 | header: "//*[@id='firstHeading']" 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/test/java/com/example/app/RunCucumberTest.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(Cucumber.class) 8 | @CucumberOptions(tags = "@Search", 9 | features = "src/test/resources/features", 10 | plugin = {"pretty", "html:target/cucumber.html"}, 11 | snippets = CucumberOptions.SnippetType.CAMELCASE 12 | ) 13 | public class RunCucumberTest { 14 | } -------------------------------------------------------------------------------- /src/test/java/com/example/app/stepdefs/CommonUISteps.java: -------------------------------------------------------------------------------- 1 | package com.example.app.stepdefs; 2 | 3 | import com.example.app.CommonActions; 4 | import com.example.app.DriverManager; 5 | import com.example.app.TestContext; 6 | import io.cucumber.java.en.And; 7 | import io.cucumber.java.en.Given; 8 | import io.cucumber.java.en.Then; 9 | import io.cucumber.java.en.When; 10 | import org.junit.Assert; 11 | 12 | public class CommonUISteps { 13 | 14 | @Given("I open browser") 15 | public void iOpenBrowser() { 16 | DriverManager.getDriver(); 17 | } 18 | 19 | @Given("navigate to application") 20 | public void navigateToApplication() { 21 | CommonActions.navigateTo(TestContext.getTestContext().getApplicationProperty("app.url")); 22 | } 23 | 24 | @Given("I am on {string} page") 25 | public void i_am_on_page(String page) { 26 | CommonActions.loadCurrentPageLocators(page); 27 | Assert.assertTrue(page, CommonActions.isElementDisplayed("header")); 28 | } 29 | 30 | @Then("the title is {string}") 31 | public void theTitleIs(String title) { 32 | Assert.assertEquals("Title is not as expected", title, CommonActions.getTitle()); 33 | } 34 | 35 | @When("I enter {string} in the {string}") 36 | public void iEnterInThe(String text, String field) { 37 | CommonActions.enterText(field, text); 38 | } 39 | 40 | @When("I click on {string}") 41 | public void iClickOn(String field) { 42 | CommonActions.click(field); 43 | } 44 | 45 | @Then("{string} is displayed") 46 | public void isDisplayed(String field) { 47 | Assert.assertTrue(field + " is not displayed", CommonActions.isElementDisplayed(field)); 48 | } 49 | 50 | @Then("{string} is not displayed") 51 | public void isNotDisplayed(String field) { 52 | Assert.assertFalse(field + " is displayed", CommonActions.isElementDisplayed(field)); 53 | } 54 | 55 | @Then("{string} is enabled") 56 | public void isEnabled(String field) { 57 | Assert.assertTrue(field + " is not enabled", CommonActions.isElementEnabled(field)); 58 | } 59 | 60 | @Then("{string} is disabled") 61 | public void isDisabled(String field) { 62 | Assert.assertTrue(field + " is not disabled", CommonActions.isElementEnabled(field)); 63 | } 64 | 65 | @Then("text of {string} is {string}") 66 | public void textOfFieldIs(String field, String expected) { 67 | Assert.assertEquals("Text is not expected", expected, CommonActions.getText(field)); 68 | } 69 | 70 | @Then("I take screenshot") 71 | public void iTakeScreenshot() { 72 | byte[] screenshot = CommonActions.takeScreenshot(); 73 | TestContext.getTestContext().getScenario().attach(screenshot, "image/png", "screenshot"); 74 | } 75 | 76 | @When("I select {string} from dropdown {string}") 77 | public void iSelectTextFromDropDown(String value, String field) { 78 | CommonActions.selectTextFromDropDown(field, value); 79 | } 80 | 81 | @When("I select option {int} from dropdown {string}") 82 | public void iSelectOptionFromTheDropdown(int option, String field) { 83 | CommonActions.selectIndexFromDropDown(field, option); 84 | } 85 | 86 | @When("I select value {string} from dropdown {string}") 87 | public void iSelectValueFromDropDown(String value, String field) { 88 | CommonActions.selectValueFromDropDown(field, value); 89 | } 90 | 91 | @Then("file {string} is downloaded") 92 | public void assertfileIsDownloaded(String file) { 93 | Assert.assertNotEquals("File is not downloaded :" + file, null, CommonActions.getRecentDownloadedFile()); 94 | } 95 | 96 | @And("text of {string} contains {string}") 97 | public void textOfContains(String field, String expected) { 98 | Assert.assertTrue("Text is not expected", CommonActions.getText(field).contains(expected)); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/example/app/stepdefs/Hooks.java: -------------------------------------------------------------------------------- 1 | package com.example.app.stepdefs; 2 | 3 | import com.example.app.CommonActions; 4 | import com.example.app.DriverManager; 5 | import com.example.app.TestContext; 6 | 7 | import io.cucumber.java.After; 8 | import io.cucumber.java.Before; 9 | import io.cucumber.java.BeforeAll; 10 | import io.cucumber.java.Scenario; 11 | import io.cucumber.java.Status; 12 | 13 | public class Hooks { 14 | 15 | @BeforeAll 16 | public static void beforeAll() { 17 | TestContext.getTestContext(); 18 | CommonActions.loadRepository(); 19 | } 20 | 21 | @Before 22 | public void before(Scenario scenario) { 23 | TestContext.getTestContext().setScenario(scenario); 24 | } 25 | 26 | @After 27 | public void after(Scenario scenario) { 28 | if (!scenario.getStatus().equals(Status.PASSED)) { 29 | byte[] screenshot = CommonActions.takeScreenshot(); 30 | TestContext.getTestContext().getScenario().attach(screenshot, "image/png", "screenshot"); 31 | } 32 | CommonActions.closeApplication(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/features/Search.feature: -------------------------------------------------------------------------------- 1 | @Search 2 | Feature: Wikipedia Search Functionality 3 | 4 | Background: 5 | Given I open browser 6 | And navigate to application 7 | 8 | @tag1 9 | Scenario: Search for a existing term 10 | And I am on "Home" page 11 | And the title is "Wikipedia" 12 | When I enter "Selenium" in the "searchTextBox" 13 | And I select "English" from dropdown "searchLanguage" 14 | And I click on "searchButton" 15 | Then I am on "Content" page 16 | And text of "header" is "Selenium" 17 | And I take screenshot 18 | 19 | @tag2 20 | Scenario: Search for a non-existing term 21 | And I am on "Home" page 22 | And the title is "Wikipedia" 23 | When I enter "abcxyz123" in the "searchTextBox" 24 | And I select "English" from dropdown "searchLanguage" 25 | And I click on "searchButton" 26 | Then I am on "SearchResults" page 27 | And "firstResult" is not displayed 28 | And text of "searchResults" contains "There were no results matching the query." 29 | And I take screenshot 30 | 31 | @tag3 32 | Scenario: Search for a generic term 33 | And I am on "Home" page 34 | And the title is "Wikipedia" 35 | When I enter "uncommon word" in the "searchTextBox" 36 | And I select "English" from dropdown "searchLanguage" 37 | And I click on "searchButton" 38 | Then I am on "SearchResults" page 39 | And "firstResult" is displayed 40 | And text of "totalResults" is "5,499" 41 | And I take screenshot 42 | --------------------------------------------------------------------------------