/* * 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.action; import java.awt.AWTException; import java.awt.Robot; import java.util.Iterator; import java.util.Set; import org.openqa.selenium.Dimension; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Point; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.suren.autotest.web.framework.core.ElementSearchStrategy; import org.suren.autotest.web.framework.core.action.ClickAble; import org.suren.autotest.web.framework.core.ui.AbstractElement; import org.suren.autotest.web.framework.core.ui.Element; import org.suren.autotest.web.framework.core.ui.FileUpload; import org.suren.autotest.web.framework.selenium.SeleniumEngine; import org.suren.autotest.web.framework.selenium.strategy.SearchStrategyUtils; /** * 通过Selenium实现点击(单击、双击) * * @author suren * @since jdk1.6 2016年6月29日 */ @Component public class SeleniumClick implements ClickAble { private static final Logger logger = LoggerFactory.getLogger(SeleniumClick.class); /** 失败后重试的最大次数 */ private int maxRetry = 3; private static final String ERR_TIMES = "CLICK_ERR_TIMES"; @Autowired private SeleniumEngine engine; @Autowired private SearchStrategyUtils searchStrategyUtils; @Override public void click(Element ele) { int errorTimes = 0; if(ele instanceof AbstractElement) { Object errObj = ((AbstractElement) ele).getData(ERR_TIMES); if(errObj instanceof Integer) { errorTimes = (Integer) errObj; if(errorTimes >= maxRetry) { return; } } } if(errorTimes > 0) { logger.warn(String.format("Click operation retry times [%s].", errorTimes)); } ElementSearchStrategy<WebElement> searchStrategy = searchStrategyUtils.findStrategy(WebElement.class, ele); WebElement webEle = searchStrategy.search(ele); if(webEle == null) { throw new RuntimeException(String.format("Element [%s] can not found " + "by strategy [%s]!", ele, searchStrategy)); } try { //对于远程服务的文件上传,不移动鼠标 if(!(ele instanceof FileUpload) && !(engine.getDriver() instanceof RemoteWebDriver)) { Dimension size = webEle.getSize(); Point loc = webEle.getLocation(); int toolbarHeight = engine.getToolbarHeight(); int x = size.getWidth() / 2 + loc.getX(); int y = size.getHeight() / 2 + loc.getY() + toolbarHeight; new Robot().mouseMove(x, y); } webEle.click(); //如果是a标签锚点的话,根据target属性来决定是否要切换window句柄 String tagName = webEle.getTagName(); String targetAttr = webEle.getAttribute("target"); if("a".equals(tagName) && "_blank".equals(targetAttr)) { WebDriver driver = engine.getDriver(); Set<String> handlers = driver.getWindowHandles(); Iterator<String> it = handlers.iterator(); while(it.hasNext()) { String name = it.next(); driver.switchTo().window(name); } } } catch(WebDriverException e) { logger.error(String.format("元素[%s]点击操作发生错误。", webEle), e); if(ele instanceof AbstractElement) { ((AbstractElement) ele).putData(ERR_TIMES, ++errorTimes); } //如果由于目标元素不在可见区域导致的异常,尝试滚动屏幕 if(e.getMessage().contains("is not clickable at point")) { logger.info("Will retry click operation, after element move."); new Actions(engine.getDriver()).moveToElement(webEle, -50, -50).perform(); WebDriverWait wait = new WebDriverWait(engine.getDriver(), 30); ((JavascriptExecutor) engine.getDriver()).executeScript("arguments[0].scrollIntoView();", webEle, -50, -50); wait.until(ExpectedConditions.visibilityOf(webEle)); click(ele); } } catch (AWTException e) { e.printStackTrace(); } } @Override public void dbClick(Element ele) { Actions actions = new Actions(engine.getDriver()); actions.doubleClick(searchStrategyUtils.findStrategy(WebElement.class, ele).search(ele)); } @Override public boolean isEnabled(Element element) { return searchStrategyUtils.findStrategy(WebElement.class, element).search(element).isEnabled(); } @Override public boolean isHidden(Element element) { return !searchStrategyUtils.findStrategy(WebElement.class, element).search(element).isDisplayed(); } /** * @return 失败后重试的最大次数 */ public int getMaxRetry() { return maxRetry; } /** * @param maxRetry 失败后重试的最大次数(默认为3) */ public void setMaxRetry(int maxRetry) { this.maxRetry = maxRetry; } }