Scaladays 2014 introduction to scalatest selenium dsl

31
SCALATEST SELENIUM DSL Scala days 2014 - Berlin

description

Selenium is a technology used to test web sites by firing up a browser and then interacting with a web site. It can be used from a number of languages - Java, Python, Ruby. Scalatest 2.0 introduced a DSL which simplifies the writing of tests in Selenium. More importantly, it simplifies the process of reading and understanding the tests. It becomes easier to walk through a test with a semi-technical person. We present a introduction where we test an application with heavy use of Javascript using the DSL, along with advantages and disadvantages of the approach that we took. We also look to the future to see what could be done better.

Transcript of Scaladays 2014 introduction to scalatest selenium dsl

Page 1: Scaladays 2014   introduction to scalatest selenium dsl

SCALATEST SELENIUM DSLScala days 2014 - Berlin

Page 2: Scaladays 2014   introduction to scalatest selenium dsl

MATTHEW FARWELL• Over 20 years development experience

• Project Lead on Scalastyle, style checker for Scala http://www.scalastyle.org

• Contributor to various open source projects, notably Scalatest, JUnit, Scala-IDE

• Co-author with Josh Suereth of "sbt in Action" http://manning.com/suereth2/

• https://github.com/matthewfarwell/scaladays-2014-selenium

Page 3: Scaladays 2014   introduction to scalatest selenium dsl

GOALS• Present the Selenium DSL

• Show how it simplifies the writing of selenium tests.

• Show how it can be used to test a javascript heavy application

• Show how it can be integrated with other tests to make more useful integration tests

• The future, well what I would like anyway

Page 4: Scaladays 2014   introduction to scalatest selenium dsl

SELENIUM• Selenium automates browsers.

• Firefox, Chrome, Internet Explorer, Safari, Opera, HtmlUnit

• Selenium has interfaces for Java, Python, Ruby, etc.

• We'll be looking at from the point of view of testing

• But we could use it for other stuff – automation of administration for example.

Page 5: Scaladays 2014   introduction to scalatest selenium dsl

EXAMPLE (JAVA)final WebDriver driver = new FirefoxDriver();Wait<WebDriver> wait = new WebDriverWait(driver, 30);driver.get("http://www.google.ch/");

driver.findElement(By.name("q")).sendKeys("Matthew Farwell");driver.findElement(By.name("btnG")).click();

wait.until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver webDriver) { return webDriver.findElement(By.id("resultStats")) != null;}});

boolean b = driver.findElement(By.tagName("body"))

.getText().contains("farwell.co.uk");System.out.println((found ? "You are famous" : "Not famous enough, sorry"));

Page 6: Scaladays 2014   introduction to scalatest selenium dsl

EXAMPLE (PYTHON)driver = webdriver.Firefox()

driver.get("http://www.google.ch")

elem = driver.find_element_by_name("q")

elem.send_keys("Farwell")

elem.send_keys(Keys.RETURN)

assert "farwell.co.uk" in driver.find_by_element_id("body")

Page 7: Scaladays 2014   introduction to scalatest selenium dsl

EXAMPLE (SCALA)go to "http://www.google.ch/"

textField("q").value = "Farwell"

click on "btnG"

eventually {   val t = find(tagName("body")).get.text }

t should include("farwell.co.uk") println("Yay, you are famous")

- AmIFamousScala.scala

Page 8: Scaladays 2014   introduction to scalatest selenium dsl

OUR APPLICATION• https://github.com/matthewfarwell/scaladays-2014-selenium

$ sbt> re-start- Run tests from Eclipse

$ sbt> re-start> test

Page 9: Scaladays 2014   introduction to scalatest selenium dsl

A REAL TESTval baseUrl = "http://localhost:9100/"

