Java tutorial
/* * Demoiselle Framework * Copyright (C) 2013 SERPRO * ---------------------------------------------------------------------------- * This file is part of Demoiselle Framework. * * Demoiselle Framework is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License version 3 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License version 3 * along with this program; if not, see <http://www.gnu.org/licenses/> * or write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301, USA. * ---------------------------------------------------------------------------- * Este arquivo parte do Framework Demoiselle. * * O Framework Demoiselle um software livre; voc pode redistribu-lo e/ou * modific-lo dentro dos termos da GNU LGPL verso 3 como publicada pela Fundao * do Software Livre (FSF). * * Este programa distribudo na esperana que possa ser til, mas SEM NENHUMA * GARANTIA; sem uma garantia implcita de ADEQUAO a qualquer MERCADO ou * APLICAO EM PARTICULAR. Veja a Licena Pblica Geral GNU/LGPL em portugus * para maiores detalhes. * * Voc deve ter recebido uma cpia da GNU LGPL verso 3, sob o ttulo * "LICENCA.txt", junto com esse programa. Se no, acesse <http://www.gnu.org/licenses/> * ou escreva para a Fundao do Software Livre (FSF) Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. */ package br.gov.frameworkdemoiselle.behave.runner.webdriver.ui; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import org.junit.Assert; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoSuchFrameException; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.reflections.ReflectionUtils; import org.reflections.Reflections; import br.gov.frameworkdemoiselle.behave.annotation.ElementMap; import br.gov.frameworkdemoiselle.behave.annotation.ScreenMap; import br.gov.frameworkdemoiselle.behave.config.BehaveConfig; import br.gov.frameworkdemoiselle.behave.exception.BehaveException; import br.gov.frameworkdemoiselle.behave.internal.ui.MappedElement; import br.gov.frameworkdemoiselle.behave.message.BehaveMessage; import br.gov.frameworkdemoiselle.behave.runner.ui.BaseUI; import br.gov.frameworkdemoiselle.behave.runner.ui.Loading; import br.gov.frameworkdemoiselle.behave.runner.webdriver.WebDriverRunner; import br.gov.frameworkdemoiselle.behave.runner.webdriver.util.ByConverter; import br.gov.frameworkdemoiselle.behave.runner.webdriver.util.SwitchDriver; public class WebBase extends MappedElement implements BaseUI { private List<String> locatorParameters; private static BehaveMessage message = new BehaveMessage(WebDriverRunner.MESSAGEBUNDLE); private SwitchDriver frame; private WebDriver driver; Logger log = Logger.getLogger(WebBase.class); public static ElementMap loadingMap = null; public static boolean alreadySearchLoadingMap = false; /** * Funo principal que pega o elemento da tela. Nova Funcionalidade: Agora * ele busca o elemento em todos os frames * * @return Lista de elementos encontrados */ public List<WebElement> getElements() { try { driver = (WebDriver) runner.getDriver(); List<WebElement> elements = new ArrayList<WebElement>(); for (String locator : getElementMap().locator()) { // Locators locator = getLocatorWithParameters(locator); By by = ByConverter.convert(getElementMap().locatorType(), locator); // Todas as buscas por elemento tem seu timeout controlado pelo // Demoiselle Behave driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); try { // Primeiro tenta encontrar na pgina sem frame sem Timeout List<WebElement> elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { elements.add(element); } } else { // Se no encontrar nada sem frames busca nos frames elements = getElementsWithFrames(driver, by); } } catch (Throwable t) { // Se no encontrar nada sem frames busca nos frames elements = getElementsWithFrames(driver, by); } finally { driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } return elements; } catch (BehaveException be) { throw be; } catch (Exception e) { throw new BehaveException(message.getString("exception-unexpected", e.getMessage()), e); } } private List<WebElement> getElementsWithFrames(WebDriver driver, By by) { List<WebElement> elements = new ArrayList<WebElement>(); boolean found = false; frame = getSwitchDriver(driver); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); while (true) { frame.bind(); for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); List<WebElement> elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { elements.add(element); found = true; } break; } } if (found) { break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig .getRunner_ScreenMaxWait()) { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } return elements; } private String getLocatorWithParameters(String locator) { if (getLocatorParameter() != null && !getLocatorParameter().isEmpty() && locator.matches(".*%param[0-9]+%.*")) { int n = 1; for (String parameter : getLocatorParameter()) { String tag = "%param" + n + "%"; if (locator.contains(tag)) { locator = locator.replace(tag, parameter); } n++; } } return locator; } public String getText() { waitElement(0); return getElements().get(0).getText(); } protected static void waitThreadSleep(Long delay) { try { Thread.sleep(delay); } catch (InterruptedException ex) { throw new BehaveException(message.getString("exception-thread-sleep"), ex); } } public void waitElement(Integer index) { // Locators final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); // Aguarda o loading waitLoading(); // Espera ser visvel e clicvel waitClickable(by); // Esta verificao necessria mesmo que dentro do clickable ele j // faa waitVisibility(by); } public void waitElementOnlyVisible(Integer index) { waitLoading(); final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); waitVisibility(by); } /** * Mtodo que verifica em todas as classes se existe um componente Loading, * e se existir, ele sempre espera que este elemento desaparea antes de * continuar. */ @SuppressWarnings("unchecked") public void waitLoading() { driver = (WebDriver) runner.getDriver(); driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); if (!alreadySearchLoadingMap) { alreadySearchLoadingMap = true; Reflections reflections = new Reflections(""); Set<Class<?>> annotatedClasses = reflections.getTypesAnnotatedWith(ScreenMap.class); for (Class<?> clazzI : annotatedClasses) { HashSet<Field> fields = (HashSet<Field>) ReflectionUtils.getAllFields(clazzI, ReflectionUtils.withAnnotation(ElementMap.class), ReflectionUtils.withTypeAssignableTo(Loading.class)); if (fields.size() == 1) { for (Field field : fields) { loadingMap = field.getAnnotation(ElementMap.class); } } } } if (loadingMap != null) { boolean existeLoading; try { // Verifica se existe o LOADING ExpectedConditions .presenceOfElementLocated( ByConverter.convert(loadingMap.locatorType(), loadingMap.locator()[0])) .apply(driver); existeLoading = true; log.debug(message.getString("message-loading-visible")); } catch (Exception e) { existeLoading = false; } if (existeLoading) { // Fora esperar o loading aparecer quando o elemento utilizado // tem a propriedade forWaitLoading na anotao @ElementMap if (getElementMap() != null && getElementMap().forceWaitLoading()) { WebDriverWait wait = new WebDriverWait(getDriver(), (BehaveConfig.getRunner_ScreenMaxWait() / 1000)); wait.until(ExpectedConditions.visibilityOfElementLocated( ByConverter.convert(loadingMap.locatorType(), loadingMap.locator()[0]))); log.debug(message.getString("message-force-loading")); } // Aguardo o LOADING desaparecer! WebDriverWait wait = new WebDriverWait(getDriver(), (BehaveConfig.getRunner_ScreenMaxWait() / 1000)); wait.until(ExpectedConditions.invisibilityOfElementLocated( ByConverter.convert(loadingMap.locatorType(), loadingMap.locator()[0]))); log.debug(message.getString("message-loading-invisible")); } } driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } private void findFrameContainingElement(By by) { // Primeiro encontra o frame que o elemento esta, para depois esperar // ele getDriver().manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); frame = getSwitchDriver(getDriver()); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); boolean found = false; while (true) { frame.bind(); for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); List<WebElement> elementsFound = getDriver().findElements(by); if (elementsFound.size() > 0) { found = true; break; } } if (found) { break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig .getRunner_ScreenMaxWait()) { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } public void isVisibleDisabled() { List<WebElement> elementsFound = getElements(); if (elementsFound.size() > 0) { WebElement e = elementsFound.get(0); // Tem que estar Visvel e Desabilitado, se estiver invisvel OU // habilitado lana a exception if (e.getTagName().toLowerCase().equals("input") || e.getTagName().toLowerCase().equals("select") || e.getTagName().toLowerCase().equals("a")) { // Verifica tambm se tem o atributo READONLY no elemento String readonlyAttribute = e.getAttribute("readonly"); String disabledAttribute = e.getAttribute("disabled"); // SE no estiver visivel OU (no possuir o attr DISABLED E no // possuir o attr READONLY) ENTO de erro! if (!e.isDisplayed() || (disabledAttribute == null && readonlyAttribute == null)) { throw new BehaveException(message.getString("exception-element-not-displayed-or-enabled", getElementMap().name())); } } else { // Faz a verificao se esta desabilitado por meio das classes // de css para os casos de combo estilo Primefaces e Richfaces String classes = e.getAttribute("class"); if (!e.isDisplayed() || !classes.contains("disabled")) { throw new BehaveException(message.getString("exception-element-not-displayed-or-enabled", getElementMap().name())); } } } else { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } public void waitVisibleClickableEnabled() { // Locators final String locator = getLocatorWithParameters(getElementMap().locator()[0].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); // Wait waitClickable(by); } // condition 'clickable' is equivalent to 'visible and enabled' // https://code.google.com/p/selenium/issues/detail?id=6804 private void waitClickable(By by) { findFrameContainingElement(by); // Faz a verificao no FRAME selecionado WebDriverWait wait = new WebDriverWait(getDriver(), (BehaveConfig.getRunner_ScreenMaxWait() / 1000)); wait.until(ExpectedConditions.elementToBeClickable(by)); } private void waitVisibility(By by) { findFrameContainingElement(by); WebDriverWait wait = new WebDriverWait(getDriver(), (BehaveConfig.getRunner_ScreenMaxWait() / 1000)); wait.until(ExpectedConditions.visibilityOfElementLocated(by)); } public WebDriver getDriver() { WebDriver driver = (WebDriver) getRunner().getDriver(); return driver; } public List<String> getLocatorParameter() { return locatorParameters; } public void setLocatorParameters(List<String> locatorParameter2) { this.locatorParameters = locatorParameter2; } /** * Retorna um Driver executor de cdigos Javascript. Verifica se o driver em * uso possui a capacidade de executar cdigos Javascript. * * @return {@link JavascriptExecutor} */ public JavascriptExecutor getJavascriptExecutor() { if (!JavascriptExecutor.class.isAssignableFrom(this.runner.getDriver().getClass())) { throw new BehaveException( message.getString("exception-javascript-driver", runner.getDriver().getClass())); } return (JavascriptExecutor) this.runner.getDriver(); } /** * Retorna o ID do primeiro elemento de tela mapeado. * * @return */ public String getId() { String id = getElements().get(0).getAttribute("id"); if (id == null || id.isEmpty()) { throw new BehaveException(message.getString("exception-id-not-found", this.getElementMap().name())); } return id; } public void waitText(String text) { waitVisibleText(text); } private SwitchDriver getSwitchDriver(WebDriver driver) { frame = new SwitchDriver(driver); return frame; } /** * Neste mtodo waitText estamos forando que seja verificado dentro do body * atravs de um loop controlado por ns e no pelo implicityWait do * Webdriver. Por isso zeramos o implicityWait e depois voltamos para o * valor padro das propriedades. * * Mtodo que busca o texto visvel SOMENTE dentro do body do HTML. */ public void waitVisibleText(String text) { // Flag utilizada para o segundo lao boolean found = false; driver = (WebDriver) runner.getDriver(); frame = getSwitchDriver(driver); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); By by = By.tagName("body"); while (true) { try { driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); // Busca o texto no body List<WebElement> elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { if (element.getText().contains(text)) { found = true; break; } } } // Se no encontrar nada sem frames busca nos frames if (!found) { frame.bind(); for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); // Busca o texto no body elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { if (element.getText().contains(text)) { found = true; break; } } } } driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } catch (BehaveException be) { throw be; } catch (StaleElementReferenceException ex) { // Ignore this exception } catch (NoSuchFrameException ex) { throw new BehaveException(message.getString("exception-no-such-frame", frame.currentFrame(), ex)); } catch (Exception e) { throw new BehaveException(message.getString("exception-unexpected", e.getMessage()), e); } finally { driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } if (found) { break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if ((GregorianCalendar.getInstance().getTimeInMillis() - startedTime) > BehaveConfig .getRunner_ScreenMaxWait()) { Assert.fail(message.getString("message-text-not-found", text)); } } } /** * Neste mtodo waitText estamos forando que seja verificado dentro do body * atravs de um loop controlado por ns e no pelo implicityWait do * Webdriver. Por isso zeramos o implicityWait e depois voltamos para o * valor padro das propriedades. * * Mtodo que busca o texto visvel SOMENTE dentro do body do HTML. */ public void waitNotVisibleText(String text) { // Flag utilizada para o segundo lao boolean found = false; driver = (WebDriver) runner.getDriver(); frame = getSwitchDriver(driver); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); By by = By.tagName("body"); while (true) { try { driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); // Busca o texto no body List<WebElement> elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { if (element.getText().contains(text)) { found = true; break; } } } // Se no encontrar nada sem frames busca nos frames if (!found) { frame.bind(); for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); // Busca o texto no body elementsFound = driver.findElements(by); if (elementsFound.size() > 0) { for (WebElement element : elementsFound) { if (element.getText().contains(text)) { found = true; break; } } } } driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } catch (BehaveException be) { throw be; } catch (StaleElementReferenceException ex) { // Ignore this exception } catch (NoSuchFrameException ex) { throw new BehaveException(message.getString("exception-no-such-frame", frame.currentFrame(), ex)); } catch (Exception e) { throw new BehaveException(message.getString("exception-unexpected", e.getMessage()), e); } finally { driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } if (!found) { break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if ((GregorianCalendar.getInstance().getTimeInMillis() - startedTime) > BehaveConfig .getRunner_ScreenMaxWait()) { Assert.fail(message.getString("message-text-found", text)); } } } /** * Mtodo que busca o texto dentro de um elemento. */ public void waitTextInElement(String text) { try { driver = (WebDriver) runner.getDriver(); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); while (true) { driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); /* * Busca o texto dentro do elemento, atentar para o mtodo * getText, ele no o getText do WebDriver e sim do Element do * framework (WebTextField, WebSelect...) */ if (getText().contains(text)) { break; } driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig .getRunner_ScreenMaxWait()) { Assert.fail(message.getString("message-text-found", text)); } } } catch (BehaveException be) { throw be; } catch (Exception e) { throw new BehaveException(message.getString("exception-unexpected", e.getMessage()), e); } } public void waitInvisible() { waitInvisible(0); } public void waitInvisible(int index) { final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); boolean testInvisibility = true; driver = (WebDriver) runner.getDriver(); // Zera o tempo do driver, se no o implicity wait no funciona com o // tempo correto driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); try { // Aguarda o elemento ficar visivel (MinWait) Long waitTimeVis = (BehaveConfig.getRunner_ScreenMinWait() / 1000); WebDriverWait waitVis = new WebDriverWait(driver, waitTimeVis); waitVis.until(ExpectedConditions.visibilityOfElementLocated(by)); testInvisibility = true; } catch (org.openqa.selenium.TimeoutException e) { testInvisibility = false; } if (testInvisibility) { // Aguarda ele sumir Long waitTime = (BehaveConfig.getRunner_ScreenMaxWait() / 1000); WebDriverWait wait = new WebDriverWait(driver, waitTime); wait.until(ExpectedConditions.invisibilityOfElementLocated(by)); } // Volta o tempo padro (maxWait) no driver driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } /** * Retira o foco do campo. O comportamento padro para isso selecionar o * <body> */ public void blur() { driver = (WebDriver) runner.getDriver(); driver.findElement(By.tagName("body")).click(); } @Override public void waitNotText(String text) { waitNotVisibleText(text); } @Override public void waitTextNotInElement(String text) { try { driver = (WebDriver) runner.getDriver(); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); while (true) { driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); /* * Busca o texto dentro do elemento, atentar para o mtodo * getText, ele no o getText do WebDriver e sim do Element do * framework (WebTextField, WebSelect...) */ if (!getText().contains(text)) { break; } driver.manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig .getRunner_ScreenMaxWait()) { Assert.fail(message.getString("message-text-found", text)); } } } catch (BehaveException be) { throw be; } catch (Exception e) { throw new BehaveException(message.getString("exception-unexpected", e.getMessage()), e); } } }