├── .idea ├── compiler.xml ├── misc.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── AutomationReports └── AutomationReport.html ├── README.md ├── images ├── Report.png └── Report1.png ├── pom.xml ├── selenium-pom-java.iml ├── src ├── main │ └── java │ │ ├── actionHelper │ │ └── WebActionHelperMethods.java │ │ ├── driverManager │ │ ├── DriverManagerType.java │ │ └── WebDrivers.java │ │ ├── listeners │ │ └── TestListner.java │ │ ├── reportManager │ │ └── ExtentManager.java │ │ └── util │ │ └── utility.java └── test │ ├── java │ ├── Pages │ │ ├── BasePageClass.java │ │ ├── HomePage.java │ │ └── LoginPage.java │ └── TestCases │ │ ├── BaseTest.java │ │ └── LoginTestCases.java │ └── resources │ └── Env.properties ├── target ├── classes │ ├── META-INF │ │ └── Selenium-POM-Java.kotlin_module │ ├── actionHelper │ │ └── WebActionHelperMethods.class │ ├── driverManager │ │ ├── DriverManagerType.class │ │ └── WebDrivers.class │ ├── listeners │ │ └── TestListner.class │ ├── reportManager │ │ └── ExtentManager.class │ └── util │ │ └── utility.class └── test-classes │ ├── Env.properties │ ├── META-INF │ └── Selenium-POM-Java.kotlin_module │ ├── Pages │ ├── BasePageClass.class │ ├── HomePage.class │ └── LoginPage.class │ └── TestCases │ ├── BaseTest.class │ └── LoginTestCases.class └── test.xml /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 102 | 103 | 104 | 106 | 107 | 130 | 131 | 132 | 137 | 138 | 139 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 104 | 105 | 106 | 107 | 108 | 109 |
110 |
111 |
112 |
113 |
Tests
114 |
115 | 116 |
117 |
118 | 1 test(s) passed 119 |
120 |
121 | 1 test(s) failed, 0 others 122 |
123 |
124 |
125 |
126 |
127 |
Steps
128 |
129 | 130 |
131 |
132 | 1 step(s) passed 133 |
134 |
135 | 1 step(s) failed, 0 others 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
Timeline (seconds)
144 |
145 | 146 |
147 |
148 |
149 |
150 |
151 |
152 |
    153 |
  • 154 |
    155 | LoginTestCases 156 | Aug 9, 2020 08:44:33 PM 157 | pass 158 |
    159 |
    160 |
    161 | Aug 9, 2020 08:44:33 PM 162 | Aug 9, 2020 08:44:33 PM 163 | 0h 0m 0s+0ms 164 |
    165 |
    166 |
    167 | TestResult 168 |
    169 |
    170 |
      171 |
    • 172 |
      173 |
      Test passed
      174 | Aug 9, 2020 08:44:33 PM 175 | · 0h 0m 0s+0ms 176 | pass 177 |
      178 |
    • 179 |
    180 |
    181 |
  • 182 |
  • 183 |
    184 | LoginTestCases 185 | Aug 9, 2020 08:44:34 PM 186 | fail 187 |
    188 |
    189 |
    190 | Aug 9, 2020 08:44:34 PM 191 | Aug 9, 2020 08:44:34 PM 192 | 0h 0m 0s+2ms 193 |
    194 |
      195 |
    • 196 |
      197 |
      Test Failed
      198 | Aug 9, 2020 08:44:34 PM 199 | · 0h 0m 0s+2ms 200 | fail 201 |
      202 |
      203 |
      204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 273 | 274 | 275 |
      StatusTimestampDetails
      cancel8:44:34 PM 217 | 271 | 272 |
      276 |
      277 |
      278 |
    • 279 |
    280 |
    281 |
  • 282 |
283 |
284 |
285 | 286 |
287 |
288 |
289 | check_circle 290 | cancel 291 | cancel 292 | error 293 | warning 294 | redo 295 | clear 296 |
297 |
298 |
299 |
300 | 301 | 302 |
303 |
304 |
305 | 306 |
307 | 308 | search Search 309 | 310 |
311 | 312 |
313 |
314 | 315 |
316 |
317 |
318 |
319 |
    320 |
  • 321 |
    322 | TestResult 323 | 324 | 1 325 | 326 |
    327 |
    328 |
    329 | Passed: 1 330 | 331 | 332 |
    333 |
    334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 |
    TimestampTestNameStatus
    Aug 9, 2020 08:44:33 PMLoginTestCasespass
    350 |
    351 |
    352 |
  • 353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 | 366 |
367 | 368 | search Search 369 | 370 |
371 | 372 |
373 |
374 | 375 |
376 |
377 |
378 |
379 |
    380 |
  • 381 |
    382 | org.openqa.selenium.InvalidSelectorException 383 | 1 384 |
    385 |
    386 |
    387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 455 | 456 | 457 |
    TimestampTestNameStatus
    Aug 9, 2020 08:44:34 PMLoginTestCases.Test Failed 400 | 454 |
    458 |
    459 |
    460 |
  • 461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
