Set Accept-Language on PhantomJSDriver in a Play Framework Specification
phantomjs, playframework, playframework-2.2, scala, selenium
Solution
Based on a forum message by Yasuki Okumura, this can be done by creating a `TestBrowser` object from a preconfigured driver.
For example:
In file `WithPhantomJS.scala`:
package com.myproject.website.tests
import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.phantomjs.PhantomJSDriver
import org.openqa.selenium.phantomjs.PhantomJSDriverService
import org.specs2.execute.AsResult
import org.specs2.execute.Result
import org.specs2.mutable.Around
import org.specs2.specification.Scope
import play.api.i18n.Lang
import play.api.test.Helpers._
import play.api.test.FakeApplication
import play.api.test.TestBrowser
import play.api.test.TestServer
import scala.collection.JavaConverters._
abstract class WithPhantomJS(val additionalOptions: Map[String, String] = Map()) extends Around with Scope {
implicit def app = FakeApplication()
implicit def port = play.api.test.Helpers.testServerPort
lazy val browser: TestBrowser = {
val defaultCapabilities = DesiredCapabilities.phantomjs
val additionalCapabilities = new DesiredCapabilities(additionalOptions.asJava)
val capabilities = new DesiredCapabilities(defaultCapabilities, additionalCapabilities)
val driver = new PhantomJSDriver(capabilities)
TestBrowser(driver, Some("http://localhost:" + port))
}
override def around[T: AsResult](body: => T): Result = {
try {
running(TestServer(port, app))(AsResult.effectively(body))
} finally {
browser.quit()
}
}
}
In file `IntegrationSpec.scala`:
package com.myproject.website.tests
import com.myproject.common.helpers._
import org.junit.runner._
import org.specs2.runner._
import play.api.i18n._
import play.api.test._
import play.api.test.Helpers._
import org.specs2.mutable.Specification
import org.openqa.selenium.phantomjs.PhantomJSDriverService
/**
* An integration test will fire up a whole play application in a real (or headless) browser.
*/
@RunWith(classOf[JUnitRunner])
class IntegrationSpec extends Specification {
val enUSLangCode = "en-US"
val ptBRLangCode = "pt-BR"
val enUSOptions = getPhantomJSLanguageOption(enUSLangCode)
val ptBROptions = getPhantomJSLanguageOption(ptBRLangCode)
"Application" should {
"work from within a browser with en-US language" in new WithPhantomJS(enUSOptions) {
browser.goTo("http://localhost:" + port)
implicit val lang = Lang(enUSLangCode)
val expected = Messages("home.index.featured_lead")
browser.pageSource must contain(expected)
}
"work from within a browser with pt-BR language" in new WithPhantomJS(ptBROptions) {
browser.goTo("http://localhost:" + port)
implicit val lang = Lang(ptBRLangCode)
val expected = Messages("home.index.featured_lead")
browser.pageSource must contain(expected)
}
}
private def getPhantomJSLanguageOption(langCode: String) =
Map(PhantomJSDriverService.PHANTOMJS_PAGE_CUSTOMHEADERS_PREFIX + "Accept-Language" -> langCode)
}
Also, this dependency is required in `build.sbt`:
libraryDependencies += "com.github.detro.ghostdriver" % "phantomjsdriver" % "1.0.4" % "test"
In Play Framework 2.3, the `WithBrowser` class will accept a `WebDriver` instance directly.
Problem
How can the PhantomJSDriver be configured with a specific Accept-Language language header in a Play Framework 2.2 specification? Given this code: ``` import org.specs2.mutable._ import org.specs2.runner._ import org.junit.runner._ import play.api.i18n._ import play.api.test._ import play.api.test.Helpers._ import org.openqa.selenium.phantomjs.PhantomJSDriver @RunWith(classOf[JUnitRunner]) class IntegrationSpec extends Specification { "Application" should { "work from within a browser" in new WithBrowser(webDriver = classOf[PhantomJSDriver]) { browser.goTo("http://localhost:" + port) implicit val lang = Lang("pt-BR") val expected = Messages("home.index.featured_lead") browser.pageSource must contain(expected) } } } ``` How can I make sure that the request generated by `goTO` will be sent with a specific `Accept-Language` header, e.g. `pt-BR`? Update: The objective of the question is to be able to run tests in a simulated browser (such as PhantomJS) with the browser configured for a specific language. The code sample above just asks the browser to detect if there is some localized text in the page, but the kind of tests that can be run in a simulated browser vary a lot. For instance, the text might be set at runtime via JavaScript. Or I may want to take a screenshot and compare it with a previous reference screenshot, to test layouts. By default, apparently the browser is using the machine's locale, which breaks continuous integration tests. So the question is how can PhantomJS be configured from a Play Framework test.