/* * Copyright 2002-2007 the original author or authors. * * 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 org.suren.autotest.web.framework.selenium; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_CHROME; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_FIREFOX; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_HTML_UNIT; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_IE; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_OPERA; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_PHANTOM_JS; import static org.suren.autotest.web.framework.settings.DriverConstants.DRIVER_SAFARI; import static org.suren.autotest.web.framework.settings.DriverConstants.ENGINE_CONFIG_FILE_NAME; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import org.openqa.selenium.Cookie; import org.openqa.selenium.Dimension; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.UnsupportedCommandException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver.Options; import org.openqa.selenium.WebDriver.Window; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.htmlunit.HtmlUnitDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.opera.OperaDriver; import org.openqa.selenium.phantomjs.PhantomJSDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.suren.autotest.web.framework.core.AutoTestException; import org.suren.autotest.web.framework.data.DynamicData; import org.suren.autotest.web.framework.settings.DriverConstants; import org.suren.autotest.web.framework.util.StringUtils; import org.suren.autotest.web.framework.util.ThreadUtil; import org.suren.autotest.webdriver.downloader.DriverDownloader; import org.suren.autotest.webdriver.downloader.DriverMapping; import org.suren.autotest.webdriver.downloader.PathUtil; /** * 浏览器引擎封装类 * @author suren * @since jdk1.6 2016年6月29日 */ @Component @Scope(value = "autotest", proxyMode = ScopedProxyMode.TARGET_CLASS) public class SeleniumEngine { private static final Logger logger = LoggerFactory.getLogger(SeleniumEngine.class); private final Properties enginePro = new Properties(); //引擎参数集合 private final Map<String, Object> dataMap = new HashMap<String, Object>(); private Map<String, DesiredCapabilities> engineCapMap = new HashMap<String, DesiredCapabilities>(); private WebDriver driver; private String driverStr; private String remoteStr; private long timeout; private boolean fullScreen; private boolean maximize; private int width; private int height; private int toolbarHeight; @Autowired private List<DynamicData> dynamicDataList; public SeleniumEngine(){} /** * 初始化配置文件 */ public void initConfig() { try { ClassLoader classLoader = this.getClass().getClassLoader(); loadDefaultEnginePath(classLoader, enginePro); //加载默认配置 System.getProperties().putAll(enginePro); } catch (MalformedURLException e) { e.printStackTrace(); } } /** * 浏览器启动前的回调函数 * @param enginePro */ public void beforeStart(Properties enginePro){}; /** * 浏览器引擎初始化 */ public void init() { initConfig(); beforeStart(enginePro); new CapabilityConfig(engineCapMap, enginePro).config(); String curDriverStr = getDriverStr(); DesiredCapabilities capability = engineCapMap.get(curDriverStr); if(StringUtils.isNotBlank(getRemoteStr())) { try { driver = new RemoteWebDriver(new URL(getRemoteStr()), capability); } catch (MalformedURLException e) { throw new AutoTestException(); } } else if(DRIVER_CHROME.equals(curDriverStr)) { driver = new ChromeDriver(capability); } else if(DRIVER_IE.equals(curDriverStr)) { driver = new InternetExplorerDriver(capability); } else if(DRIVER_FIREFOX.equals(curDriverStr)) { // String proFile = System.getProperty("firefox.profile", null); // FirefoxProfile profile = new FirefoxProfile(proFile != null ? new File(proFile) : null); // fireFoxPreSet(profile); // FirefoxOptions firefoxOptions = new FirefoxOptions(); // firefoxOptions.setProfile(new FirefoxProfile()); // driver = new FirefoxDriver(firefoxOptions); // FirefoxProfile profile = new FirefoxProfile(); // profile.setPreference("browser.tabs.remote.autostart", false); // profile.setPreference("browser.tabs.remote.autostart.1", false); // profile.setPreference("browser.tabs.remote.autostart.2", false); // profile.setPreference("browser.tabs.remote.force-enable", false); // capability.setCapability(FirefoxDriver.PROFILE, profile); driver = new FirefoxDriver(capability); } else if(DRIVER_SAFARI.equals(curDriverStr)) { driver = new SafariDriver(capability); } else if(DRIVER_OPERA.equals(curDriverStr)) { driver = new OperaDriver(capability); } else if(DRIVER_PHANTOM_JS.equals(curDriverStr)) { driver = new PhantomJSDriver(capability); } else if(DRIVER_HTML_UNIT.equals(curDriverStr)) { driver = new HtmlUnitDriver(true); } else { throw new RuntimeException(String.format("Unknow type driver [%s].", curDriverStr)); } if(timeout > 0) { driver.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS); } Window window = driver.manage().window(); if(fullScreen) { try { // window.fullscreen(); } catch(UnsupportedCommandException e) { logger.error("Unsupported fullScreen command.", e); } } // 处理cookie Options manage = driver.manage(); boolean cookieLoad = Boolean.parseBoolean(enginePro.getProperty("cookie.load", "false")); File root = PathUtil.getRootDir(); File cookieFile = new File(root, enginePro.getProperty("cookie.save.path", "phoenix.autotest.cookie")); if(cookieLoad) { try(ObjectInputStream input = new ObjectInputStream(new FileInputStream(cookieFile))) { Object cookiesObj = input.readObject(); if(cookiesObj != null && cookiesObj instanceof Set<?>) { Set<Cookie> cookies = (Set<Cookie>) cookiesObj; for(Cookie cookie : cookies) { manage.addCookie(cookie); } } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } if(maximize) { window.maximize(); } if(getWidth() > 0) { window.setSize(new Dimension(getWidth(), window.getSize().getHeight())); } if(getHeight() > 0) { window.setSize(new Dimension(window.getSize().getWidth(), getHeight())); } } /** * @return 引擎中的配置参数 */ public Map<Object, Object> getEngineConfig() { return Collections.unmodifiableMap(enginePro == null ? new Properties() : enginePro); } public void setProgressId(String key, String identify) { enginePro.put(key, identify); } /** * @return 谷歌浏览器版本 */ public String getChromeVer() { return enginePro.getProperty(DriverConstants.DRIVER_CHROME + ".version"); } public void setChromeVer(String ver) { enginePro.setProperty(DriverConstants.DRIVER_CHROME + ".version", ver); } /** * 加载默认的engine * @param enginePro * @throws MalformedURLException */ private void loadDefaultEnginePath(ClassLoader classLoader, Properties enginePro) throws MalformedURLException { Enumeration<URL> resurceUrls = null; URL defaultResourceUrl = null; try { resurceUrls = classLoader.getResources(ENGINE_CONFIG_FILE_NAME); defaultResourceUrl = classLoader.getResource(ENGINE_CONFIG_FILE_NAME); } catch (IOException e) { logger.error("Engine properties loading error.", e); } if(resurceUrls == null) { return; } //这里包含所有的,包括jar中的 while(resurceUrls.hasMoreElements()) { URL url = resurceUrls.nextElement(); try { loadFromURL(enginePro, url); } catch (IOException e) { logger.error("loading engine error.", e); } } try { //这里是运行类路径下的 loadFromURL(enginePro, defaultResourceUrl); } catch (IOException e) { logger.error("loading engine error.", e); } loadDriverFromMapping(classLoader, enginePro); } /** * 从映射文件中,动态获取当前需要加载的浏览器驱动 * @param classLoader * @param enginePro * @throws MalformedURLException */ private void loadDriverFromMapping(ClassLoader classLoader, Properties enginePro) throws MalformedURLException { //实现对多个操作系统的兼容性设置 final String os = System.getProperty("os.name"); final String arch = System.getProperty("os.arch"); final String curDriverStr = getDriverStr(); String commonOs = enginePro.getProperty("os.map.name." + os); String commonArch = enginePro.getProperty("os.map.arch." + arch); if(StringUtils.isAnyBlank(commonOs, commonArch)) { throw new RuntimeException(String.format("unknow os [%s] and arch [%s].", os, arch)); } final String ver = enginePro.getProperty(curDriverStr + ".version"); DriverMapping driverMapping = new DriverMapping(); driverMapping.init(); URL driverURL = null; String remoteDriverUrl = driverMapping.getUrl(curDriverStr, ver, commonOs, commonArch); if(remoteDriverUrl == null) { logger.error(String.format("Can not found remote driver url, browser is" + " [%s], version is [%s], os is [%s], arch is [%s].", curDriverStr, ver, commonOs, commonArch)); } else { driverURL = new URL(remoteDriverUrl); String driverPath = null; try { driverPath = new DriverDownloader().getLocalFilePath(driverURL); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if(StringUtils.isBlank(driverPath)) { throw new RuntimeException("Driver path is empty!"); } enginePro.put(String.format("webdriver.%s.driver", curDriverStr), driverPath); } } private void loadFromURL(Properties enginePro, URL url) throws IOException { try(InputStream inputStream = url.openStream()) { enginePro.load(inputStream); } } /** * @return */ public boolean storePro() { ClassLoader classLoader = this.getClass().getClassLoader(); return storePro(classLoader); } /** * @param classLoader * @return */ public boolean storePro(ClassLoader classLoader) { URL defaultResourceUrl = classLoader.getResource(ENGINE_CONFIG_FILE_NAME); try(OutputStream out = new FileOutputStream( new File(URLDecoder.decode(defaultResourceUrl.getFile(), "utf-8")))) { enginePro.store(out, ""); return true; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } /** * 转为为初始化的驱动 * @param driver * @return */ public WebDriver turnToRootDriver(WebDriver driver) { return driver.switchTo().defaultContent(); } /** * 打开指定地址 * @param url */ public void openUrl(String url) { driver.get(url); dataMap.put("sys.startUrl", url); } /** * @return 系统数据配置,不可修改 */ public Map<String, Object> getDataMap() { return Collections.unmodifiableMap(dataMap); } /** * 延迟关闭 * @param timeout 单位:毫秒 */ public void delayClose(long timeout) { ThreadUtil.silentSleep(timeout); close(); } /** * 关闭浏览器引擎 */ public void close() { if(driver != null) { Options manage = driver.manage(); boolean cookieSave = Boolean.parseBoolean(enginePro.getProperty("cookie.save", "false")); File root = PathUtil.getRootDir(); File cookieFile = new File(root, enginePro.getProperty("cookie.save.path", "phoenix.autotest.cookie")); if(cookieSave) { Set<Cookie> cookies = manage.getCookies(); try(ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(cookieFile))) { output.writeObject(cookies); } catch (IOException e) { e.printStackTrace(); } } driver.quit(); } } /** * @return 引擎对象 */ public WebDriver getDriver() { return driver; } /** * @return 引擎名称 */ public String getDriverStr() { return driverStr; } /** * 设置引擎名称 * @param driverStr */ public void setDriverStr(String driverStr) { this.driverStr = driverStr; } public String getRemoteStr() { return remoteStr; } public void setRemoteStr(String remoteStr) { this.remoteStr = remoteStr; if(remoteStr == null) { return; } for(DynamicData dynamicData : dynamicDataList) { if("system".equals(dynamicData.getType())) { this.remoteStr = dynamicData.getValue(remoteStr); break; } } } /** * @return 超时时间 */ public long getTimeout() { return timeout; } /** * 设定超时时间 * @param timeout */ public void setTimeout(long timeout) { this.timeout = timeout; } /** * @return 全屏返回true,否则返回false */ public boolean isFullScreen() { return fullScreen; } /** * 设置是否要全屏 * @param fullScreen */ public void setFullScreen(boolean fullScreen) { this.fullScreen = fullScreen; } /** * @return 浏览器宽度 */ public int getWidth() { return width; } /** * 设置浏览器宽度 * @param width */ public void setWidth(int width) { this.width = width; } /** * @return 浏览器高度 */ public int getHeight() { return height; } /** * 设置浏览器高度 * @param height */ public void setHeight(int height) { this.height = height; } /** * @return the maximize */ public boolean isMaximize() { return maximize; } /** * @param maximize the maximize to set */ public void setMaximize(boolean maximize) { this.maximize = maximize; } /** * 计算工具栏高度 * @return */ public int computeToolbarHeight() { JavascriptExecutor jsExe = (JavascriptExecutor) driver; Object objectHeight = jsExe.executeScript("return window.outerHeight - window.innerHeight;"); if(objectHeight instanceof Long) { toolbarHeight = ((Long) objectHeight).intValue(); } return toolbarHeight; } /** * @return the toolbarHeight */ public int getToolbarHeight() { return toolbarHeight; } }