Dashboard
473 | 474 |
475 |
476 |
477 | Tests 478 |
2
479 |
480 |
481 |
482 |
483 | Steps 484 |
2
485 |
486 |
487 |
488 |
489 | Start 490 |
Aug 9, 2020 08:44:27 PM
491 |
492 |
493 |
494 |
495 | End 496 |
Aug 9, 2020 08:44:34 PM
497 |
498 |
499 |
500 |
501 | Time Taken 502 |
0h 0m 6s+780ms
503 |
504 |
505 |
506 |
507 | Categories

 

508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 525 | 526 |
NamePassedFailedOthersPassed %
TestResult100 523 | 100% 524 |
527 |
528 |
529 |
530 |
531 |
532 | 533 | 534 | 535 | 567 | 572 | 573 | 575 | 576 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Selenium-PageObject-Java-Automation-Framework 2 | 3 | Selenium page object automation framework using java & Maven & TestNG & Extent Report 4 | 5 | ## Steps to Setup 6 | 7 | **1. Clone the application** 8 | 9 | ```bash 10 | git clone 11 | ``` 12 | 13 | **2. Import project in any Editor(Eclispe/Intellij)** 14 | 15 | **3. Run test.xml** 16 | 17 | 18 | 19 | ## Project Structure 20 | ### Package & Classes Details 21 | 22 | ##### actionHelper : In this package common web functions is present 23 | 24 | ```bash 25 | WebActionHelperMethods : All the common web functions is present in this class like click(),Scroll(),Enter() etc. 26 | ``` 27 | ##### driverManager : In this package We are handling drivers initialization on the basis of browser 28 | 29 | ```bash 30 | DriverManagerType : We have create an enum for Driver types and its definations 31 | ``` 32 | ```bash 33 | Webdrivers : In this class we are creating driver object on the Basis of DriverType like DriverManagerType.CHROME,DriverManagerType.firefoxdriver 34 | ``` 35 | ##### listners : In this package we are using TestNg ITestlistner for creating report on the basis of Test result 36 | 37 | ```bash 38 | TestListner :In order to listen to test events such as passed, failed, skipped, etc. we have TestListener class which implements ITestListener. 39 | ``` 40 | ```bash 41 | **onFinish:** This method is invoked after all tests methods gets executed. 42 | 43 | **onTestStart:** This method is invoked before any test methods are invoked. This can be used to indicate that the particular test method has been started. 44 | 45 | **onTestSkipped:** This method is invoked when each test method is skipped. This can be used to indicate that the particular test method has been skipped. 46 | 47 | **onTestSuccess:** This method is invoked when any test method succeeds. This can be used to indicate that the particular test method has successfully finished its execution. 48 | 49 | **onTestFailure:** This method is invoked when any test method fails. This can be used to indicate that the particular test method has failed. You can create an event for taking a screenshot which will show where the test has been failed. 50 | ``` 51 | ##### reportManager : In this package we are using Extent report for reporting testCases 52 | 53 | ```bash 54 | ExtentManager :In this class we are using Extent api and initialization of Extent object 55 | ``` 56 | 57 | ##### Pages : In this package all the pages of application is present. 58 | 59 | ```bash 60 | BasePageClass :In this class we have initialize all the page classes using PagePafctory conecepts(PageFactory.initElements) 61 | ``` 62 | ```bash 63 | HomePage,Login Page :In this class we have all the locators and associated methods. 64 | ``` 65 | ##### TestCases : In this package all the TestCases is present. 66 | 67 | ```bash 68 | BaseTest :In this class we have initialize drivers and all the pages. 69 | ``` 70 | 71 | ##### Report 72 | 73 | ![](images/Report.png) 74 | 75 | ![](images/Report1.png) 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /images/Report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/images/Report.png -------------------------------------------------------------------------------- /images/Report1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/images/Report1.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.selenium 8 | selenium-pom-java 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.testng 15 | testng 16 | 6.11 17 | 18 | 19 | com.aventstack 20 | extentreports 21 | 4.0.9 22 | 23 | 24 | 25 | io.github.bonigarcia 26 | webdrivermanager 27 | 3.7.1 28 | test 29 | 30 | 31 | 32 | org.seleniumhq.selenium 33 | selenium-java 34 | 3.141.59 35 | 36 | 37 | io.github.bonigarcia 38 | webdrivermanager 39 | 3.8.1 40 | compile 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /selenium-pom-java.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/java/actionHelper/WebActionHelperMethods.java: -------------------------------------------------------------------------------- 1 | package actionHelper; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.Keys; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.chrome.ChromeDriver; 8 | import org.openqa.selenium.firefox.FirefoxDriver; 9 | import org.openqa.selenium.interactions.Actions; 10 | import org.openqa.selenium.support.ui.Select; 11 | 12 | import java.util.List; 13 | import java.util.Set; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | public class WebActionHelperMethods { 17 | 18 | private WebDriver driver; 19 | 20 | public WebActionHelperMethods(WebDriver driver) { 21 | this.driver = driver; 22 | } 23 | 24 | public void writeOnEditText(String data, String xpath) { 25 | driver.findElement(By.xpath(xpath)).sendKeys(data); 26 | } 27 | 28 | public boolean clickbutton(String xpath) { 29 | driver.findElement(By.xpath(xpath)).click(); 30 | return true; 31 | } 32 | 33 | public boolean clickbutton(WebElement xpath) { 34 | xpath.click(); 35 | return true; 36 | } 37 | 38 | public void clickLink(String data) { 39 | driver.findElement(By.linkText(data)); 40 | } 41 | 42 | public void clickImage(String data, String xpath) { 43 | driver.findElement(By.xpath(xpath)).click(); 44 | } 45 | 46 | public String getObjectText(String xpath) { 47 | return driver.findElement(By.xpath(xpath)).getText(); 48 | } 49 | 50 | public boolean compareString(String First, String Second) { 51 | if (First.equalsIgnoreCase(Second)) { 52 | return true; 53 | } else 54 | return false; 55 | 56 | } 57 | 58 | public boolean containsString(String First, String Second) { 59 | if (First.contains(Second)) { 60 | return true; 61 | } else 62 | return false; 63 | 64 | } 65 | 66 | /** 67 | * This Keyword verifies the Text of an specified object on the web page. It 68 | * takes an object as object input argument and before & after as data input 69 | * arguments. 70 | * 71 | * @param Text 72 | * @param xpath 73 | * @return 74 | */ 75 | public boolean verifyObjectText(String Text, String xpath) { 76 | 77 | return compareString(Text, driver.findElement(By.xpath(xpath)) 78 | .getText()); 79 | } 80 | 81 | /** 82 | * This keyword verifies whether the specified object exist over the given 83 | * web page or not. This keyword takes object as object input argument. 84 | * 85 | * @param xpath 86 | * @return 87 | */ 88 | public boolean VerifyObjectExists(String xpath) { 89 | if (driver.findElement(By.xpath(xpath)).isDisplayed()) { 90 | return true; 91 | 92 | } else { 93 | return false; 94 | } 95 | } 96 | 97 | /** 98 | * This keyword verifies that the provided Object is enabled on page or not. 99 | * This keyword is mostly used in situations where you have to provide an 100 | * Object and want to verify that the particular object is enabled on the 101 | * page or not. 102 | * 103 | * @param xpath 104 | * @return 105 | */ 106 | public boolean VerifyObjectEnabled(String xpath) { 107 | if (driver.findElement(By.xpath(xpath)).isEnabled()) { 108 | return true; 109 | 110 | } else { 111 | return false; 112 | } 113 | } 114 | 115 | /** 116 | * This keyword verifies that the specified object is disabled on the page. 117 | * 118 | * @param xpath 119 | * @return 120 | */ 121 | public boolean VerifyObjectDisabled(String xpath) { 122 | if (driver.findElement(By.xpath(xpath)).isEnabled()) { 123 | return true; 124 | 125 | } else { 126 | return false; 127 | } 128 | } 129 | 130 | /** 131 | * Method is used to get Internal text 132 | * 133 | * @param xpath 134 | * @return 135 | * @author Ashish 136 | */ 137 | public String getobjectValue(String xpath) { 138 | return driver.findElement(By.xpath(xpath)).getAttribute("value"); 139 | } 140 | 141 | /** 142 | * This keyword clears the value of specified Edit box. 143 | * 144 | * @param xpath 145 | */ 146 | public void ClearEditField(String xpath) { 147 | driver.findElement(By.xpath(xpath)).clear(); 148 | } 149 | 150 | /** 151 | * This keyword clears the text from specified TextArea 152 | * 153 | * @param xpath 154 | */ 155 | public void ClearTextArea(String xpath) { 156 | driver.findElement(By.xpath(xpath)).clear(); 157 | } 158 | 159 | /** 160 | * This keyword clicks on given button and waits for the specified Time. It 161 | * takes Button object and time in seconds as input argument. 162 | * 163 | * @param xpath 164 | * @param time 165 | * @throws Exception 166 | */ 167 | public void ClickButtonAndWait(String xpath, long time) throws Exception { 168 | driver.findElement(By.xpath(xpath)).click(); 169 | TimeUnit.SECONDS.sleep(time); 170 | } 171 | 172 | /** 173 | * This keyword closes all the open browser sessions started by Selenium. It 174 | * does not take any input argument. 175 | * 176 | * @return 177 | */ 178 | public boolean CloseAllBrowsers() { 179 | try { 180 | driver.quit(); 181 | return true; 182 | } catch (Exception e) { 183 | return false; 184 | } 185 | } 186 | 187 | /** 188 | * This keyword closes the currently opened browser session. 189 | * 190 | * @return 191 | */ 192 | public boolean CloseBrowser() { 193 | try { 194 | driver.close(); 195 | return true; 196 | } catch (Exception e) { 197 | return false; 198 | } 199 | } 200 | 201 | /** 202 | * This keyword closes the selected window. It takes title name of the 203 | * window to be closed as data input argument. 204 | * 205 | * @param title 206 | * @return 207 | */ 208 | public boolean CloseSelectedWindow(String title) { 209 | String currentWindow = driver.getWindowHandle(); 210 | Set windows = driver.getWindowHandles(); 211 | for (String window : windows) { 212 | if (driver.switchTo().window(window).getTitle().equals(title)) { 213 | driver.close(); 214 | return true; 215 | } else { 216 | driver.switchTo().window(currentWindow); 217 | return false; 218 | } 219 | 220 | } 221 | return false; 222 | } 223 | 224 | /** 225 | * This keyword double clicks on the specified object. 226 | * 227 | * @param xpath 228 | * @return 229 | */ 230 | public boolean DoubleClick(String xpath) { 231 | try { 232 | new Actions(driver) 233 | .doubleClick(driver.findElement(By.xpath(xpath))).build() 234 | .perform(); 235 | 236 | return true; 237 | } catch (Exception e) { 238 | return false; 239 | } 240 | } 241 | 242 | /** 243 | * This keyword double clicks on an object and waits for the specified time 244 | * after double click. 245 | * 246 | * @param xpath 247 | * @param seconds 248 | * @return 249 | */ 250 | public boolean DoubleClickAndWait(String xpath, long seconds) { 251 | try { 252 | new Actions(driver) 253 | .doubleClick(driver.findElement(By.xpath(xpath))).build() 254 | .perform(); 255 | TimeUnit.SECONDS.sleep(seconds); 256 | return true; 257 | } catch (Exception e) { 258 | return false; 259 | } 260 | 261 | } 262 | 263 | /** 264 | * This keyword double clicks on object according to specified co-ordinates. 265 | * It is used in situations where you want to double click on Object 266 | * according to its position on web page, when we are not able to identify 267 | * that object. 268 | * 269 | * @param xpath 270 | * @param start 271 | * @param end 272 | * @return 273 | */ 274 | 275 | public boolean DoubleClickAt(String xpath, int start, int end) { 276 | try { 277 | new Actions(driver) 278 | .moveToElement(driver.findElement(By.xpath(xpath))) 279 | .moveByOffset(start, end).click().perform(); 280 | return true; 281 | } catch (Exception e) { 282 | return false; 283 | } 284 | } 285 | 286 | /** 287 | * This keyword presses the Enter key. 288 | * 289 | * @param xpath 290 | * @return 291 | */ 292 | public boolean Enter(String xpath) { 293 | try { 294 | driver.findElement(By.xpath(xpath)).sendKeys(Keys.ENTER); 295 | return true; 296 | } catch (Exception e) { 297 | return false; 298 | } 299 | } 300 | 301 | /** 302 | * This keyword presses the ESC key. 303 | * 304 | * @param xpath 305 | * @return 306 | */ 307 | public boolean pressESC(String xpath) { 308 | try { 309 | driver.findElement(By.xpath(xpath)).sendKeys(Keys.ESCAPE); 310 | return true; 311 | } catch (Exception e) { 312 | return false; 313 | } 314 | } 315 | 316 | 317 | /** 318 | * This keyword presses the ESC key. 319 | * 320 | * @param xpath 321 | * @return 322 | */ 323 | public boolean pressESC(WebElement xpath) { 324 | try { 325 | xpath.sendKeys(Keys.ESCAPE); 326 | return true; 327 | } catch (Exception e) { 328 | return false; 329 | } 330 | } 331 | /** 332 | * This keyword navigates back to previous page and then wait for specified 333 | * seconds. 334 | * 335 | * @param seconds 336 | * @return 337 | */ 338 | public boolean GoBackAndWait(long seconds) { 339 | try { 340 | driver.navigate().back(); 341 | TimeUnit.SECONDS.sleep(seconds); 342 | return true; 343 | } catch (Exception e) { 344 | return false; 345 | } 346 | } 347 | 348 | /** 349 | * This keyword navigates forward to next browser page. 350 | * 351 | * @return 352 | */ 353 | public boolean GoForward() { 354 | try { 355 | driver.navigate().forward(); 356 | // TimeUnit.SECONDS.sleep(seconds); 357 | return true; 358 | } catch (Exception e) { 359 | return false; 360 | } 361 | } 362 | 363 | /** 364 | * This keyword navigates forward to next browser page. 365 | * 366 | * @return 367 | */ 368 | public boolean NavigateTo(String URL) { 369 | try { 370 | driver.navigate().to(URL); 371 | // TimeUnit.SECONDS.sleep(seconds); 372 | return true; 373 | } catch (Exception e) { 374 | return false; 375 | } 376 | } 377 | 378 | /** 379 | * This keyword navigates forward to next browser page and waits for 380 | * specified time. It takes timeout (sec) as input parameter. 381 | * 382 | * @param seconds 383 | * @return 384 | */ 385 | public boolean GoForwardAndWait(long seconds) { 386 | try { 387 | driver.navigate().forward(); 388 | TimeUnit.SECONDS.sleep(seconds); 389 | return true; 390 | } catch (Exception e) { 391 | return false; 392 | } 393 | } 394 | 395 | /** 396 | * This keyword presses left Arrow Key of keyboard. It does not take any 397 | * input argument. 398 | * 399 | * @param xpath 400 | * @return true else false 401 | */ 402 | public boolean KeyLeft(String xpath) { 403 | try { 404 | driver.findElement(By.xpath(xpath)).sendKeys(Keys.ARROW_LEFT); 405 | return true; 406 | } catch (Exception e) { 407 | return false; 408 | } 409 | 410 | } 411 | 412 | /** 413 | * This keyword presses Right Arrow Key of keyboard. It does not take any 414 | * input argument. 415 | * 416 | * @param xpath 417 | * @return 418 | */ 419 | public boolean KeyRight(String xpath) { 420 | try { 421 | driver.findElement(By.xpath(xpath)).sendKeys(Keys.RIGHT); 422 | return true; 423 | } catch (Exception e) { 424 | return false; 425 | } 426 | 427 | } 428 | 429 | /** 430 | * This keyword presses Down Arrow Key of keyboard. It does not take any 431 | * input argument. 432 | * 433 | * @param xpath 434 | * @return true else false 435 | */ 436 | public boolean KeyDown(String xpath) { 437 | try { 438 | driver.findElement(By.xpath(".//a")).sendKeys(Keys.ARROW_DOWN); 439 | return true; 440 | } catch (Exception e) { 441 | return false; 442 | } 443 | 444 | } 445 | 446 | /** 447 | * This keyword presses Page Down Key of keyboard. It takes Key, No. of 448 | * repetition as input parameter. input argument. 449 | *

