├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── kz │ └── qwertukg │ ├── searchContextElementsExtensions.kt │ ├── searchContextExtensions.kt │ ├── webDriver.kt │ ├── webDriverOptions.kt │ └── webDriverWaitExtensions.kt └── test └── java └── kz └── qwertukg ├── WebDriverKtTest.kt └── base.kt /.gitignore: -------------------------------------------------------------------------------- 1 | ### Common ### 2 | target/ 3 | resources/ 4 | 5 | 6 | 7 | ### IntelliJ IDEA ### 8 | .idea 9 | *.iml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Daniil Rakhmatulin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SeleniumBuilder 2 | DSL for Selenium. Provide a possibility to write tests in [Kotlin type-safe builders](https://kotlinlang.org/docs/reference/type-safe-builders.html#a-type-safe-builder-example) style 3 | 4 | ## Sample 5 | ```kotlin 6 | driver(ChromeDriver()) { 7 | get("http://cool-website.com") 8 | 9 | elementByClass("login") { 10 | sendKeys("user@example.com") 11 | } 12 | 13 | elementByName("password") { 14 | sendKeys("123456") 15 | submit() 16 | } 17 | 18 | element(By.className("search")) { 19 | sendKeys("kotlin") 20 | } 21 | 22 | wait(10) { 23 | elementVisibilityById("result-item") { 24 | elementByClass("salary") { 25 | item.salary = text 26 | } 27 | } 28 | } 29 | } 30 | ``` 31 | 32 | ## Total function list 33 | 34 | #### Driver builders 35 | 36 | `driver(driver: WebDriver) {}` 37 | 38 | `chromeDriver {}` 39 | 40 | `chromeDriver(pathToDriver: String) {}` 41 | 42 | `firefoxDriver {}` 43 | 44 | `firefoxDriver(pathToDriver: String) {}` 45 | 46 | #### `WebDriver` and `WebElement` element builders 47 | 48 | `element(by: By) {}` 49 | 50 | `elementById(id: String) {}` 51 | 52 | `elementByClass(className: String) {}` 53 | 54 | `elementByName(name: String) {}` 55 | 56 | `elementBySelector(selector: String) {}` 57 | 58 | `elementByXpath(selector: String) {}` 59 | 60 | #### `WebDriver` and `WebElement` element list builders 61 | 62 | `elements(by: By) {}` 63 | 64 | `elementsById(id: String) {}` 65 | 66 | `elementsByClass(className: String) {}` 67 | 68 | `elementsByName(name: String) {}` 69 | 70 | `elementsBySelector(selector: String) {}` 71 | 72 | `elementsByXpath(selector: String) {}` 73 | 74 | #### `WebDriver` and `WebElement` element exists functions 75 | 76 | `elementExists(by: By): Boolean` 77 | 78 | `elementByIdExists(id: String): Boolean` 79 | 80 | `elementByClassExists(className: String): Boolean` 81 | 82 | `elementByNameExists(name: String): Boolean` 83 | 84 | `elementBySelectorExists(selector: String): Boolean` 85 | 86 | `elementByXpathExists(selector: String): Boolean` 87 | 88 | #### `WebDriver` `WebDriverWait` builder 89 | 90 | `wait(timeout: Long) {}` 91 | 92 | #### `WebDriverWait` element visibility builders 93 | 94 | `elementVisibility(by: By) {}` 95 | 96 | `elementVisibilityById(id: String) {}` 97 | 98 | `elementVisibilityByClass(className: String) {}` 99 | 100 | `elementVisibilityByName(name: String) {}` 101 | 102 | `elementVisibilityBySelector(selector: String) {}` 103 | 104 | `elementVisibilityByXpath(xpath: String) {}` 105 | 106 | #### `WebDriverWait` element invisibility functions 107 | 108 | `elementInvisibility(by: By): Boolean` 109 | 110 | `elementInvisibilityById(id: String): Boolean` 111 | 112 | `elementInvisibilityByClass(className: String): Boolean` 113 | 114 | `elementInvisibilityByName(name: String): Boolean` 115 | 116 | `elementInvisibilityBySelector(selector: String): Boolean` 117 | 118 | `elementInvisibilityByXpath(xpath: String): Boolean` 119 | 120 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | kz.qwertukg 8 | SeleniumBuilder 9 | 0.1 10 | 11 | 12 | 1.2.30 13 | 14 | 15 | 16 | 17 | org.jetbrains.kotlin 18 | kotlin-stdlib-jdk8 19 | ${kotlin.version} 20 | 21 | 22 | org.jetbrains.kotlin 23 | kotlin-test-junit 24 | ${kotlin.version} 25 | test 26 | 27 | 28 | 29 | com.google.guava 30 | guava 31 | 23.6-jre 32 | 33 | 34 | 35 | 36 | org.seleniumhq.selenium 37 | selenium-java 38 | 3.10.0 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.jetbrains.kotlin 46 | kotlin-maven-plugin 47 | ${kotlin.version} 48 | 49 | 50 | compile 51 | compile 52 | 53 | compile 54 | 55 | 56 | 57 | test-compile 58 | test-compile 59 | 60 | test-compile 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/kz/qwertukg/searchContextElementsExtensions.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package kz.qwertukg 4 | 5 | import org.openqa.selenium.By 6 | import org.openqa.selenium.SearchContext 7 | import org.openqa.selenium.WebElement 8 | 9 | /* 10 | * withElements collection functions 11 | * */ 12 | 13 | /* 14 | * Find elementS by 15 | * */ 16 | inline fun SearchContext.withElements(by: By, init: Iterable.() -> Unit) { 17 | findElements(by).init() 18 | } 19 | 20 | /* 21 | * Find elementS by class 22 | * */ 23 | inline fun SearchContext.withElementsByClass(className: String, init: Iterable.() -> Unit) = 24 | withElements(By.className(className), init) 25 | 26 | /* 27 | * Find elementS by name 28 | * */ 29 | inline fun SearchContext.withElementsByName(name: String, init: Iterable.() -> Unit) = 30 | withElements(By.name(name), init) 31 | 32 | /* 33 | * Find elementS by css selector. 34 | * */ 35 | inline fun SearchContext.withElementsBySelector(selector: String, init: Iterable.() -> Unit) = 36 | withElements(By.cssSelector(selector), init) 37 | 38 | /* 39 | * Find element by xpath 40 | * */ 41 | inline fun SearchContext.withElementsByXpath(xpath: String, init: Iterable.() -> Unit) { 42 | withElements(By.xpath(xpath), init) 43 | } 44 | 45 | /* 46 | * Find elementS by 47 | * */ 48 | inline fun SearchContext.eachElement(by: By, init: WebElement.() -> Unit) { 49 | findElements(by).forEach(init) 50 | } 51 | 52 | /* 53 | * Find element by tag 54 | * */ 55 | inline fun SearchContext.eachElementByTag(tag: String, init: WebElement.() -> Unit) { 56 | eachElement(By.tagName(tag), init) 57 | } 58 | 59 | /* 60 | * Find element by xpath 61 | * */ 62 | inline fun SearchContext.eachElementByXPath(xpath: String, init: WebElement.() -> Unit) { 63 | eachElement(By.xpath(xpath), init) 64 | } 65 | 66 | /* 67 | * Find element by class name 68 | * */ 69 | inline fun SearchContext.eachElementByClassName(className: String, init: WebElement.() -> Unit) { 70 | eachElement(By.className(className), init) 71 | } 72 | 73 | /* 74 | * Find element by class name 75 | * */ 76 | inline fun SearchContext.eachElementByCssSelector(cssSelector: String, init: WebElement.() -> Unit) { 77 | eachElement(By.cssSelector(cssSelector), init) 78 | } 79 | 80 | /* 81 | * Find withElements by xpath 82 | * */ 83 | inline fun SearchContext.elementsByXPath(xpath: String, init: List.() -> T): T { 84 | return findElements(By.xpath(xpath)).init() 85 | } 86 | 87 | /* 88 | * Find elementS by 89 | * */ 90 | fun SearchContext.elements(by: By) : List = findElements(by) 91 | 92 | fun SearchContext.elementsByTag(tag: String) = elements(By.tagName(tag)) 93 | 94 | fun SearchContext.elementsByName(tag: String) = elements(By.name(tag)) 95 | 96 | fun SearchContext.elementsByXPath(tag: String) = elements(By.xpath(tag)) 97 | 98 | fun SearchContext.elementsByLinkText(tag: String) = elements(By.linkText(tag)) 99 | 100 | fun SearchContext.elementsByClassName(tag: String) = elements(By.className(tag)) 101 | 102 | fun SearchContext.elementsByCssSelector(tag: String) = elements(By.cssSelector(tag)) 103 | 104 | fun SearchContext.elementsByPartialLinkText(tag: String) = elements(By.partialLinkText(tag)) 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/main/java/kz/qwertukg/searchContextExtensions.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.openqa.selenium.By 4 | import org.openqa.selenium.SearchContext 5 | import org.openqa.selenium.WebDriver 6 | import org.openqa.selenium.WebElement 7 | import org.openqa.selenium.support.ui.WebDriverWait 8 | 9 | /** 10 | * Selenium Kotlin Builder 11 | * Created by Daniil Rakhmatulin 12 | * http://daniil.rakhmatulin.kz 13 | */ 14 | 15 | /* 16 | * Build WebDriverWait with timeout 17 | * */ 18 | fun WebDriver.wait(timeout: Long, sleepTimeout: Long = 500, init: WebDriverWait.() -> Unit) { 19 | WebDriverWait(this, timeout, sleepTimeout).init() 20 | } 21 | 22 | /* 23 | * Single element functions 24 | * */ 25 | 26 | /* 27 | * Find element by 28 | * */ 29 | inline fun SearchContext.element(by: By, init: WebElement.() -> Unit) { 30 | findElement(by).init() 31 | } 32 | 33 | /* 34 | * Find element by id 35 | * */ 36 | 37 | inline fun SearchContext.elementById(id: String, init: WebElement.() -> Unit) { 38 | findElement(By.id(id)).init() 39 | } 40 | 41 | /* 42 | * Find element by class 43 | * */ 44 | inline fun SearchContext.elementByClass(className: String, init: WebElement.() -> T): T { 45 | return findElement(By.className(className)).init() 46 | } 47 | 48 | /* 49 | * Find element by name 50 | * */ 51 | inline fun SearchContext.elementByName(name: String, init: WebElement.() -> Unit) { 52 | findElement(By.name(name)).init() 53 | } 54 | 55 | /* 56 | * Find element by tag 57 | * */ 58 | inline fun SearchContext.elementByTag(tag: String, init: WebElement.() -> T): T { 59 | return findElement(By.tagName(tag)).init() 60 | } 61 | 62 | /* 63 | * Find element by selector 64 | * */ 65 | inline fun SearchContext.elementBySelector(selector: String, init: WebElement.() -> Unit) { 66 | findElement(By.cssSelector(selector)).init() 67 | } 68 | 69 | /* 70 | * Find element by xpath 71 | * */ 72 | inline fun SearchContext.elementByXpath(xpath: String, init: WebElement.() -> Unit) { 73 | findElement(By.xpath(xpath)).init() 74 | } 75 | 76 | 77 | 78 | 79 | 80 | /* 81 | * element existing functions. 82 | * */ 83 | 84 | /* 85 | * Element exists by. 86 | * */ 87 | fun SearchContext.elementExists(by: By) = findElements(by).isNotEmpty() 88 | 89 | /* 90 | * Element exists by id 91 | * */ 92 | fun SearchContext.elementByIdExists(id: String) = findElements(By.id(id)).isNotEmpty() 93 | 94 | /* 95 | * Element exists by class name 96 | * */ 97 | fun SearchContext.elementByClassExists(className: String) = findElements(By.className(className)).isNotEmpty() 98 | 99 | /* 100 | * Element exists by name 101 | * */ 102 | fun SearchContext.elementByNameExists(name: String) = findElements(By.name(name)).isNotEmpty() 103 | 104 | /* 105 | * Element exists by css selector 106 | * */ 107 | fun SearchContext.elementBySelectorExists(selector: String) = findElements(By.cssSelector(selector)).isNotEmpty() 108 | 109 | /* 110 | * Element exists by xpath 111 | * */ 112 | fun SearchContext.elementByXpathExists(xpath: String) = findElements(By.xpath(xpath)).isNotEmpty() 113 | -------------------------------------------------------------------------------- /src/main/java/kz/qwertukg/webDriver.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.openqa.selenium.WebDriver 4 | import org.openqa.selenium.chrome.ChromeDriver 5 | import org.openqa.selenium.firefox.FirefoxDriver 6 | 7 | /** 8 | * Selenium Kotlin Builder 9 | * Created by Daniil Rakhmatulin 10 | * http://daniil.rakhmatulin.kz 11 | */ 12 | 13 | /* 14 | * Web Driver 15 | * */ 16 | inline fun driver(driver: T, init: T.() -> Unit) { 17 | try { 18 | driver.init() 19 | } finally { 20 | driver.close() 21 | } 22 | } 23 | 24 | /* 25 | * Web Driver Chrome 26 | * */ 27 | fun chromeDriver(init: WebDriver.() -> Unit) = driver(ChromeDriver(), init) 28 | 29 | /* 30 | * Web Driver Chrome with path to driver 31 | * */ 32 | fun chromeDriver( 33 | settings: ChromeDriverSettings, 34 | init: ChromeDriver.() -> Unit 35 | ) { 36 | return driver(ChromeDriver(settings.driverOptions), init) 37 | } 38 | 39 | /* 40 | * Web Driver FireFox 41 | * */ 42 | inline fun firefoxDriver(init: WebDriver.() -> Unit) = driver(FirefoxDriver(), init) 43 | 44 | /* 45 | * Web Driver FireFox with path to driver 46 | * */ 47 | inline fun firefoxDriver(pathToDriver: String, init: WebDriver.() -> Unit) { 48 | System.setProperty("webdriver.firefox.driver", pathToDriver) 49 | driver(FirefoxDriver(), init) 50 | } -------------------------------------------------------------------------------- /src/main/java/kz/qwertukg/webDriverOptions.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.openqa.selenium.chrome.ChromeOptions 4 | 5 | open class DriverOptions( 6 | pathToDriver: String 7 | ) { 8 | init { 9 | System.setProperty("webdriver.chrome.driver", pathToDriver) 10 | } 11 | } 12 | 13 | class ChromeDriverSettings( 14 | pathToDriver: String, 15 | val driverOptions: ChromeOptions = ChromeOptions() 16 | ) : DriverOptions(pathToDriver) -------------------------------------------------------------------------------- /src/main/java/kz/qwertukg/webDriverWaitExtensions.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.openqa.selenium.By 4 | import org.openqa.selenium.WebElement 5 | import org.openqa.selenium.support.ui.ExpectedConditions 6 | import org.openqa.selenium.support.ui.WebDriverWait 7 | 8 | /** 9 | * Selenium Kotlin Builder 10 | * Created by Daniil Rakhmatulin 11 | * http://daniil.rakhmatulin.kz 12 | */ 13 | 14 | /* 15 | * Visibility of element 16 | * */ 17 | 18 | /* 19 | * Web driver wait element is visible 20 | * */ 21 | inline fun WebDriverWait.elementVisibility(by: By, init: WebElement.() -> Unit) { 22 | until(ExpectedConditions.visibilityOfElementLocated(by)).init() 23 | } 24 | 25 | /* 26 | * Web driver wait element by id is visible 27 | * */ 28 | inline fun WebDriverWait.elementVisibilityById(id: String, init: WebElement.() -> Unit) { 29 | until(ExpectedConditions.visibilityOfElementLocated(By.id(id))).init() 30 | } 31 | 32 | /* 33 | * Web driver wait element by class is visible 34 | * */ 35 | inline fun WebDriverWait.elementVisibilityByClass(className: String, init: WebElement.() -> T) : T{ 36 | return until(ExpectedConditions.visibilityOfElementLocated(By.className(className))).init() 37 | } 38 | 39 | /* 40 | * Web driver wait element by name is visible 41 | * */ 42 | inline fun WebDriverWait.elementVisibilityByName(name: String, init: WebElement.() -> Unit) { 43 | until(ExpectedConditions.visibilityOfElementLocated(By.name(name))).init() 44 | } 45 | 46 | /* 47 | * Web driver wait element by link is visible 48 | * */ 49 | inline fun WebDriverWait.elementVisibilityByLink(link: String, init: WebElement.() -> Unit) { 50 | until(ExpectedConditions.visibilityOfElementLocated(By.linkText(link))).init() 51 | } 52 | 53 | /* 54 | * Web driver wait element by tag is visible 55 | * */ 56 | inline fun WebDriverWait.elementVisibilityByTag(tag: String, init: WebElement.() -> T) : T{ 57 | return until(ExpectedConditions.visibilityOfElementLocated(By.tagName(tag))).init() 58 | } 59 | 60 | /* 61 | * Web driver wait element by css selector is visible 62 | * */ 63 | inline fun WebDriverWait.elementVisibilityBySelector(selector: String, init: WebElement.() -> Unit) { 64 | until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(selector))).init() 65 | } 66 | 67 | /* 68 | * Web driver wait element by css selector is visible 69 | * */ 70 | inline fun WebDriverWait.elementVisibilityByXpath(xpath: String, init: WebElement.() -> Unit) { 71 | until(ExpectedConditions.visibilityOfElementLocated(By.xpath(xpath))).init() 72 | } 73 | 74 | /* 75 | * Invisibility of element 76 | * */ 77 | 78 | /* 79 | * Web driver wait element is invisible 80 | * */ 81 | fun WebDriverWait.elementInvisibility(by: By) = until(ExpectedConditions.invisibilityOfElementLocated(by)) 82 | 83 | /* 84 | * Web driver wait element by id is invisible 85 | * */ 86 | fun WebDriverWait.elementInvisibilityById(id: String) = until(ExpectedConditions.invisibilityOfElementLocated(By.id(id))) 87 | 88 | /* 89 | * Web driver wait element by class is invisible 90 | * */ 91 | fun WebDriverWait.elementInvisibilityByClass(className: String) = until(ExpectedConditions.invisibilityOfElementLocated(By.className(className))) 92 | 93 | /* 94 | * Web driver wait element by name is invisible 95 | * */ 96 | fun WebDriverWait.elementInvisibilityByName(name: String) = until(ExpectedConditions.invisibilityOfElementLocated(By.name(name))) 97 | 98 | /* 99 | * Web driver wait element by class is invisible 100 | * */ 101 | fun WebDriverWait.elementInvisibilityBySelector(selector: String) = until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(selector))) 102 | 103 | /* 104 | * Web driver wait element by class is invisible 105 | * */ 106 | fun WebDriverWait.elementInvisibilityByXpath(xpath: String) = until(ExpectedConditions.invisibilityOfElementLocated(By.xpath(xpath))) 107 | -------------------------------------------------------------------------------- /src/test/java/kz/qwertukg/WebDriverKtTest.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | class WebDriverKtTest { 7 | @Test 8 | fun `test chromeDriver, elementById, wait, elementVisibilityById, elementVisibilityBySelector functions on google`() { 9 | var result = "" 10 | 11 | chromeDriver(settings) { 12 | get("http://google.com") 13 | 14 | elementById("lst-ib") { 15 | sendKeys("kotlin") 16 | 17 | wait(10) { 18 | elementVisibilityByName("btnK") { 19 | click() 20 | } 21 | 22 | elementVisibilityBySelector("a[href = 'https://kotlinlang.org/']") { 23 | result = text 24 | } 25 | } 26 | } 27 | } 28 | 29 | assertEquals("Kotlin Programming Language", result) 30 | } 31 | } -------------------------------------------------------------------------------- /src/test/java/kz/qwertukg/base.kt: -------------------------------------------------------------------------------- 1 | package kz.qwertukg 2 | 3 | import org.openqa.selenium.chrome.ChromeOptions 4 | 5 | val settings = ChromeDriverSettings( 6 | pathToDriver = "c:/chromedriver.exe", 7 | driverOptions = ChromeOptions().apply { 8 | setHeadless(true) 9 | } 10 | ) 11 | 12 | //val settings2 = ChromeDriverSettings( 13 | // pathToDriver = "/Users/alex/Downloads/chromedriver", 14 | // driverOptions = ChromeOptions().apply { setHeadless(false) } 15 | //) --------------------------------------------------------------------------------