/******************************************************************************* * Copyright 2017 Ivan Shubin http://galenframework.com * * 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 com.galenframework.page.selenium; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import com.galenframework.config.GalenConfig; import com.galenframework.config.GalenProperty; import com.galenframework.page.Rect; import com.galenframework.page.AbsentPageElement; import com.galenframework.page.Page; import com.galenframework.page.PageElement; import com.galenframework.specs.page.Locator; import com.galenframework.rainbow4j.Rainbow4J; import com.galenframework.utils.GalenUtils; import org.openqa.selenium.*; import static com.galenframework.page.selenium.ByChain.fromLocator; public class SeleniumPage implements Page { private WebDriver driver; private Map<String, PageElement> cachedPageElements = new HashMap<>(); private PageElement parentObject; private BufferedImage cachedScreenshotImage; private File cachedScreenshotFile; private int offsetLeft = 0; private int offsetTop = 0; private final SearchContext driverSearchContext; public SeleniumPage(WebDriver driver) { this(driver, driver); } private SeleniumPage(WebDriver driver, SearchContext driverSearchContext) { this.driver = driver; this.driverSearchContext = driverSearchContext; } private SeleniumPage(WebDriver driver, SearchContext searchContext, Locator objectContextLocator) { this.driver = driver; WebElement contextElement = findObjectContext(searchContext, objectContextLocator); this.driverSearchContext = contextElement; this.parentObject = new WebPageElement(driver, "parent", contextElement, objectContextLocator) .withOffset(offsetLeft, offsetTop); } private WebElement findObjectContext(SearchContext searchContext, Locator objectContextLocator) { if (objectContextLocator != null) { ByChain byChain = fromLocator(objectContextLocator); if (byChain == null) { throw new RuntimeException("Cannot convert locator " + objectContextLocator.prettyString()); } return byChain.findElement(searchContext); } else { throw new IllegalArgumentException("objectContextLocator cannot be null"); } } @Override public PageElement getObject(Locator objectLocator) { return locatorToElement("unnamed", objectLocator); } @Override public PageElement getObject(String objectName, Locator objectLocator) { if (objectName != null) { PageElement pageElement = cachedPageElements.get(objectName); if (pageElement == null) { pageElement = getObject(objectLocator); cachedPageElements.put(objectName, pageElement); return pageElement; } else { return pageElement; } } else { return locatorToElement("unnamed", objectLocator); } } private List<WebElement> driverFindElements(ByChain byChain) { return byChain.findElements(driverSearchContext); } private WebElement driverFindElement(ByChain byChain) { return byChain.findElement(driverSearchContext); } private PageElement locatorToElement(String objectName, Locator objectLocator) { PageElement pageElement; ByChain byChain = fromLocator(objectLocator); try { WebElement webElement = driverFindElement(byChain); pageElement = new WebPageElement(driver, objectName, webElement, objectLocator).withOffset(offsetLeft, offsetTop); } catch (NoSuchElementException e) { pageElement = new AbsentPageElement(); } return pageElement; } @Override public PageElement getSpecialObject(String objectName) { if ("screen".equals(objectName)) { return new ScreenElement(driver).withOffset(offsetLeft, offsetTop); } else if ("viewport".equals(objectName)) { return new ViewportElement(driver); } else if ("parent".equals(objectName) || "self".equals(objectName)) { if (parentObject != null) { return parentObject; } else throw new RuntimeException("There is no " + objectName + " object defined on page"); } else return null; } @Override public int getObjectCount(Locator locator) { return driverFindElements(fromLocator(locator)).size(); } @Override public Page createObjectContextPage(Locator objectContextLocator) { return new SeleniumPage(this.driver, this.driverSearchContext, objectContextLocator); } @Override public File getScreenshotFile() { if (this.cachedScreenshotFile == null) { cachedScreenshotFile = createNewScreenshot(); } return this.cachedScreenshotFile; } private File createNewScreenshot() { try { if (GalenConfig.getConfig().getBooleanProperty(GalenProperty.SCREENSHOT_FULLPAGE)) { return GalenUtils.makeFullScreenshot(driver); } else return makeSimpleScreenshot(); } catch (Exception e) { throw new RuntimeException("Error making screenshot", e); } } private File makeSimpleScreenshot() throws IOException { return GalenUtils.takeScreenshot(driver); } @Override public void setScreenshot(File screenshotFile) { this.cachedScreenshotFile = screenshotFile; } @Override public BufferedImage getScreenshotImage() { if (this.cachedScreenshotImage == null) { try { cachedScreenshotImage = Rainbow4J.loadImage(getScreenshotFile().getAbsolutePath()); } catch (Exception e) { throw new RuntimeException("Couldn't take screenshot for page", e); } } return this.cachedScreenshotImage; } @Override public String getTitle() { return driver.getTitle(); } @Override public void switchToFrame(PageElement mainObject) { WebPageElement webPageElement = (WebPageElement)mainObject; driver.switchTo().frame(webPageElement.getWebElement()); } @Override public void switchToParentFrame() { driver.switchTo().parentFrame(); } @Override public Page createFrameContext(PageElement frameElement) { SeleniumPage framePage = new SeleniumPage(driver); Rect mainObjectArea = frameElement.getArea(); framePage.setOffset(mainObjectArea.getLeft(), mainObjectArea.getTop()); framePage.switchToFrame(frameElement); framePage.setParentObject(frameElement); return framePage; } private void setOffset(int offsetLeft, int offsetTop) { this.offsetLeft = offsetLeft; this.offsetTop = offsetTop; } public PageElement getParentObject() { return parentObject; } public void setParentObject(PageElement parentObject) { this.parentObject = parentObject; } public WebDriver getDriver() { return driver; } }