/* * 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 versão 3 como publicada pela Fundação * do Software Livre (FSF). * * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português * para maiores detalhes. * * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título * "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/> * ou escreva para a Fundação 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.Date; 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.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; Logger log = Logger.getLogger(WebBase.class); public static ElementMap loadingMap = null; public static boolean alreadySearchLoadingMap = false; public WebDriver getDriver() { return (WebDriver) getRunner().getDriver(); } /** * Mostra no log (DEBUG) as informações estatísticas da execução do teste. * * @param msg * mensagem a ser mostrada no log */ public void logStatistics(String msg) { if (BehaveConfig.getRunner_ShowExecutionStatistics()) { log.debug(msg); } } /** * Função 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 { 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 getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); try { // Primeiro tenta encontrar na página sem frame sem Timeout List<WebElement> elementsFound = getDriver().findElements(by); if (elementsFound.size() > 0) { elements.addAll(elementsFound); } else { // Se não encontrar nada sem frames busca nos frames elements = getElementsWithFrames(getDriver(), by); } } catch (Throwable t) { // Se não encontrar nada sem frames busca nos frames elements = getElementsWithFrames(getDriver(), by); } finally { getDriver().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); } } /** * Retorna lista de elementos filtrados pelo By dentro dos frames do navegador, sendo que o primeiro elemento encontrado dentro de um frame será retornado. * * @param driver * WebDriver a ser utilizado * @param by * Locator by * @return Lista de elementos que foram encontrados no frame */ 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) { elements.addAll(elementsFound); found = true; break; } } if (found) { break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); // Controle do timeout manualmente if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait()) { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } return elements; } /** * Método que faz a substituição dos parâmetros no locator (param1, param2) * * @param locator * texto do locator com parâmetros * @return o locator atualizado com os parâmetros */ 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; } /** * Retorna o texto do elemento corrente utilizando o método de várias tentativas até dar o timeout selecionado pelo usuário. Este getText é difeirente do getTexto puro do WebDriver pois possui o mecanismo de várias tentativas. * * @return o texto de dentro (innerText) do elemento */ public String getText() { waitElement(0); String s = null; final long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); Exception lastEx = null; while (true) { try { getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); // A implementação final do GET TEXT do WebDriver faz // verificações a mais que o nosso Wait Element que pode fazer // com que de problema em algumas situações não mapeadas, por // isso ficamos tentando até conseguir s = getElements().get(0).getText(); log.debug("Conteúdo do elemento: " + s); break; } catch (Exception e) { log.warn("Erro no getText do Webdriver"); log.warn(e); lastEx = e; } finally { // Volta o tempo padrão de timeout getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); // Controle do timeout manualmente if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait()) { if (lastEx != null) { throw new BehaveException(lastEx); } throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } } return s; } /** * Método de thread wait. Apesar de não ser recomandada a utilização deste método ele se faz necessário em muitos casos, principalmente em casos que dependam de renderização dos objetos no navegador. * * @param delay * tempo de espera */ protected static void waitThreadSleep(Long delay) { try { Thread.sleep(delay); } catch (InterruptedException ex) { throw new BehaveException(message.getString("exception-thread-sleep"), ex); } } /** * * @param index * Posição no Array de locators do elemento */ public void waitElement(Integer index) { // Locators final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); final long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); // Variável para calcular o tempo gasto para encontrar o texto Date startWaitTotal = GregorianCalendar.getInstance().getTime(); // Executa o controle de verificação de tempo manualmente while (true) { try { // É necessário um minimo período de tempo para renderização de // objetos waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); // WARN: É necessário setar o TIMEOUT desta maneira para que o // WebDriverWait tenha um timeout correto getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); // Aguarda o loading waitLoading(); // --------------- Cálculo do tempo gasto --------------- Date endLoading = GregorianCalendar.getInstance().getTime(); Long diffLoading = endLoading.getTime() - startWaitTotal.getTime(); logStatistics("O tempo para esperar o LOADING foi de [" + diffLoading + "ms]"); // Garante o tempo minimo para verificação getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); // Espera ser visível e clicável waitClickable(by); // --------------- Cálculo do tempo gasto --------------- Date endClickable = GregorianCalendar.getInstance().getTime(); Long diffClickable = endClickable.getTime() - endLoading.getTime(); Long diffTotal = endClickable.getTime() - startWaitTotal.getTime(); logStatistics("O tempo para esperar o CLICKABLE foi de [" + diffClickable + "ms] e total foi de [" + diffTotal + "ms]"); // Garante o tempo minimo para verificação getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); // Esta verificação é necessária mesmo que dentro do clickable // ele já faça waitVisibility(by); // --------------- Cálculo do tempo gasto --------------- Date endVisibility = GregorianCalendar.getInstance().getTime(); Long diffVisibility = endVisibility.getTime() - endClickable.getTime(); diffTotal = endVisibility.getTime() - startWaitTotal.getTime(); logStatistics("O tempo para esperar o VISIBILITY foi de [" + diffVisibility + "ms] e total foi de [" + diffTotal + "ms]"); // Passou por todas as verificações break; } catch (Exception e) { log.warn("Erro no Wait Element"); log.warn(e); } finally { // Volta o tempo padrão de timeout getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); // Controle do timeout manualmente if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait()) { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } } } /** * Aguarda o elemento ficar visível na tela. * * @param index * Posição no Array de locators do elemento */ public void waitElementOnlyVisible(Integer index) { try { // WARN: É necessário setar o TIMEOUT desta maneira para que o // WebDriverWait tenha um timeout correto getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); waitLoading(); waitVisibility(by); } finally { // Volta o tempo padrão de timeout getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } /** * Método que verifica em todas as classes se existe um componente Loading, e se existir, ele sempre espera que este elemento desapareça antes de continuar. */ @SuppressWarnings("unchecked") public void waitLoading() { 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(getDriver()); existeLoading = true; log.debug(message.getString("message-loading-visible")); } catch (Exception e) { existeLoading = false; log.debug(message.getString("message-loading-not-found")); } if (existeLoading) { // Força esperar o loading aparecer quando o elemento utilizado // tem a propriedade forWaitLoading na anotação @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")); } } } /** * Procura por um elemento dentro do TODOS os FRAMES/IFRAMES da página, e assim que encontrar ele deixa o frame selecionado para ser utilizado. * * @param by * Locator para lolizar o elemento */ private void findFrameContainingElement(By by) { try { getDriver().manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); // Variável para calcular o tempo gasto Date startWaitTotal = GregorianCalendar.getInstance().getTime(); // Primeiro encontra o frame que o elemento esta, para depois // esperar // ele frame = getSwitchDriver(getDriver()); long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); boolean found = false; // --------------- Cálculo do tempo gasto --------------- Date endGetSwitcher = GregorianCalendar.getInstance().getTime(); Long diffFrame = endGetSwitcher.getTime() - startWaitTotal.getTime(); logStatistics("[findFrameContainingElement] O tempo para esperar o getSwitchDriver foi de [" + diffFrame + "ms]"); while (true) { Date startBind = GregorianCalendar.getInstance().getTime(); frame.bind(); // --------------- Cálculo do tempo gasto --------------- Date endBind = GregorianCalendar.getInstance().getTime(); Long diffBind = endBind.getTime() - startBind.getTime(); Long diffTotal = endBind.getTime() - startWaitTotal.getTime(); logStatistics("[findFrameContainingElement] O tempo para esperar o BIND foi de [" + diffBind + "ms] e total foi de [" + diffTotal + "ms]"); for (int i = 0; i < frame.countFrames(); i++) { // --- SWITCH FRAME --- Date startSwitchFrame = GregorianCalendar.getInstance().getTime(); frame.switchNextFrame(); // --------------- Cálculo do tempo gasto --------------- Date endSwitchFrame = GregorianCalendar.getInstance().getTime(); Long diffSwitchFrame = endSwitchFrame.getTime() - startSwitchFrame.getTime(); diffTotal = endSwitchFrame.getTime() - startWaitTotal.getTime(); logStatistics("[findFrameContainingElement] O tempo para esperar o SWITCH FRAME foi de [" + diffSwitchFrame + "ms] e total foi de [" + diffTotal + "ms]"); // --- FIND ELEMENT --- Date startFindElement = GregorianCalendar.getInstance().getTime(); List<WebElement> elementsFound = getDriver().findElements(by); // --------------- Cálculo do tempo gasto --------------- Date endFindElement = GregorianCalendar.getInstance().getTime(); Long diffFindElement = endFindElement.getTime() - startFindElement.getTime(); diffTotal = endFindElement.getTime() - startWaitTotal.getTime(); logStatistics("[findFrameContainingElement] O tempo para esperar o FIND ELEMENTS foi de [" + diffFindElement + "ms] e total foi de [" + diffTotal + "ms]"); if (elementsFound.size() > 0) { found = true; break; } } if (found) { // --------------- Cálculo do tempo gasto --------------- Date end = GregorianCalendar.getInstance().getTime(); diffTotal = end.getTime() - startWaitTotal.getTime(); logStatistics("[findFrameContainingElement] O tempo para total do processo foi de [" + diffTotal + "ms]"); break; } waitThreadSleep(BehaveConfig.getRunner_ScreenMinWait()); // Controle do timeout manualmente if (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait()) { throw new BehaveException(message.getString("exception-element-not-found", getElementMap().name())); } } } finally { // Volta o tempo padrão de timeout getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } /** * Método que verifica se um elemento está VISÍVEL e DESABILITADO levando em consideração atributos como readonly e disabled. */ public void isVisibleDisabled() { List<WebElement> elementsFound = getElements(); if (elementsFound.size() > 0) { WebElement e = elementsFound.get(0); // Tem que estar Visível e Desabilitado, se estiver invisível OU // habilitado lança a exception if (e.getTagName().toLowerCase().equals("input") || e.getTagName().toLowerCase().equals("select") || e.getTagName().toLowerCase().equals("a")) { // Verifica também se tem o atributo READONLY no elemento String readonlyAttribute = e.getAttribute("readonly"); String disabledAttribute = e.getAttribute("disabled"); // SE não estiver visivel OU (não possuir o attr DISABLED E não // possuir o attr READONLY) ENTÃO 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 verificação 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())); } } /** * Aguarda um elemento estar visível, clicável e habilitado. */ public void waitVisibleClickableEnabled() { try { // WARN: É necessário setar o TIMEOUT desta maneira para que o // WebDriverWait tenha um timeout correto getDriver().manage().timeouts().implicitlyWait(getImplicitlyWaitTimeoutInMilliseconds(), TimeUnit.MILLISECONDS); // Locators final String locator = getLocatorWithParameters(getElementMap().locator()[0].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); // Wait waitClickable(by); } finally { // Volta o tempo padrão de timeout getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); } } /** * Aguarda o elemento ser clicável. * * ATENÇÃO: condition 'clickable' is equivalent to 'visible and enabled' https://code.google.com/p/selenium/issues/detail?id=6804 * * @param by */ private void waitClickable(By by) { // Variável para calcular o tempo gasto Date startWaitTotal = GregorianCalendar.getInstance().getTime(); findFrameContainingElement(by); // --------------- Cálculo do tempo gasto --------------- Date endFrame = GregorianCalendar.getInstance().getTime(); Long diffFrame = endFrame.getTime() - startWaitTotal.getTime(); logStatistics("[waitClickable] O tempo para esperar a busca por FRAME foi de [" + diffFrame + "ms]"); // Faz a verificação no FRAME selecionado WebDriverWait wait = new WebDriverWait(getDriver(), BehaveConfig.getRunner_ScreenMaxWait() / 1000); wait.until(ExpectedConditions.elementToBeClickable(by)); // --------------- Cálculo do tempo gasto --------------- Date endWaitExplicit = GregorianCalendar.getInstance().getTime(); Long diffWaitExcplicit = endWaitExplicit.getTime() - endFrame.getTime(); Long diffTotal = endWaitExplicit.getTime() - startWaitTotal.getTime(); logStatistics("[waitClickable] O tempo para esperar o WAIT EXPLICITO foi de [" + diffWaitExcplicit + "ms] e total foi de [" + diffTotal + "ms]"); } /** * Método que retorna um tempo fixo para que o Implicitly Wait do WebDriver tente encontrar um elemento na tela * * @return tempo de timeout para Implicitly Wait */ public Long getImplicitlyWaitTimeoutInMilliseconds() { return 1000L; } /** * Aguardda o elemento estar visível. * * @param by * Locator do elemento. */ private void waitVisibility(By by) { findFrameContainingElement(by); // Faz a verificação no FRAME selecionado WebDriverWait wait = new WebDriverWait(getDriver(), BehaveConfig.getRunner_ScreenMaxWait() / 1000); wait.until(ExpectedConditions.visibilityOfElementLocated(by)); } /** * * @return */ public List<String> getLocatorParameter() { return locatorParameters; } public void setLocatorParameters(List<String> locatorParameter2) { this.locatorParameters = locatorParameter2; } /** * Retorna um Driver executor de códigos Javascript. Verifica se o driver em uso possui a capacidade de executar códigos 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 ID do primeiro elemento do locator */ 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; } /** * Retorna o SwitchDriver do Driver atual. O Switch Driver é responsável pela manipulação de frames de um navegador. * * @param driver * @return Instância de SwitchDriver */ private SwitchDriver getSwitchDriver(WebDriver driver) { frame = new SwitchDriver(driver); return frame; } /** * Aguarda um texto ficar visível na página. É importante saber que textos que não estão visíveis mas estão no HTML não são considerados. Também não são considerados textos que estiverem dentro das tags SCRIPT e STYLE. * * @param text * Texto a ser encontrado. */ public void waitVisibleText(String text) { WebDriver driver = (WebDriver) runner.getDriver(); frame = getSwitchDriver(driver); final long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); boolean found = false; // Variável para calcular o tempo gasto para encontrar o texto Date startSearch = GregorianCalendar.getInstance().getTime(); while (true) { try { getDriver().manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); // Mesmo que não tenha frame ele pega o "primeiro" frame.bind(); // Quando tem somente 1 frame if (frame.countFrames() == 1) { List<WebElement> elementsFound = getDriver().findElements(By.xpath("/html")); String textHtml = elementsFound.get(0).getText(); logStatistics("O tamanho do texto analisado é de [" + textHtml.getBytes().length + " bytes]"); if (textHtml.contains(text)) { found = true; break; } } else { for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); List<WebElement> elementsFound = getDriver().findElements(By.xpath("/html")); if (elementsFound.size() == 1) { WebElement element = elementsFound.get(0); String textHtml = element.getText(); logStatistics("[FRAME] O tamanho do texto analisado é de [" + textHtml.getBytes().length + " bytes] no frame [" + frame.currentFrame() + "]"); if (textHtml.contains(text)) { found = true; break; } } } } // Quando encontra o texto if (found) { // Cálculo do tempo gasto para encontrar o texto Long diffSearch = GregorianCalendar.getInstance().getTime().getTime() - startSearch.getTime(); logStatistics("O tempo para encontrar o texto foi de [" + diffSearch + "ms]"); break; } } catch (BehaveException be) { log.warn("waitVisibleText BehaveException"); log.warn(be); } catch (Exception e) { log.warn("waitVisibleText Exception"); log.warn(e); } finally { getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); // Controle do timeout manualmente if (!found && (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait())) { Assert.fail(message.getString("message-text-not-found", text)); } } } } /** * Aguarda um texto NÃO ficar visível na página. É importante saber que textos que não estão visíveis mas estão no HTML não são considerados. Também não são considerados textos que estiverem dentro das tags SCRIPT e STYLE. * * @param text * Texto a ser encontrado. */ public void waitNotVisibleText(String text) { frame = getSwitchDriver(getDriver()); final long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); boolean found = true; // Verifica 3 vezes se existe antes de continuar int countTries = 1; int maxCountTries = 3; while (true) { try { getDriver().manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS); // Mesmo que não tenha frame ele pega o "primeiro" frame.bind(); // Quando tem somente 1 frame if (frame.countFrames() == 1) { List<WebElement> elementsFound = getDriver().findElements(By.xpath("/html")); if (!elementsFound.get(0).getText().contains(text) && countTries >= maxCountTries) { found = false; break; } } else { for (int i = 0; i < frame.countFrames(); i++) { frame.switchNextFrame(); List<WebElement> elementsFound = getDriver().findElements(By.xpath("/html")); if (elementsFound.size() == 1) { WebElement element = elementsFound.get(0); if (!element.getText().contains(text) && countTries >= maxCountTries) { found = false; break; } } } } if (!found) { break; } countTries += 1; } catch (BehaveException be) { log.warn("waitNotVisibleText BehaveException"); log.warn(be); } catch (Exception e) { log.warn("waitNotVisibleText Exception"); log.warn(e); } finally { getDriver().manage().timeouts().implicitlyWait(BehaveConfig.getRunner_ScreenMaxWait(), TimeUnit.MILLISECONDS); // Controle do timeout manualmente if (found && (GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait())) { Assert.fail(message.getString("message-text-found", text)); } } } } /** * Método que busca o texto dentro de um elemento utilizando os métodos de tentativa e controle manual de timeout. * * @param text * Texto a ser encontrado no elemento. * @param visible * Verifica se o texto está visível (true) ou não (false) */ public void waitVisibleOrNotTextInElement(String text, boolean visible) { long startedTime = GregorianCalendar.getInstance().getTimeInMillis(); boolean ok = false; while (true) { try { /* * Busca o texto dentro do elemento, atentar para o método getText, ele não é o getText do WebDriver e sim do Element do framework (WebTextField, WebSelect...) */ String elementText = getText(); if (visible) { log.debug("Existe o texto [" + text + "] no texto do elemento [" + elementText + "]?"); if (elementText.contains(text)) { log.debug("SIM!"); ok = true; break; } else { log.debug("NÃO!"); } } else { log.debug("NÃO existe o texto [" + text + "] no texto do elemento [" + elementText + "]?"); if (!elementText.contains(text)) { log.debug("SIM!"); ok = true; break; } else { log.debug("NÃO!"); } } log.debug("Vai TENTAR novamente encontrar o texto"); } catch (BehaveException be) { log.warn("Text in element BehaveException"); log.warn(be); } catch (Exception e) { log.warn("Text in element Exception"); log.warn(e); } finally { // Controle do timeout manualmente if (!ok && GregorianCalendar.getInstance().getTimeInMillis() - startedTime > BehaveConfig.getRunner_ScreenMaxWait()) { Assert.fail(message.getString("message-text-not-found", text)); } } } } /** * Método chamado pelas frases que aguardam o primeiro elemento do locator não está visível. */ public void waitInvisible() { waitInvisible(0); } /** * Aguarda que um elemento selecionado pela sua posição no locator não esteja visível. * * @param index * Posição no locator do element. */ public void waitInvisible(int index) { final String locator = getLocatorWithParameters(getElementMap().locator()[index].toString()); final By by = ByConverter.convert(getElementMap().locatorType(), locator); boolean testInvisibility = true; try { // Aguarda o elemento ficar visivel (MinWait) Long waitTimeVis = (BehaveConfig.getRunner_ScreenMinWait() / 1000); WebDriverWait waitVis = new WebDriverWait(getDriver(), 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(getDriver(), waitTime); wait.until(ExpectedConditions.invisibilityOfElementLocated(by)); } } /** * Retira o foco do campo. O comportamento padrão para isso é selecionar o <body> */ public void blur() { getDriver().findElement(By.tagName("body")).click(); } /** * Aguarda um texto na página inteira (exceto as tags script e style). Na verdade chama o método waitVisibleText * * @param text * Texto a ser encontrato na página. */ public void waitText(String text) { waitVisibleText(text); } /** * Aguarda que o texto não esteja na página inteira (exceto as tags script e style). Na verdade chama o método waitNotVisibleText * * @param text * Texto a não ser encontrado na página. */ public void waitNotText(String text) { waitNotVisibleText(text); } /** * Aguarda que o elemento atual não contenha o texto. * * @param text * Texto a não ser encontrato no elemento. */ public void waitTextNotInElement(String text) { waitVisibleOrNotTextInElement(text, false); } /** * Aguarda que o elemento atual contenha o texto. * * @param text * Texto a ser encontrato no elemento. */ public void waitTextInElement(String text) { waitVisibleOrNotTextInElement(text, true); } }