Skip to content

Commit

Permalink
Simplify browser configuration #10 -
Browse files Browse the repository at this point in the history
configurations are now provided via Configuration class and stored in loginConfig and config respectively
the configurations will then be applied in the beforeEach method. Configurations in loginConfig will be applied before calling login(),
the once in config will be applied afterwards.
  • Loading branch information
Daniel.Rey committed Oct 22, 2016
1 parent e05ad0c commit 6cc8180
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 127 deletions.
37 changes: 27 additions & 10 deletions aem/src/main/scala/org/scalawebtest/aem/AemTweaks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,44 @@
*/
package org.scalawebtest.aem

import org.openqa.selenium.Cookie
import org.scalawebtest.aem.WcmMode._
import org.scalawebtest.core.IntegrationSpec
import org.scalawebtest.core.{Configuration, FormBasedLogin, IntegrationSpec, WebClientExposingDriver}

trait AemTweaks { self: IntegrationSpec =>
/**
* Extend this trait to inherit useful default configuration for AEM projects.
*
* In addition it allows for convenient selection of the wcmmode.
*/
trait AemTweaks {
self: IntegrationSpec with FormBasedLogin =>

override val config = new Configuration() with AemConfig
override val loginPath = "/libs/granite/core/content/login.html"

trait AemConfig {
self: Configuration =>
def setWcmMode(wcmMode: WcmMode) = configurations += "wcmMode" ->
((webDriver: WebClientExposingDriver) => setWcmModeCookie(wcmMode))
}

private def setWcmModeCookie(mode: WcmMode) {
add cookie("wcmmode", mode.toString)
}

/**
* Fixture to set the wccmode for the given function call
*/
def withWcmMode[X](mode: WcmMode) = withWcmModeInternal(mode, _: X => Unit)

private def withWcmModeInternal[X](mode: WcmMode, f: X => Unit): X => Unit = {
x: X => {
setWcmMode(mode)
setWcmModeCookie(mode)
try {
f(x)
} finally {
setWcmMode(DISABLED)
setWcmModeCookie(DISABLED)
}
}
}

def setWcmMode(mode: WcmMode) {
prepareCookieContext()
val cookie = new Cookie("wcmmode", mode.toString)
webDriver.manage().addCookie(cookie)
}
}
35 changes: 35 additions & 0 deletions core/src/main/scala/org/scalawebtest/core/Configuration.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.scalawebtest.core

class Configuration() {
var configurations: Map[String, WebClientExposingDriver => Unit] = Map()

//initialize with sensible default configuration
disableJavaScript()
swallowJavaScriptErrors()
disableCss()

def enableJavaScript(throwOnError: Boolean): Unit = {
configurations += "enableJavaScript" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setJavaScriptEnabled(true))
configurations += "throwOnJSError" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setThrowExceptionOnFailingStatusCode(throwOnError))
}

def disableJavaScript(): Unit = {
configurations += "enableJavaScript" -> ((webDriver: WebClientExposingDriver) => webDriver.getOptions.setJavaScriptEnabled(false))
configurations += "throwOnJSError" -> ((webDriver: WebClientExposingDriver) => webDriver.getOptions.setThrowExceptionOnFailingStatusCode(false))
}

def throwOnJavaScriptError(): Unit = configurations += "throwOnJSError" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setThrowExceptionOnFailingStatusCode(true))

def swallowJavaScriptErrors(): Unit = configurations += "throwOnJSError" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setThrowExceptionOnFailingStatusCode(false))

def enableCss(): Unit = configurations += "enableCss" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setCssEnabled(true))

def disableCss(): Unit = configurations += "enableCss" ->
((webDriver: WebClientExposingDriver) => webDriver.getOptions.setCssEnabled(false))

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package org.scalawebtest.core
* Default settings
*/
trait IntegrationSettings {
val host = "http://localhost:4502"

val host = "http://localhost:8080"
val projectRoot = ""
}
65 changes: 48 additions & 17 deletions core/src/main/scala/org/scalawebtest/core/Login.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,67 @@
*/
package org.scalawebtest.core

import javax.xml.bind.DatatypeConverter

import org.scalatest.concurrent.PatienceConfiguration.Timeout
import org.scalatest.time.SpanSugar._

import scala.language.postfixOps

/**
* Extend this trait when implementing you own login implementation,
* to assert identical username, password configuration across all implementations
*/
trait Login {
val username = "admin"
val password = "admin"
}

