Тестовый фреймворк GEB
для тестирования WEB
приложений и Mobile
YaroslavSviatkin
email:yariks@i.ua
http://sviatkin.com
HtmlElements. Page Object
JDI UI Test Automation Framework
@JSite(domain="https://epam.github.io/JDI/")
publicclassJDIExampleSiteextendsWebSite{
publicstaticHomePagehomePage;
publicstaticLoginFormloginForm;
@FindBy(css=".profile-photo")
publicstaticLabelprofilePhoto;
publicstaticvoidlogin(){
profilePhoto.click();
loginForm.loginAs(newUser());
}
}
Automated Acceptance
Testing with Style
http://www.thucydides.info/#/
Project structure
Page Object classes
Steps implementation class
Stories classes
Requirements for the
application under test
Organizing requirements
First, you create a model of the features and user stories you intend to implement:
Stories
Features
Confidential
9
Page Objects
Next you will need to implement your page objects. These are almost just run-of-the-mill
WebDriver page objects, but with a few enhancements:
Steps implementation
Now implement the actual test steps using either WebDriver page objects or other test steps. Here you start
thinking about implementation:
A step library
High level steps...
...implemented with Page
Objects
...or with other steps
Selenide
http://selenide.org
Geb
http://www.gebish.org
What is Geb?
Geb is a browser automation solution
What can you test with Geb?
• Any web and mobile applications
• App doesn't need to be written in Groovy
go"http://www.google.com"
$("input",name:"q").value("geb")
$("button",name:"btnG").click()
waitFor{$("#search").displayed}
$("h3.r").first().click()
waitFor{title=="Geb-VeryGroovyBrowserAutomation"}
Selector syntax
$("#by-id")
$(".by-class")
$("div",name:"by-attribute")
$("div",text:"Bytext")
$(By.id("some-id"))
$(By.className("some-class"))
$(By.xpath('//p[@class="xpath"]'))
…
title{$(By.xpath(".//h4[@class='titleng-binding']")).text()
assert$("p",1..2)*.text()==["b","c"]
assert$("p",text:~/p./).size()==2
assert$("p",text:startsWith("p")).size()==2
assert$("p.d").previous()==$("p.c")
assert$("p.e").prevAll()==$("p.c").add("p.d")
assert$("p.d").next()==$("p.e")
assert$("p.c").nextAll()==$("p.d").add("p.e")
assert$("p.d").parent()==$("div.b")
assert$("p.c").siblings()==$("p.d").add("p.e")
assert$("div.a").children()==$("div.b").add("div.f")
project { String index -> $(By.xpath("//div[@class=card-item']//h4[@title='${index}']")).click() }
projectPage.project(nameProject)
dynamicallyAdded(wait:true){$("p.dynamic")}
dynamicallyAdded(wait:5,required:false){$("p.dynamic")}
cachedValue(cache:true){value}
helpLink(to:HelpPage){$("a",text:"Help")}
Page Object Model
Page
Module
Control modules
• FormElement
• Checkbox
• Select
• MultipleSelect
• TextInput
• Textarea
• FileInput
• RadioButtons
classExamplePageextendsPage{
staticcontent={
theModule{moduleExampleModule}
}
}
classExampleModuleextendsModule{
staticcontent={
button{$("input",type:"submit")}
}
}
class NotificationModule extends Module {
static content = {
notifocation {
$(By.xpath(".//li[contains(@ng-repeat,'notifications')]")).moduleList(Notification)
}
gotItButton { $(By.xpath(".//button[@ng-click='appCtrl.gotItNotifications()']")) }
}
}
class Notification extends Module {
static content = {
name { $(By.xpath("//h5")).text() }
dete { $(By.xpath("//div[contains(@class,'date')]")).text() }
notification { $(By.xpath("//p")) text() }
}
}
searchResult(required: false, wait: 5) { $(By.xpath("//li/a/strong"))*.text() }
notification { $(By.xpath("//ul[contains(@ng-if,'notifications')]")).module(NotificationModule) }
menuLinksModule(wait: 5) { $(By.xpath("//button[contains(@class,'services')]")).module(MenuLinksModule) }
Verify test at current page
classIdeaCreatePageextendsgeb.Page{
staticat={$("div#create-idea").displayed}
}
staticcontent={
createButton(to:IdeaShowPage){$("input#create")}
}
IdeaCreatePageideaCreatePage=to(IdeaCreatePage)
isAt(IdeaCreatePage)
class LoginPage extends Page {
static url = "access/signin"
static at = { browser.currentUrl.startsWith("https://wwwwwwwwww.com") }
static content = {
userName(wait: 5) { $(By.xpath("//input[@type='text']")) }
userPassword { $(By.xpath("//input[@type='password']")) }
loginError(required: false, wait: 3) { $(By.xpath("//div[@class='error']")).text()
}
loginSubmit { $("button", text: startsWith("Login")).click() }
heading (to:BasePage){ $(By.xpath("//div[@class='info']/h1")).text() }
}
def login(String login, String password) {
userName.firstElement().clear()
userPassword.firstElement().clear()
userName << login
userPassword << password
loginSubmit
}
}
LoginPage loginPage = page(LoginPage)
waitFor examples
waitFor{
$("div.alert").displayed
}
waitFor{
$("div.message").text()=="Updatesuccessful"
}
Mouse interactions
voidmoveRatingSlider(Integerrating){
//Slideris400pixelswideandstartsat1,
//soeachnotchabove1is100pixelsapart
IntegernumPixelsX=(rating-1)*100
interact{
clickAndHold(ratingSliderHandle)
moveByOffset(numPixelsX,0)
release()
}
}
WebElementunderlyingElement=
$('#myElement').getElement(0)
Actionaction=newActions(browser.driver)
.clickAndHold(underlyingElement)
.moveByOffset(15,15)
.release()
.build()
action.perform()
}
Use keyboard
$(".ui-slider-handle")<<Keys.ARROW_RIGHT
Already opened windows
withWindow({title=="Geb-VeryGroovyBrowserAutomation"}){
assert$("#slogan").text().startsWith("verygroovybrowserautomation…")
}
}
withNewWindow({$('a').click()}){
asserttitle=='Geb-VeryGroovyBrowserAutomation'
}
@Test
void feedBackReferenceTest() {
openMenu
browser.withNewWindow({ basePage.menuLinksModule.feedback }, {
assert browser.currentUrl.startsWith("https://helpdesk.com/")
})
}
@Test
void officeMapReferenceTest() {
openMenu
browser.withWindow({ basePage.menuLinksModule.officeMap }, {
if (browser.currentUrl == signinUrl) {
loginPage.login(userName, userPassword)
}
assert browser.currentUrl == "https://portal.com"
})
browser.to(ProjectPage)
}
Show hidden element
void scrollUp() {
js.exec("""window.scrollTo(0,0)""")
}
$("div#a").jquery.mouseover() Browser.drive{
assertjs.myGlobalVar==1
}
Available browsers
waiting {
timeout = 2
}
baseUrl = "https://wwwwwwwww.com/"
autoClearCookies = false
atCheckWaiting = true
baseNavigatorWaiting = true
name = ''
password = ''
mail =''
environments {
chrome {
driver = {
def driverInstance = new ChromeDriver()
driverInstance.manage().window().maximize()
driverInstance
}
}
firefox {
driver = {
def driverInstance = new FirefoxDriver()
driverInstance.manage().window().maximize()
driverInstance
}
}
ie {
driver = {
def driverInstance = new InternetExplorerDriver()
driverInstance.manage().window().maximize()
driverInstance
} }}
//Receiving name and password from GebConfig.groovy
final String userName = browser.config.rawConfig.name
final String userPassword = browser.config.rawConfig.password
task chromeTest(type: Test) {
systemProperty "geb.env", "chrome"
systemProperty "webdriver.chrome.driver", "driverschromedriver.exe"
useTestNG {
suites "srctestresourcestestng-suite.xml"
useDefaultListeners = true
}
}
// Drivers
testCompile "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion"
testCompile "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
testCompile "org.seleniumhq.selenium:selenium-ie-driver:$seleniumVersion"
static String randomString(int count) {
(1..count).inject("") { a, b -> a += ('a'..'z')[new Random().nextFloat() * 26 as int] }.capitalize()
}
def getWanted() {
def result = []
HTTPRequest.request(GET, JSON) { req ->
uri.path = '/wanted'
headers.'Auth' = "${TOKEN}"
response.success = { resp, json ->
println new JsonBuilder( json).toPrettyString()
(json as ArrayList).each {
String name = it.name
def projects = []
(it.projects as ArrayList).each {
projects << [it.projectid.'$oid', it.title]
}
result << [name, projects].flatten()
}
}
}
result
}
List getAllIdProject() {
def result = []
GITLAB.get(path: "/gitlab/api/v3/projects/all") { resp, json ->
println new JsonBuilder(json).toPrettyString()
def request = (json as Map)
result = request*.id
}
result
}
assert loginPage.heading == "Welcome"
Geb integrates with
Geb-mobile
https://github.com/JasonKissinger-MDT/geb-mobile
email : yariks@i.ua
http://sviatkin.com

QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB приложений и Mobile