Platinum Partner
java,scala,languages

Scala, WebDriver and the Page Object Pattern

We’re using WebDriver on my project to automate our functional tests and as a result are using the Page Object pattern to encapsulate each page of the application in our tests.

We’ve been trying to work out how to effectively reuse code since some of the pages have parts of them which work exactly the same as another page.

For example we had a test similar to this…

class FooPageTests extends Spec with ShouldMatchers with FooPageSteps {
  it("is my dummy test") {
    ...
    then(iShouldNotSeeAnyCommonLinks())
  }
}

…where FooPageSteps extends CommonSteps which contains the common assertions:

trait CommonSteps {
  val page : FooPage
  val driver: HtmlUnitDriver
 
  def iShouldNotSeeAnyCommonLinks() {
    page.allCommonLinks.isEmpty should equal(true)
  }
}

FooPage looks like this:

class FooPage(override val driver:WebDriver) extends Page(driver) with CommonSection {
 
}
 
abstract class Page(val driver: WebDriver) {
  def title(): String = driver.getTitle;
}
 
trait CommonSection {
  val driver:WebDriver
  def allCommonLinks:Seq[String] = driver.findElements(By.cssSelector(".common-links li")).map(_.getText)
}

We wanted to reuse CommonSteps for another page like so:

But that means that we need to change the type of page in CommonSteps to make it a bit more generic so it will work for BarPageSteps too.

Making it of type Page is not enough since we still need to be able to call the allCommonLinks which is mixed into FooPage by CommonSection.

We therefore end up with the following:

trait CommonSteps {
  val page : Page with CommonSection
  val driver: HtmlUnitDriver
 
  def iShouldNotSeeAnyCommonLinks() {
    page.allCommonLinks.isEmpty should equal(true)
  }
}

We’re able to mix in CommonSection just for this instance of Page which works pretty well for allowing us to achieve code reuse in this case!

 

From http://www.markhneedham.com/blog/2011/08/09/scala-webdriver-and-the-page-object-pattern/

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}