gwen.web.WebElementLocator.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gwen-web Show documentation
Show all versions of gwen-web Show documentation
Web automation engine for Gwen
/*
* Copyright 2014-2015 Branko Juric, Brady Wood
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gwen.web
import java.util
import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import gwen.Predefs.Kestrel
import com.typesafe.scalalogging.LazyLogging
/**
* Locates web elements using the selenium web driver.
*
* @author Branko Juric, Brady Wood
*/
trait WebElementLocator extends LazyLogging {
/**
* Locates a bound web element.
*
* @param env the web environment context
* @param elementBinding the web element locator binding
* @return the found element (errors if not found)
*/
private[web] def locate(env: WebEnvContext, elementBinding: LocatorBinding): WebElement = {
logger.debug(s"Locating ${elementBinding.element}")
findElementByLocator(env, elementBinding) match {
case Some(webElement) => webElement
case None => throw new NoSuchElementException(s"Web element not found: ${elementBinding.element}")
}
}
/** Finds an element by the given locator expression. */
private def findElementByLocator(env: WebEnvContext, elementBinding: LocatorBinding): Option[WebElement] = {
val lookup = elementBinding.lookup
val locator = elementBinding.locator
(locator match {
case "id" => getElement(env, By.id(lookup), elementBinding)
case "name" => getElement(env, By.name(lookup), elementBinding)
case "tag name" => getElement(env, By.tagName(lookup), elementBinding)
case "css selector" => getElement(env, By.cssSelector(lookup), elementBinding)
case "xpath" => getElement(env, By.xpath(lookup), elementBinding)
case "class name" => getElement(env, By.className(lookup), elementBinding)
case "link text" => getElement(env, By.linkText(lookup), elementBinding)
case "partial link text" => getElement(env, By.partialLinkText(lookup), elementBinding)
case "javascript" => getElementByJavaScript(env, s"$lookup")
case _ => throw new LocatorBindingException(elementBinding.element, s"unsupported locator: $locator")
}) tap { optWebElement =>
optWebElement foreach { webElement =>
if (!webElement.isDisplayed) {
env.scrollIntoView(webElement, ScrollTo.top)
}
env.highlight(webElement)
}
}
}
/**
* Gets a web element using the given by locator.
*
* @param env the web environment context
* @param by the by locator
*/
private def getElement(env: WebEnvContext, by: By, elementBinding: LocatorBinding): Option[WebElement] = Option {
env.withWebDriver { driver =>
val handle = driver.getWindowHandle
try {
elementBinding.container.fold(driver.findElement(by)) { containerName =>
getContainerElement(env, env.getLocatorBinding(containerName)) match {
case Some(containerElem) => containerElem.findElement(by)
case _ => driver.findElement(by)
}
}
} catch {
case e: Throwable =>
driver.switchTo().window(handle)
throw e
}
}
}
/**
* Gets container web element using the given by locator.
*
* @param env the web environment context
* @param containerBinding the container binding
*/
private def getContainerElement(env: WebEnvContext, containerBinding: LocatorBinding): Option[WebElement] = {
val container = findElementByLocator(env, containerBinding)
container flatMap { containerElem =>
containerElem.getTagName match {
case "iframe" | "frame" =>
env.withWebDriver(_.switchTo().frame(containerElem))
None
case _ =>
container
}
}
}
/**
* Gets a web element by the given javascript expression. If the web element is not
* visible in the browser, then the element is brought into view by scrolling to it.
*
* @param env the web environment context
* @param javascript the javascript expression for returning the element
*/
private def getElementByJavaScript(env: WebEnvContext, javascript: String): Option[WebElement] = {
var element: Option[WebElement] = None
env.waitUntil {
element = env.executeScript(s"return $javascript") match {
case elems: util.ArrayList[_] =>
if (!elems.isEmpty) Option(elems.get(0).asInstanceOf[WebElement])
else None
case elem => Option(elem) match {
case Some(e) => Option(e.asInstanceOf[WebElement])
case None => None
}
}
element.isDefined
}
element
}
}
/**
* Captures a web element locator binding.
*
* @param element the web element name
* @param locator the locator type
* @param lookup the lookup string
* @param container optional parent container name
*/
case class LocatorBinding(element: String, locator: String, lookup: String, container: Option[String])
/** Thrown when a web element cannot be located. */
class LocatorBindingException(element: String, causeMsg: String) extends RuntimeException(s"Could not locate $element: $causeMsg")
© 2015 - 2025 Weber Informatics LLC | Privacy Policy