trait FormBasedLogin extends Login { self: IntegrationSpec =>
/**
* Extend the FormBasedLogin trait to provide login information via web form before every request.
*
* The following configurations are available with this login:
* - username
* - password
*
* - usernameFieldName
* - passwordFieldName
* - loginPath
* - loginTimeout
*/
trait FormBasedLogin extends Login {
self: IntegrationSpec =>
val username_fieldname = "j_username"
val password_fieldname = "j_password"

val loginPath = "/libs/granite/core/content/login.html"
val loginPath = "/login"

def loginTimeout = Timeout(5 seconds)

override def login() = {
withoutCss(withoutFollowingRedirects[Any](Any => {
eventually(loginTimeout)({
go to s"$host$loginPath"
click on username_fieldname
emailField(username_fieldname).value = username
click on password_fieldname
pwdField(password_fieldname).value = password

submit()
})
}))(())
eventually(loginTimeout)({
go to s"$host$loginPath"
click on username_fieldname
emailField(username_fieldname).value = username
click on password_fieldname
pwdField(password_fieldname).value = password

submit()
})
}
}

trait BasicAuthLogin extends Login { self: IntegrationSpec =>

}
/**
* Extend the BasicAuthLogin trait to provide credentials via basic authentication with every request.
*
* The following configurations are available with this login:
* - username
* - password
*/

trait CookieBasedLogin extends Login { self: IntegrationSpec =>
trait BasicAuthLogin extends Login {
self: IntegrationSpec =>
def base64Encode(value: String) = DatatypeConverter.printBase64Binary(value.getBytes())

webDriver.getClient.addRequestHeader("Authorization", "Basic " + base64Encode(username + ":" + password))
}
162 changes: 66 additions & 96 deletions core/src/main/scala/org/scalawebtest/core/Specs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,53 @@ import java.util.logging.Level
import org.openqa.selenium.Cookie
import org.scalatest._
import org.scalatest.concurrent.Eventually
import org.scalatest.concurrent.PatienceConfiguration.Timeout
import org.scalatest.selenium.WebBrowser
import org.scalatest.time.SpanSugar._
import org.slf4j.LoggerFactory

import scala.collection.mutable.ListBuffer
import scala.language.postfixOps

/**
* Base class for integration tests. Please extend this class, together with your extension of IntegrationSettings
*/

abstract class FlatSpecBehavior extends FlatSpec with Matchers with Inspectors

abstract class FreeSpecBehavior extends FreeSpec with Matchers with Inspectors

abstract class IntegrationFlatSpec extends FlatSpecBehavior with IntegrationSpec

abstract class IntegrationFreeSpec extends FreeSpecBehavior with IntegrationSpec

/**
* This is the base trait for integration specs. The recommended way is to create your own project specific trait, which extends
* IntegrationFlatSpec or IntegrationFreeSpec, depending on the ScalaTest style which you prefer.
*
* In you own implementation you will usually overwrite settings provided by the IntegrationSettings trait,
* adapted the default configuration available in loginConfig and config,
* and extend one of the Login traits if applicable.
*/
trait IntegrationSpec extends WebBrowser with Suite with BeforeAndAfterEach with BeforeAndAfterAll with WebClientExposingHtmlUnit with IntegrationSettings with Eventually {
val cookiesToBeDiscarded = new ListBuffer[Cookie]()
val logger = LoggerFactory.getLogger("IntegrationSpec")
val cookiesToBeDiscarded = new ListBuffer[Cookie]()
/**
* Configuration applied before login.
* Cookies cannot be set in this configuration. The webDriver
* has to open a connection, before it can set cookies
*/
val loginConfig = new Configuration
/**
* Configuration applied after login.
* Cookies may be added here.
*/
val config = new Configuration

def loginTimeout = Timeout(60 seconds)

webDriver.setJavascriptEnabled(false)
webDriver.getOptions.setThrowExceptionOnScriptError(false)
webDriver.getOptions.setCssEnabled(false)

/**
* Override to encode your project specific login mechanism.
*
* Best practice is to create a trait which overrides the login function and extends the trait Login.
*
* For the following standard mechanisms an implementation is already available.
* - fill login form with your credentials (use FormBasedLogin trait)
* - use basic authentication (use BasicAuthLogin trait)
*/
def login() {}

/**
Expand All @@ -59,29 +78,50 @@ trait IntegrationSpec extends WebBrowser with Suite with BeforeAndAfterEach with
*/
def afterLogin() = {}

def applyConfiguration(config: Configuration): Unit = {
config.configurations.values.foreach(configFunction =>
try {
configFunction(webDriver)
}
catch {
case e: Exception => logger.error("The following error occurred while applying settings.", e)
})
}

def avoidLogSpam(): Unit = {
java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF)
java.util.logging.Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.OFF)
java.util.logging.Logger.getLogger("net.lightbody").setLevel(Level.OFF)
}

override def afterEach() {
cookiesToBeDiscarded.foreach(cookie => delete cookie cookie.getName)
cookiesToBeDiscarded.clear()
}

/**
* Overwrite beforeLogin() and afterLogin() for test-specific tasks
*/
override def beforeAll() {
beforeLogin()
avoidLogSpam()
applyConfiguration(config)
login()
applyConfiguration(config)
afterLogin()
}

/**
* Sets a cookie for the current test. Any cookie set through this method
* is discarded after a test.
*/
def setCookie(name: String, value: String) {
prepareCookieContext()
def setCookieForSingleTest(name: String, value: String) {
val cookie: Cookie = new Cookie(name, value)
webDriver.manage().addCookie(cookie)
add cookie (name, value)
cookiesToBeDiscarded += cookie
}

def prepareCookieContext() {
// WebDriver needs to request a HTML page before cookies can be set, as cookies
// can only be set for a specific domain
if (pageSource isEmpty) {
withoutJavascript(withoutCss(webDriver.get))(s"$host/etc/packages.html")
}
}

def deleteCookie(name: String) = {
webDriver.manage().deleteCookieNamed(name)
}

/**
* Resets all cookies, sets the WCM mode to disabled and logs in again
*/
Expand All @@ -98,74 +138,4 @@ trait IntegrationSpec extends WebBrowser with Suite with BeforeAndAfterEach with
go to targetUrl
}
}

