Java tutorial
// Copyright (C) 2013 Google Inc. // // 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.google.caja.plugin; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.TimeUnit; import org.openqa.selenium.Capabilities; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.logging.LogEntries; import org.openqa.selenium.logging.LogEntry; import org.openqa.selenium.logging.LogType; import org.openqa.selenium.logging.Logs; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; import com.google.caja.SomethingWidgyHappenedError; import com.google.caja.util.TestFlag; import com.google.gwt.thirdparty.guava.common.base.Charsets; /** * Wrapper around a WebDriver instance. */ class WebDriverHandle { private RemoteWebDriver driver = null; private boolean canExecuteScript = true; private boolean reportedVersion = false; private String firstWindow = null; private int windowSeq = 0; private boolean windowOpened = false; // Don't keep more than this many failed test windows. (Otherwise // a broken tree can overload a machine with browser windows.) private static final int MAX_FAILS_KEPT = 9; private static int failsKept = 0; WebDriver begin() { if (driver == null) { driver = makeDriver(); firstWindow = driver.getWindowHandle(); reportVersion(driver); try { driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS); } catch (WebDriverException e) { Echo.echo("failed to set pageLoadTimeout: " + e); // harmless, ignore } try { driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS); } catch (WebDriverException e) { Echo.echo("failed to setScriptTimeout: " + e); // harmless, ignore } } // Try to open a new window String name = "cajatest" + (windowSeq++); windowOpened = (Boolean) executeScript("return !!window.open('', '" + name + "');"); if (windowOpened) { driver.switchTo().window(name); } return driver; } // Selenium 2.33 has trouble executing script on Firefox 23 and later private Object executeScript(String script) { if (canExecuteScript) { try { return driver.executeScript(script); } catch (WebDriverException e) { canExecuteScript = false; Echo.echo("executeScript failed: " + e); } } return null; } private void reportVersion(RemoteWebDriver driver) { if (reportedVersion) { return; } reportedVersion = true; Capabilities caps = driver.getCapabilities(); String name = caps.getBrowserName(); if (name == null) { name = "unknown"; } String version = caps.getVersion(); if (version == null) { version = "unknown"; } // Firefox's version is something like "20.0", which doesn't tell // you the exact build, so we also try to report buildID. String build = (String) executeScript("return String(navigator.buildID || '')"); if (build != null && !"".equals(build)) { version += " build " + build; } Echo.echo("webdriver: browser " + name + " version " + version); } void end(boolean passed) { // If a test fails, drop the driver handle without close or quit, // leaving the browser open, which is helpful for debugging. if (!passed && !TestFlag.BROWSER_CLOSE.truthy() && failsKept++ < MAX_FAILS_KEPT) { driver = null; } else { try { // If we're reusing the same browser, close the current window. if (windowOpened) { driver.close(); driver.switchTo().window(firstWindow); } else { driver.get("about:blank"); } } catch (Exception e) { Echo.echo("window cleanup failed: " + e); closeDriver(); } } } void release() { closeDriver(); } private void closeDriver() { if (driver != null) { try { driver.quit(); } finally { driver = null; } } } private static RemoteWebDriver makeDriver() { DesiredCapabilities dc = new DesiredCapabilities(); String browserType = TestFlag.BROWSER.getString("firefox"); if ("chrome".equals(browserType)) { // Chrome driver is odd in that the path to Chrome is specified // by a desiredCapability when you start a session. The other // browser drivers will read a java system property on start. // This applies to both remote Chrome and local Chrome. ChromeOptions chromeOpts = new ChromeOptions(); String chromeBin = TestFlag.CHROME_BINARY.getString(null); if (chromeBin != null) { chromeOpts.setBinary(chromeBin); } String chromeArgs = TestFlag.CHROME_ARGS.getString(null); if (chromeArgs != null) { String[] args = chromeArgs.split(";"); chromeOpts.addArguments(args); } dc.setCapability(ChromeOptions.CAPABILITY, chromeOpts); } String url = TestFlag.WEBDRIVER_URL.getString(""); if (!"".equals(url)) { dc.setBrowserName(browserType); dc.setJavascriptEnabled(true); try { return new RemoteWebDriver(new URL(url), dc); } catch (MalformedURLException e) { throw new RuntimeException(e); } } else if ("chrome".equals(browserType)) { return new ChromeDriver(dc); } else if ("firefox".equals(browserType)) { return new FirefoxDriver(); } else if ("safari".equals(browserType)) { // TODO(felix8a): local safari doesn't work yet return new SafariDriver(); } else { throw new RuntimeException("No local driver for browser type '" + browserType + "'"); } } public void captureResults(String name) { if (driver == null) { return; } String dir = TestFlag.CAPTURE_TO.getString(""); if ("".equals(dir)) { return; } if (!dir.endsWith("/")) { dir = dir + "/"; } mkdirs(dir); // Try to capture the final html try { String source = driver.getPageSource(); if (source != null) { saveToFile(dir + name + ".capture.html", source); } } catch (WebDriverException e) { Echo.echo("capture html failed: " + e); } // Try to capture a screenshot if (driver instanceof TakesScreenshot) { TakesScreenshot ss = (TakesScreenshot) driver; try { byte[] bytes = ss.getScreenshotAs(OutputType.BYTES); saveToFile(dir + name + ".capture.png", bytes); } catch (WebDriverException e) { Echo.echo("capture screenshot failed: " + e); } } // Try to capture logs try { Logs logs = driver.manage().logs(); if (logs != null) { if (logs.getAvailableLogTypes().contains(LogType.BROWSER)) { LogEntries entries = logs.get(LogType.BROWSER); if (entries != null) { StringBuilder sb = new StringBuilder(); for (LogEntry e : entries) { sb.append(e.toString() + "\n"); } saveToFile(dir + name + ".capture.log", sb.toString()); } } } } catch (WebDriverException e) { Echo.echo("capture logs failed: " + e); } } private static void mkdirs(String dirName) { File dir = new File(dirName); if (!dir.isDirectory() && !dir.mkdirs()) { Echo.echo("couldn't mkdir " + dirName); } } private static void saveToFile(String fileName, String str) { saveToFile(fileName, str.getBytes(Charsets.UTF_8)); } private static void saveToFile(String fileName, byte[] bytes) { FileOutputStream out = null; try { out = new FileOutputStream(fileName); try { out.write(bytes); } finally { out.close(); } } catch (IOException e) { throw new SomethingWidgyHappenedError(e); } } }