pattern patron page diseño java selenium webdriver selenium-webdriver pageobjects

java - patron - Espere al elemento-WebDriver-Patrón de pageObject



patron de diseño page factory (2)

Siempre que use el patrón PageObject, me pregunto dónde debo esperar el elemento en las páginas dinámicas. Suponiendo que tenemos el método de prueba y la clase pageObject. ¿Debo hacer algo como (en el método de prueba):

  1. Haga clic en el botón
  2. Espere a que se muestre el elemento
  3. Verificar el elemento (contiene, por ejemplo, el método isElementDisplayed ())

¿O tal vez hay otra buena práctica para esperar el elemento? Tal vez deberíamos esperar al elemento en el método isElementDisplayed que está en PageObject.class?


Debe esperar elementos en su clase de objeto de página, no en clase de prueba, porque sus elementos deben definirse en clase de objeto de página, la clase de prueba no debe saber nada de ningún elemento, selector o similar. Las pruebas, en mi humilde opinión, deberían contener únicamente cadenas de llamadas a métodos que describan el flujo de prueba, toda la interacción con el sitio web y el DOM subyacente debería tener lugar en la clase de objeto de página.

Entonces, un método demasiado detallado para esperar a que aparezca algún elemento podría ser algo así como:

private final By yourElement = By.id("id"); @Override public void isLoaded() throws Error { new FluentWait<WebDriver>(driver) .withTimeout(60, TimeUnit.SECONDS) .pollingEvery(1, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class) .ignoring(StaleElementReferenceException.class) .until(new Function<WebDriver, Boolean>() { @NotNull @Override public Boolean apply(WebDriver webDriver) { WebElement element = driver.findElement(yourElement); return element != null && element.isDisplayed(); } }); }

En palabras simples, la función si consulta el DOM durante 60 segundos (cada 1 segundo) para ver si el elemento existe en DOM y está visible (significa que tiene altura y witdh mayor que 1px). Si el elemento existe (y se muestra), la función devuelve el elemento encontrado y detiene el sondeo (aunque el método isLoaded() no devuelve el elemento en este caso particular).

Tiene sentido ignorar NoSuchElementException que puede ser lanzado por el método findElement en caso de que no se encuentre el elemento, y StaleElementException , que indica que una referencia a un elemento ahora está "obsoleta" - el elemento ya no aparece en el DOM de la página. Esto generalmente significa que algo (más comúnmente JS) ha modificado el DOM y la referencia ya no es válida, por lo tanto, el WebDriver necesita buscarla de nuevo.

Por supuesto, un código más corto también serviría para el truco, algo así como:

new WebDriverWait(driver, 60) .until(ExpectedConditions.visibilityOf(someWebElement));

La documentación es bastante buena en esto.

EDIT: respuesta al comentario:

Entendido. Pero, ¿y si el elemento está presente después de hacer clic en algún botón, etc.?

Supongamos que tiene un escenario, donde tiene un botón y luego de hacer clic en ese botón, aparece un cuadro de texto y desea interactuar con él.

public class PageObject extends LoadableComponent<PageObject>{ public PageObject() throws Exception { driver = getWebDriver(); PageFactory.initElements(driver, this); isLoaded(); } private WebDriver driver = null; @FindBy(id = "yourButton") private WebElement button; @FindBy(id = "textBoxThatAppears") private WebElement txtBox; @Override public void isLoaded() throws Error { // Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible. waitForVisibility(button); } private void waitForVisibility(WebElement element) throws Error{ new WebDriverWait(driver, 60) .until(ExpectedConditions.visibilityOf(element)); } public void clickButton(){ button.click(); } public void interactWithTextbox(String text){ // Wait for txtBox to be visible, then send text waitForVisibility(txtBox); txtBox.sendKeys(text); // EDIT 27.04.14: // Actually you should not do the assertion here or anywhere in // the pageObject, because when reusing the method in some other test, you might // not want to assert, you might wonder that why wouldn''t you assert some // specific condition every time, but I would throw that question right back // to you and ask: What is the point of checking the exact same thing over and // over again. There are 2 things, firstly the assertion takes resources (and // that can become important when test suite grows, secondly your tests can // simply start failing at the same point when one little condition is not as // it should be. Also, having the asserts in the test, makes the test more // readable and understandable for others. // end edit 27.04.14 // Next line is no longer recommended by this answer. // assert that something happened that you expected. } }

Y ahora tu clase de prueba:

public void TestClass { @Test public void testClickButtonAndInteractWithTextbox(){ // Initiate the page object Pageobject po = new PageObject(); po.clickButtonAndWaitForTextbox(); po.interactWithTextbox("blabla"); // edit 27.04.14 assertSomethingGoodHappened(); } }


Otro concepto eficiente de página de prueba (desde el selenio 1) de uno de los marcos de prueba de selenio - ISFW puede utilizarse aquí. Tiene un elemento cargado de forma diferida, función de componente personalizada y espera automática (no espera implícita que reduzca el rendimiento), métodos de espera incorporados con elementos y otras características que son muy útiles para la aplicación de bases ajax.

Proporciona los siguientes bloques de construcción para el desarrollo de casos de prueba:

  1. Página de prueba
  2. Componente
  3. Paso de prueba

Además, los informes también son descriptivos.