"slash" should "redirect to admin index.html" in { go to baseUrl

currentUrl should be (baseUrl + "admin/index.html#/users")

find("pageTitle").get.text should be("Users")

textField("userSearch").value should be('empty)

find("userUsername_2").get.text should be("matthew")}- UserSpec1.scala

Page 10: Scaladays 2014   introduction to scalatest selenium dsl

ADDING EVENTUALLYeventually { find("userUsername_2").get.text should be("matthew")}

- UserSpec2.scala

Page 11: Scaladays 2014   introduction to scalatest selenium dsl

ADDING EVENTUALLY (2)eventually { find("pageTitle").get.text should be("Users")

textField("userSearch").value should be('empty)

find("userUsername_2").get.text should be("matthew")}

- UserSpec2.scala

Page 12: Scaladays 2014   introduction to scalatest selenium dsl

GETTING / SETTING VALUESgo to (baseUrl + "admin/index.html#/users")

eventually { click on "userEdit_2"}

eventually { val tf = textField("userFullname") tf.value should be("Matthew Farwell") tf.isEnabled should be (true)}

textField("userFullname").value = "Matthew Farwell is great"- UserSpec3.scala

Page 13: Scaladays 2014   introduction to scalatest selenium dsl

GETTING / SETTING VALUESpwdField("password").value = "hello world"

pwdField("confirmPassword").value = "hello world"

find("error").get.text should be("Passwords do not match")

- UserSpec3.scala

Page 14: Scaladays 2014   introduction to scalatest selenium dsl

DEBUGGINGcapture to "foo.png"

println(currentUrl)

println(pageSource)

withScreenshot { // some stuff // if ModifiableMessage is thrown, screenshot is taken}

Page 15: Scaladays 2014   introduction to scalatest selenium dsl

DEBUGGING - REPORTERSevent match { case e: TestFailed => { val name = e.testName web.captureTo(s"${name}.png") println(web.pageSource) }}

- Common.scala

Page 16: Scaladays 2014   introduction to scalatest selenium dsl

OTHER INPUT TYPES• textField• pwdField• checkBox• radioButton• singleSel, multiSel

• HTML5 - emailField, colorField, dateField, dateTimeField, dateTimeLocalField, monthField, numberField, rangeField, searchField, telField, timeField, urlField, weekField

Page 17: Scaladays 2014   introduction to scalatest selenium dsl

XPATH LOOKUPS"list" should "default to 10 items" in {

go to (baseUrl + "admin/index.html#/users")

eventually { val xp = "//tr//td[starts-with(@id, 'userUsername_')]"

val tds = findAll(xpath(xp)).map(_.text).toList

tds.size should be(10) }}

- UserSpec5.scala

Page 18: Scaladays 2014   introduction to scalatest selenium dsl

PAGE OBJECT PATTERNclass HomePage extends Page { val url = "localhost:9100/index.html"}

val homePage = new HomePage

go to homePage

Page 19: Scaladays 2014   introduction to scalatest selenium dsl

COOKIESadd cookie ("cookie_name", "cookie_value")

cookie("cookie_name").value should be ("cookie_value")

delete cookie "cookie_name"

Page 20: Scaladays 2014   introduction to scalatest selenium dsl

ALERTS, FRAMES, WINDOWSswitch to alert

switch to frame(0) // switch by indexswitch to frame("name") // switch by name

switch to window(windowHandle)

switch to activeElementswitch to defaultContent

Page 21: Scaladays 2014   introduction to scalatest selenium dsl

NAVIGATIONgoBack()

goForward()

reloadPage()

Page 22: Scaladays 2014   introduction to scalatest selenium dsl

JAVASCRIPTgo to (host + "index.html")

val result1 = executeScript("return document.title;")

result1 should be ("Test Title")

val result2 = executeScript("return 'Hello ' + arguments[0]", "ScalaTest")

result2 should be ("Hello ScalaTest")

Page 23: Scaladays 2014   introduction to scalatest selenium dsl

INTEGRATION TESTING// create a new user

click on "newUser"

textField("username").value = "user"

// etc.

click on "submit"

// how do we test that the user has been created?

- UserSpec4.scala

Page 24: Scaladays 2014   introduction to scalatest selenium dsl

INTEGRATION• A lot of the time, we would like to assert something which isn't available

through the HTML front end

Page 25: Scaladays 2014   introduction to scalatest selenium dsl

INTEGRATION TESTINGeventually { val after = Services.listUsers().unmarshall

after.size should be(before.size + 1)

val u = after.find(_.username == "user").get

u.fullName should be(Some("Mr. User"))

u.id should not be (None)}

- UserSpec4.scala

Page 26: Scaladays 2014   introduction to scalatest selenium dsl

MULTI-BROWSER TESTINGabstract class UserSpecBase with Driver { // tests here}

class UserSpecChrome extends UserSpecBase with Chrome

class UserSpecFirefox extends UserSpecBase with Firefox

class UserSpecSafari extends UserSpecBase with Safari

- UserSpec6.scala

Page 27: Scaladays 2014   introduction to scalatest selenium dsl

OUR CONTEXT• Lots of legacy code, partially tested with selenium in Java / Python.

• Lots of new code, which has been tested with Scalatest selenium DSL

• A simple click on a web page can have effects way beyond CRUD

• Selenium used for testing pure HTML, GWT, Angular JS applications

Page 28: Scaladays 2014   introduction to scalatest selenium dsl

OUR EXPERIENCE• DSL is good for walking through a test – clearer and more readable than the

Java equivalent• We have tests written by "developers" and "testers"• Consistent tests – we use Scalatest for unit tests, UI tests and integration tests.• Selenium DSL is integrated into Scalatest• Always have ids on elements• Our integration tests work with heterogeneous actions in the same test:

• we can perform an action in the Browser,• then check call rest service,• then check the database,• call a command via ssh on a remote machine.

Page 29: Scaladays 2014   introduction to scalatest selenium dsl

WHAT WE'D LIKE TO IMPROVE IMPLICIT EVENTUALLY

eventually { click on "userEdit_2"}eventually { textField("foo").get.value should be ("bar")}eventually { click on "btn"}eventually { textField("baz").get.value should be ("flobble")}

Page 30: Scaladays 2014   introduction to scalatest selenium dsl

WHAT WE'D LIKE TO IMPROVE SLOWING DOWN

eventually { click on "userEdit_2"}eventually { textField("foo").get.value should be ("bar")}eventually { click on "userEdit_2"}eventually { textField("foo").get.value should be ("bar")}

Page 31: Scaladays 2014   introduction to scalatest selenium dsl

ME AGAIN• Matthew Farwell

• Twitter: @matthewfarwell

• Blog: http://randomallsorts.blogspot.ch/

• Scalastyle: http://www.scalastyle.org

• sbt in Action: http://manning.com/suereth2