Scalatest: Extended Page Object Pattern Support (Geb like)

Created on 17 May 2016  路  4Comments  路  Source: scalatest/scalatest

Hello @bvenners,

we are using the page object pattern similar to the implementation provided by geb in our scalatest webpage tests and we would ask if you are interested in an contribution of this code to scalatest.

Here is an example:

package org.scalatest.examples.selenium

import org.scalatest.FunSpec
import org.scalatest.concurrent.Eventually
import org.scalatest.selenium.Chrome
import org.scalatest.selenium.DomainPage
import org.scalatest.selenium.Firefox
import org.scalatest.selenium.PageObject
import org.scalatest.selenium.WebBrowser
import org.scalatest.selenium.WebBrowserLauncher

/**
 * It is recommended to create a DomainPage if you are testing more then one page in the same domain.
 */
trait GoogleDomainPage extends DomainPage with PageObject with WebBrowser {
  /**
   * For this example the domain is hardcoded. But you can also do something like:
   * val domain = Option(System.getenv("DEV_SERVER_PREFIX")).getOrElse("https://www.google.com")
   */
  val domain = "https://www.google.com"
}

/**
 * This is the "Page Object Pattern" object for the google search page.
 *
 * A Page Object should not contain any state.
 */
case object GoogleSearchPage extends GoogleDomainPage {
  val path = "/"

  /**
   * a content object is required, it should contain functions returning elements from the page
   */
  object content {
    // in this example, we only need to access element with name "q"
    def q = textField("q")
  }

  override def at(): Unit = {
    assert(pageTitle == "Google")
  }
}

/**
 * WebBrowserLauncher will use @WrapWith to create Test instances as needed.
 *
 * bolierplate code like this is not needed:
 * <pre class="stHighlight">
 * class GoogleSearchSpecWithChrome extends GoogleSearchSpec with Chrome
 * class GoogleSearchSpecWithSafari extends GoogleSearchSpec with Safari
 * class GoogleSearchSpecWithInternetExplorer extends GoogleSearchSpec with InternetExplorer
 * class GoogleSearchSpecWithFirefox extends GoogleSearchSpec with Firefox
 * </pre>
 */
abstract class BaseSpec extends FunSpec with WebBrowserLauncher with Eventually {
  def Browsers = Seq(Firefox, Chrome)
}

class GoogleSearchPageObjectSpec extends BaseSpec {
  describe("google.com") {
    it("should change its title based on the term searched") {
      // Cancel test when cannot access google.com
      try to(GoogleSearchPage) catch {
        case e: Throwable => cancel(e)
      }
      val q = GoogleSearchPage.content.q
      click on q
      q.value = "Cheese!"
      submit()
      // Google's search is rendered dynamically with JavaScript.
      eventually(assert(pageTitle === "Cheese! - Google Search"))
    }
  }
}

Unfortunately some refactorings of org.scalatest.selenium.WebBrowser are needed, but this is possible without breaking existing API.

Most helpful comment

@mb73 please have a look at https://www.pageobject.org/ we have relased this as an extension for scalatest.

All 4 comments

@mb73 please have a look at https://www.pageobject.org/ we have relased this as an extension for scalatest.

@drieks This looks really cool! Does it also support that WebBrowserLauncher feature you wrote in the example above ( def Browsers = Seq(Firefox, Chrome) )? If so, could you please point me to some sample code or documentation?

hi @mb73,

yes this is supported. But I think it is not the best way. We are overriding the browsers to test with with environment vars.
You should prefer providing a custom DriverFactoryList that match your needs (maybe test only FF and chrome) by setting RUN_WITH_DRIVERS. If you want to run all browsers in VNC servers set RUN_WITH_DRIVERS=org.pageobject.core.driver.vnc.DefaultVncDriverFactoryList.

I think it is easier to change a environment var than changing all your test cases if you want to modify something.

We have to change the way used in the example above because we have to create an instance before you can call Browsers(). Because of this we changed this into an annotation. You can write @RunWithDrivers(factory class) in this case. But it is not possible to override this using an environment var currently so you should use this only if you want a separate handling for the annotated class. Maybe "this test case should only be tested using html unit" or something like this.

Please have a look here https://github.com/scalatest/scalatest/pull/952#issuecomment-246974339 for another comment about specifing browsers to test.

Please tell me if you have any questions!

I'm going to close this because we already have released this, see https://github.com/agido/pageobject

Was this page helpful?
0 / 5 - 0 ratings