├── .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 | [](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 |
--------------------------------------------------------------------------------