def withoutFollowingRedirects[X](f: X => Unit): X => Unit = withFollowingRedirectsInternal(f, enableRedirects = false)

def withFollowingRedirects[X](f: X => Unit): X => Unit = withFollowingRedirectsInternal(f, enableRedirects = true)

private def withFollowingRedirectsInternal[X](f: (X) => Unit, enableRedirects: Boolean): (X) => Unit = {
x: X => {
val redirectionEnabled = webDriver.getOptions.isRedirectEnabled
webDriver.getOptions.setRedirectEnabled(enableRedirects)
try {
f(x)
} finally {
webDriver.getOptions.setRedirectEnabled(redirectionEnabled)
}
}
}

def withoutCss[X](f: X => Unit): X => Unit = withCssInternal(f, enableCss = false)

def withCss[X](f: X => Unit): X => Unit = withCssInternal(f, enableCss = true)

private def withCssInternal[X](f: (X) => Unit, enableCss: Boolean): (X) => Unit = {
x: X => {
val wasEnabled = webDriver.getOptions.isCssEnabled
webDriver.getOptions.setCssEnabled(enableCss)
try {
f(x)
} finally {
webDriver.getOptions.setCssEnabled(wasEnabled)
}
}
}

def withoutJavascript[X](f: X => Unit): X => Unit = withJavascript(f, enabled = false)

def withJavascript[X](f: X => Unit): X => Unit = withJavascript(f, enabled = true)

private def withJavascript[X](f: (X) => Unit, enabled: Boolean): (X) => Unit = {
x: X => {
val jsEnabled = webDriver.getOptions.isJavaScriptEnabled
webDriver.getOptions.setJavaScriptEnabled(enabled)
try {
f(x)
} finally {
webDriver.getOptions.setJavaScriptEnabled(jsEnabled)
}
}
}

override def afterEach() {
cookiesToBeDiscarded.foreach(cookie => webDriver.manage().deleteCookieNamed(cookie.getName))
cookiesToBeDiscarded.clear()
}

/**
* Overwrite beforeLogin() and afterLogin() for test-specific tasks
*/
override def beforeAll() {
beforeLogin()
avoidLogSpam()
login()
afterLogin()
}

def avoidLogSpam() {
java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF)
java.util.logging.Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.OFF)
java.util.logging.Logger.getLogger("net.lightbody").setLevel(Level.OFF)
}

}
Loading

0 comments on commit 6cc8180

Please sign in to comment.