Selenium WebDriver在加载页面的时候,无论是driver.get(url)或者driver.getPageSource(),会立即返回当时页面的数据。但当代的网页技术都大量使用了异步Ajax调用,这使得许多DOM元素的创建和加载,都分布在页面load结束后的许多零散的时间点,让WebDriver的findElement经常无功而返。这个时候,一般有两种方式来解决问题:
FluentWait<By> fluentWait = new FluentWait<By>(By.tagName("TEXTAREA")); fluentWait.pollingEvery(100, TimeUnit.MILLISECONDS); fluentWait.withTimeout(1000, TimeUnit.MILLISECONDS); fluentWait.until(new Predicate<By>() { public boolean apply(By by) { try { return browser.findElement(by).isDisplayed(); } catch (NoSuchElementException ex) { return false; } } }); browser.findElement(By.tagName("TEXTAREA")).sendKeys("text to enter");
public ExpectedCondition<WebElement> visibilityOfElementLocated(final By by) { return new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver driver) { WebElement element = driver.findElement(by); return element.isDisplayed() ? element : null; } }; } public void performSomeAction() { .. .. Wait<WebDriver> wait = new WebDriverWait(driver, 20); WebElement element = wait.until(visibilityOfElementLocated(By.tagName("a"))); .. }
protected void syncAjaxByJQuery(String timeout) { boolean isSucceed = false; try { selenium.waitForCondition( "selenium.browserbot.getCurrentWindow().jQuery.active == 0", timeout); isSucceed = true; } catch (SeleniumException se) { LOG.error(se); } catch (Exception re) { throw new RuntimeException(re.getMessage()); } operationCheck(isSucceed); } protected void syncAjaxByPrototype(String timeout) { boolean isSucceed = false; try { selenium.waitForCondition( "selenium.browserbot.getCurrentWindow().Ajax.activeRequestCount == 0", timeout); isSucceed = true; } catch (SeleniumException se) { LOG.error(se); } catch (Exception re) { throw new RuntimeException(re.getMessage()); } operationCheck(isSucceed); } protected void syncAjaxByDojo(String timeout) { boolean isSucceed = false; try { selenium.waitForCondition( "selenium.browserbot.getCurrentWindow().dojo.io.XMLHTTPTransport.inFlight.length == 0", timeout); isSucceed = true; } catch (SeleniumException se) { LOG.error(se); } catch (Exception re) { throw new RuntimeException(re.getMessage()); } operationCheck(isSucceed); }
最近遇到许多网页用Selenium操作的时候,网页本身会弹出许多Alert模态窗口,这种模态窗口会阻断driver继续执行。虽然WebDriver已经提供了些许方法来处理模态Alert窗口,但是依然会在不同的浏览器上存在未修复的Bug。先来看看WebDriver提供的处理Alert的方式,基本就是通过driver.switchTo()方法获得Alert模态窗口的句柄,然后调用Alert.accept()或者Alert.dismiss()方法接受或者拒绝,同样的操作也适用于Confirm窗口。我为了防止意外情况下WebDriver内置Alert处理的代码会崩溃,所以特意设计了一个超时机制,一旦超时就转而使用原始键盘模拟输入回车来消除窗口,使用的也是java.awt.Robot类来模拟操作系统的键盘输入动作。
public T handleAlert(){ KeyboardUtils.enter(); long clockTime = System.currentTimeMillis(); long timeout = 3 * 1000; while(true){ if((System.currentTimeMillis()-clockTime) > timeout){ KeyboardUtils.enter(); break; }else if(WebDriverUtils.isAlertExist(driver)){ try{ Alert alert = driver.switchTo().alert(); alert.getText(); alert.accept(); }catch(Exception ex){ KeyboardUtils.enter(); } } waiting(300); } return instance; } //In WebDriverUtils.class public static boolean isAlertExist(WebDriver driver){ try{ driver.switchTo().alert(); return true; }catch(NoAlertPresentException ex){ return false; } }
DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer(); ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); return new InternetExplorerDriver(ieCapabilities);
public static void closeWebDriver(WebDriver driver){ if(driver == null) return; try{ String current = driver.getWindowHandle(); Set<String> otherWins = driver.getWindowHandles(); for(String winId : otherWins) if(winId.equals(current)) continue; else driver.switchTo().window(winId).close(); }catch(Exception ex){ //ignore }finally{ try{ driver.quit(); }catch(Exception ex){} } }
public static String takeScreenshot(WebDriver driver, String savePath, long delay){ try { CommonUtils.waiting(delay * 1000); File screenShotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); String path = "screenshot/"+savePath; if(!savePath.endsWith("/.png")) path = path + ".png"; FileUtils.copyFile(screenShotFile, new File(path)); LOG.info("Take screenshot at "+savePath); return path; } catch (IOException ex) { LOG.warn("failed to take screenshot for current page, caused by "+ex.getMessage()); return null; } }