450 | * If you want to press a pagedown single time, then Pass 1 and so on. 451 | * 452 | * @return true else false 453 | */ 454 | public boolean PageDown(int PageDownTimes) { 455 | try { 456 | while (PageDownTimes > 0) { 457 | driver.findElement(By.xpath(".//a")).sendKeys(Keys.PAGE_DOWN); 458 | PageDownTimes--; 459 | } 460 | 461 | return true; 462 | } catch (Exception e) { 463 | return false; 464 | } 465 | 466 | } 467 | 468 | /** 469 | * This keyword presses Page Up Key of keyboard. It takes Key, No. of 470 | * repetition as input parameter. input argument. 471 | *

472 | * If you want to press a Page Up single time, then Pass 1 and so on. 473 | * 474 | * @return true else false 475 | */ 476 | public boolean PageUP(int PageUpTimes) { 477 | try { 478 | while (PageUpTimes > 0) { 479 | driver.findElement(By.xpath(".//a")).sendKeys(Keys.PAGE_UP); 480 | PageUpTimes--; 481 | } 482 | 483 | return true; 484 | } catch (Exception e) { 485 | return false; 486 | } 487 | 488 | } 489 | 490 | /** 491 | * This keyword maximizes the current browser. 492 | * 493 | * @return 494 | */ 495 | public boolean MaximizeBrowser() { 496 | try { 497 | driver.manage().window().maximize(); 498 | return true; 499 | } catch (Exception e) { 500 | return false; 501 | } 502 | 503 | } 504 | 505 | /** 506 | * This keyword hovers mouse on specified OR object. 507 | * 508 | * @param xpath 509 | * @return 510 | */ 511 | public boolean MouseHover(String xpath) { 512 | try { 513 | new Actions(driver).moveToElement(driver.findElement(By.xpath(xpath))).perform(); 514 | return true; 515 | } catch (Exception e) { 516 | return false; 517 | } 518 | 519 | } 520 | 521 | /** 522 | * This keyword refreshes the current browser session. 523 | * 524 | * @return 525 | */ 526 | public boolean RefreshBrowser() { 527 | try { 528 | driver.navigate().refresh(); 529 | //driver.get(driver.getCurrentUrl()); 530 | //driver.findElement(By.xpath(".//a")).sendKeys(Keys.F5); 531 | 532 | return true; 533 | } catch (Exception e) { 534 | return false; 535 | } 536 | 537 | } 538 | 539 | /** 540 | * This keyword refreshes the browser page and waits for the given timeout. 541 | * This keyword takes timeout (in seconds) to wait after refreshing the 542 | * page. 543 | * 544 | * @param seconds 545 | * @return 546 | */ 547 | public boolean RefreshAndWait(long seconds) { 548 | try { 549 | driver.navigate().refresh(); 550 | TimeUnit.SECONDS.sleep(seconds); 551 | return true; 552 | } catch (Exception e) { 553 | return false; 554 | } 555 | 556 | } 557 | 558 | /** 559 | * This keyword Right clicks on object. This keyword is mostly used in 560 | * situations where you want to perform a Right Click on provided Object 561 | * before performing any action on it. 562 | *

563 | * For example, you want to Click Right on Object. 564 | * 565 | * @param xpath 566 | * @return 567 | */ 568 | public boolean RightClickOnObject(String xpath) { 569 | try { 570 | new Actions(driver) 571 | .contextClick(driver.findElement(By.xpath(xpath))).build().perform(); 572 | 573 | return true; 574 | } catch (Exception e) { 575 | return false; 576 | } 577 | 578 | } 579 | 580 | public boolean OpenNewTab() { 581 | try { 582 | driver.findElement(By.xpath(".//a")).sendKeys(Keys.CONTROL, "t"); 583 | return true; 584 | } catch (Exception e) { 585 | return false; 586 | } 587 | } 588 | 589 | 590 | /** 591 | * LiDropdown is used where dropdown contains values in 592 | * li tag 593 | * 594 | * @return 595 | *//* 596 | 597 | public boolean LiDropdown(Xpath.Locators LocatorType, String LocatorValue, String value) { 598 | List elements = driver.findElements(Locators(LocatorType, LocatorValue)); 599 | elements.stream().filter(p -> p.getText().trim().equalsIgnoreCase(value)).findFirst().get().click(); 600 | return true; 601 | 602 | 603 | *//* elements.stream().forEach(a -> { 604 | System.out.println(a.getText()); 605 | if (a.getText().contains((value))) { 606 | a.click(); 607 | } 608 | }); 609 | return true; 610 | *//* 611 | }*/ 612 | public void SelectByValue() { 613 | 614 | Select select = new Select(driver.findElement(By.xpath(""))); 615 | select.selectByIndex(1); 616 | } 617 | 618 | 619 | public boolean selectdropdown(String xpath, String value) { 620 | 621 | try { 622 | List elements = driver.findElements(By.xpath(xpath)); 623 | 624 | for (WebElement element : elements) { 625 | System.out.println(element.getText()); 626 | if (element.getText().contains(value)) { 627 | // System.out.println(element.getText()); 628 | element.click(); 629 | } 630 | } 631 | return true; 632 | } catch (Exception e) { 633 | System.out.println(e.getMessage()); 634 | } 635 | return false; 636 | } 637 | 638 | } -------------------------------------------------------------------------------- /src/main/java/driverManager/DriverManagerType.java: -------------------------------------------------------------------------------- 1 | package driverManager; 2 | 3 | public enum DriverManagerType { 4 | ANDROID("AndroidDriver", "Init AndroidDiver"), 5 | CHROME("ChromeDriver", "Init ChromeDriver"), 6 | FIREFOX("firefoxdriver", "Init firefoxdriver"), 7 | IE("iedriver", "Init iedriver"); 8 | 9 | private String driverName; 10 | private String desc; 11 | 12 | 13 | DriverManagerType(String driverName, String desc) { 14 | this.driverName = driverName; 15 | this.desc = desc; 16 | } 17 | 18 | /** 19 | * Gets the Driver 20 | * 21 | * @return get the Driver 22 | */ 23 | public String getDriver() { 24 | return driverName; 25 | } 26 | 27 | public String getDriverdesc() { 28 | return desc; 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/driverManager/WebDrivers.java: -------------------------------------------------------------------------------- 1 | package driverManager; 2 | 3 | import io.github.bonigarcia.wdm.WebDriverManager; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.chrome.ChromeDriver; 6 | import org.openqa.selenium.chrome.ChromeOptions; 7 | import org.openqa.selenium.firefox.FirefoxDriver; 8 | import org.openqa.selenium.ie.InternetExplorerDriver; 9 | 10 | public class WebDrivers {public static WebDriver getDriver(DriverManagerType browserName) { 11 | switch (browserName.getDriver()) { 12 | case "ChromeDriver": 13 | ChromeOptions chromeOptions = new ChromeOptions(); 14 | // chromeOptions.addArguments("--headless"); 15 | chromeOptions.addArguments("--disable-notifications"); 16 | WebDriverManager.chromedriver().setup(); 17 | return new ChromeDriver(chromeOptions); 18 | case "firefoxdriver": 19 | WebDriverManager.firefoxdriver().setup(); 20 | return new FirefoxDriver(); 21 | case "iedriver": 22 | WebDriverManager.iedriver().setup(); 23 | return new InternetExplorerDriver(); 24 | } 25 | return null; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/listeners/TestListner.java: -------------------------------------------------------------------------------- 1 | package listeners; 2 | 3 | import com.aventstack.extentreports.ExtentReports; 4 | import com.aventstack.extentreports.ExtentTest; 5 | import com.aventstack.extentreports.markuputils.ExtentColor; 6 | import com.aventstack.extentreports.markuputils.MarkupHelper; 7 | import org.testng.ITestContext; 8 | import org.testng.ITestListener; 9 | import org.testng.ITestResult; 10 | import org.testng.TestListenerAdapter; 11 | import reportManager.ExtentManager; 12 | 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | public class TestListner implements ITestListener { 16 | private ConcurrentHashMap allTests = new ConcurrentHashMap<>(); 17 | String reportFolderPath = System.getProperty("user.dir") + "//AutomationReports//"; 18 | String reportName = "AutomationReport.html"; 19 | 20 | //After ending all tests, below method runs. 21 | @Override 22 | public void onFinish(ITestContext iTestContext) { 23 | ExtentManager.getInstance().flush(); 24 | } 25 | 26 | @Override 27 | public void onTestStart(ITestResult iTestResult) { 28 | ExtentTest extentTest = ExtentManager.createInstance(reportFolderPath, reportName).createTest(iTestResult.getMethod().getRealClass().getSimpleName()); 29 | allTests.put(iTestResult.getClass().getSimpleName(), extentTest); 30 | ExtentManager.setTest(extentTest); 31 | ExtentManager.getInstance().flush(); 32 | } 33 | 34 | @Override 35 | public void onTestSuccess(ITestResult iTestResult) { 36 | ExtentManager.getTest().get().assignCategory(iTestResult.getClass().getSimpleName()); 37 | ExtentManager.getTest().get().createNode(MarkupHelper.createLabel("Test passed", ExtentColor.GREEN).getMarkup()); 38 | ExtentManager.getInstance().flush(); 39 | } 40 | 41 | @Override 42 | public void onTestFailure(ITestResult iTestResult) { 43 | try { 44 | ExtentManager.getTest().get().createNode(MarkupHelper.createLabel("Test Failed", ExtentColor.RED).getMarkup()) 45 | .fail(iTestResult.getThrowable()); 46 | ExtentManager.getInstance().flush(); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | @Override 53 | public void onTestSkipped(ITestResult iTestResult) { 54 | 55 | } 56 | 57 | @Override 58 | public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) { 59 | } 60 | 61 | @Override 62 | public void onStart(ITestContext iTestContext) { 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/java/reportManager/ExtentManager.java: -------------------------------------------------------------------------------- 1 | package reportManager; 2 | 3 | import com.aventstack.extentreports.ExtentReports; 4 | import com.aventstack.extentreports.ExtentTest; 5 | import com.aventstack.extentreports.reporter.ExtentHtmlReporter; 6 | import com.aventstack.extentreports.reporter.configuration.Theme; 7 | 8 | public class ExtentManager { 9 | 10 | private static ExtentReports extentReports = null; 11 | private static ThreadLocal extent = new ThreadLocal(); 12 | private static ThreadLocal test = new ThreadLocal(); 13 | private static ThreadLocal child = new ThreadLocal(); 14 | private static ThreadLocal subchild = new ThreadLocal(); 15 | 16 | public ExtentManager() { 17 | } 18 | 19 | 20 | public synchronized static ThreadLocal getTest() { 21 | return test; 22 | } 23 | 24 | public synchronized static void setTest(ExtentTest test) { 25 | getTest().set(test); 26 | } 27 | 28 | public synchronized static ThreadLocal getChild() { 29 | return child; 30 | } 31 | 32 | public synchronized static void setChild(ExtentTest child) { 33 | getChild().set(child); 34 | } 35 | 36 | public static ThreadLocal getExtent() { 37 | return extent; 38 | } 39 | 40 | public static void setExtent(ExtentReports extent) { 41 | getExtent().set(extent); 42 | } 43 | 44 | public static ExtentReports getInstance() { 45 | return extentReports; 46 | } 47 | 48 | public static ExtentReports createInstance(String reportFolderPath, String reportName) { 49 | if (extentReports == null) { 50 | ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(reportFolderPath + reportName); 51 | htmlReporter.config().setDocumentTitle("Automation Report"); 52 | htmlReporter.config().setReportName("Automation Reports "); 53 | htmlReporter.config().setTheme(Theme.STANDARD); 54 | htmlReporter.config().setEncoding("utf-8"); 55 | extentReports = new ExtentReports(); 56 | extentReports.attachReporter(htmlReporter); 57 | setExtent(extentReports); 58 | return getExtent().get(); 59 | } 60 | return extentReports; 61 | } 62 | 63 | public static void addExecutionDetails_ExtentReport() { 64 | getExtent().get().flush(); 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/main/java/util/utility.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.Properties; 8 | 9 | public class utility { 10 | 11 | static Properties properties; 12 | static InputStream input; 13 | 14 | public static Properties loadProperties(String path) { 15 | try { 16 | input = new FileInputStream(path); 17 | properties = new Properties(); 18 | properties.load(input); 19 | return properties; 20 | 21 | } catch (FileNotFoundException e) { 22 | e.printStackTrace(); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | return properties; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/Pages/BasePageClass.java: -------------------------------------------------------------------------------- 1 | package Pages; 2 | 3 | import actionHelper.WebActionHelperMethods; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.support.PageFactory; 6 | 7 | public class BasePageClass { 8 | protected WebDriver driver; 9 | static WebActionHelperMethods webActionHelperMethods; 10 | 11 | public BasePageClass(WebDriver driver) { 12 | this.driver = driver; 13 | PageFactory.initElements(driver, this); 14 | webActionHelperMethods= new WebActionHelperMethods(driver); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/Pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package Pages; 2 | 3 | import org.openqa.selenium.Keys; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.PageFactory; 8 | 9 | public class HomePage extends BasePageClass { 10 | public HomePage(WebDriver driver) { 11 | super(driver); 12 | } 13 | 14 | @FindBy(xpath = "//*[@placeholder=\"Search for products, brands and more\"]") 15 | WebElement searchForProducts; 16 | 17 | @FindBy(xpath = "") 18 | WebElement mobileNames; 19 | 20 | public void searchForProducts() { 21 | webActionHelperMethods.clickbutton(searchForProducts); 22 | searchForProducts.sendKeys("Mobiles"); 23 | searchForProducts.sendKeys(Keys.ENTER); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/Pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | package Pages; 2 | 3 | import actionHelper.WebActionHelperMethods; 4 | import org.openqa.selenium.Keys; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.FindBy; 8 | 9 | public class LoginPage extends BasePageClass { 10 | 11 | public LoginPage(WebDriver driver) { 12 | super(driver); 13 | } 14 | 15 | @FindBy(xpath = "//*[@type=\"submit\"]") 16 | WebElement loginBtn; 17 | 18 | 19 | 20 | public void pressExc() { 21 | webActionHelperMethods.pressESC(loginBtn); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/TestCases/BaseTest.java: -------------------------------------------------------------------------------- 1 | package TestCases; 2 | 3 | import Pages.LoginPage; 4 | import Pages.HomePage; 5 | import driverManager.DriverManagerType; 6 | import driverManager.WebDrivers; 7 | import org.openqa.selenium.WebDriver; 8 | import org.testng.annotations.AfterSuite; 9 | import org.testng.annotations.BeforeSuite; 10 | import util.utility; 11 | 12 | import java.util.Properties; 13 | 14 | public class BaseTest { 15 | 16 | protected LoginPage loginPage; 17 | protected HomePage homePage; 18 | WebDriver driver; 19 | Properties properties; 20 | static String URL; 21 | 22 | @BeforeSuite 23 | public void setUp() { 24 | String propertyPath = System.getProperty("user.dir") + "//src//test//resources//Env.properties"; 25 | try { 26 | driver = WebDrivers.getDriver(DriverManagerType.CHROME); 27 | properties = utility.loadProperties(propertyPath); 28 | URL = properties.getProperty("URL"); 29 | 30 | loginPage = new LoginPage(driver); 31 | homePage = new HomePage(driver); 32 | 33 | 34 | } catch (Exception e) { 35 | System.out.println(e.getMessage()); 36 | } 37 | } 38 | 39 | @AfterSuite 40 | public void destroyDriver() { 41 | driver.quit(); 42 | } 43 | } -------------------------------------------------------------------------------- /src/test/java/TestCases/LoginTestCases.java: -------------------------------------------------------------------------------- 1 | package TestCases; 2 | 3 | import org.testng.annotations.BeforeMethod; 4 | import org.testng.annotations.Test; 5 | 6 | public class LoginTestCases extends BaseTest { 7 | 8 | 9 | @Test 10 | public void TEST_CASE_ONE() { 11 | driver.get(URL); 12 | loginPage.pressExc(); 13 | } 14 | 15 | @Test 16 | public void TEST_CASE_TWO() throws Exception { 17 | driver.get(URL); 18 | loginPage.pressExc(); 19 | homePage.searchForProducts(); 20 | 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/Env.properties: -------------------------------------------------------------------------------- 1 | URL=https://www.flipkart.com/ -------------------------------------------------------------------------------- /target/classes/META-INF/Selenium-POM-Java.kotlin_module: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /target/classes/actionHelper/WebActionHelperMethods.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/actionHelper/WebActionHelperMethods.class -------------------------------------------------------------------------------- /target/classes/driverManager/DriverManagerType.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/driverManager/DriverManagerType.class -------------------------------------------------------------------------------- /target/classes/driverManager/WebDrivers.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/driverManager/WebDrivers.class -------------------------------------------------------------------------------- /target/classes/listeners/TestListner.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/listeners/TestListner.class -------------------------------------------------------------------------------- /target/classes/reportManager/ExtentManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/reportManager/ExtentManager.class -------------------------------------------------------------------------------- /target/classes/util/utility.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/classes/util/utility.class -------------------------------------------------------------------------------- /target/test-classes/Env.properties: -------------------------------------------------------------------------------- 1 | URL=https://www.flipkart.com/ -------------------------------------------------------------------------------- /target/test-classes/META-INF/Selenium-POM-Java.kotlin_module: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /target/test-classes/Pages/BasePageClass.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/test-classes/Pages/BasePageClass.class -------------------------------------------------------------------------------- /target/test-classes/Pages/HomePage.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/test-classes/Pages/HomePage.class -------------------------------------------------------------------------------- /target/test-classes/Pages/LoginPage.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/test-classes/Pages/LoginPage.class -------------------------------------------------------------------------------- /target/test-classes/TestCases/BaseTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/test-classes/TestCases/BaseTest.class -------------------------------------------------------------------------------- /target/test-classes/TestCases/LoginTestCases.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashishjublsdet/Selenium-PageObject-Java-AutomationFramework/71d1b57dab8c3d4311b68e6a5ae9374aafad3292/target/test-classes/TestCases/LoginTestCases.class -------------------------------------------------------------------------------- /test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------