Alguna sugerencia para las pruebas de extjs código en un navegador, de preferencia con selenio?

StackOverflow https://stackoverflow.com/questions/107314

Pregunta

Hemos estado utilizando el selenio, con gran éxito de manejar un alto nivel de sitio web de prueba (además de la amplia python doctests en un nivel de módulo).Sin embargo, ahora estamos usando extjs para un montón de páginas y sus resultando difícil incorporar Selenio pruebas para los componentes complejos como mallas.

Alguien ha tenido éxito la escritura de pruebas automatizadas para extjs-basado en páginas web?Un montón de googlear encuentra gente con problemas similares, pero pocas respuestas.Gracias!

¿Fue útil?

Solución

El obstáculo más grande en la prueba de ExtJS con el Selenio es que ExtJS no hacen estándar de los elementos HTML y el Selenium IDE ingenuamente (y con razón) generar los comandos dirigidos a los elementos que sólo actúan como decoración -- superfluo elementos que ayudan a ExtJS con todo el escritorio-look-and-feel.Aquí hay algunos consejos y trucos que he reunido durante la escritura de los automatizado de Selenio de la prueba en contra de un ExtJS aplicación.

Consejos Generales

La Localización De Los Elementos

Cuando la generación de Selenio de los casos de prueba mediante la grabación de acciones de usuario con Selenium IDE en Firefox, Selenio, base de las acciones registradas en los identificadores de los elementos HTML.Sin embargo, para la mayoría de los elementos seleccionables, ExtJS usa id generados como "ext-gen-345", que son propensos a cambiar en una visita posterior a la misma página, incluso si no hay cambios de código se han hecho.Después de la grabación de acciones de usuario para una prueba, no debe ser un esfuerzo manual para ir a través de todas las acciones que dependen de id generados y a reemplazarlos.Hay dos tipos de sustituciones que se pueden realizar:

La sustitución de un Id de Localizador con un CSS o XPath Localizador de

CSS localizadores de comenzar con "css=" y XPath localizadores de comenzar con "//" (el "xpath=" prefijo es opcional).CSS localizadores son menos detalladas y más fáciles de leer y debe ser preferido sobre XPath localizadores.Sin embargo, puede haber casos donde XPath localizadores de ser necesario, porque una de CSS localizador simplemente no se puede cortar.

La Ejecución De JavaScript

Algunos elementos requieren más que un simple ratón/teclado interacciones debido a la complejidad de la representación llevada a cabo por ExtJS.Por ejemplo, una Ext.el formulario.CombBox no es realmente un <select> elemento, sino de un texto de entrada con un desprendimiento de la lista desplegable que está en algún lugar en la parte inferior del árbol del documento.Con el fin de simular correctamente un ComboBox de selección, es posible que el primer simular un clic en la flecha de lista desplegable y, a continuación, haga clic en la lista que aparece.Sin embargo, la localización de estos elementos a través de CSS o XPath buscadores puede ser engorroso.Una alternativa es buscar el ComoBox componente de sí mismo y llamar a métodos en ella para simular la selección:

var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components
combo.setValue('female'); // set the value
combo.fireEvent('select'); // because setValue() doesn't trigger the event

En el Selenio runScript comando puede ser utilizado para realizar la operación anterior en una forma más concisa:

with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

Afrontamiento con AJAX y Lento de Representación

El selenio tiene "*AndWait" sabores para todos los comandos de espera para la carga de la página cuando un usuario resultados de la acción en las transiciones de página o recargas.Sin embargo, desde AJAX recupera no implican real de la carga de la página, estos comandos no puede ser utilizado para la sincronización.La solución es hacer uso de las pistas visuales como la presencia/ausencia de un AJAX indicador de progreso o la apariencia de filas en una cuadrícula, componentes adicionales, enlaces, etc.Por ejemplo:

Command: waitForElementNotPresent
Target: css=div:contains('Loading...')

A veces un elemento sólo aparece después de una cierta cantidad de tiempo, dependiendo de la rapidez con ExtJS representa los componentes después de una acción del usuario resulta en un cambio de vista.En lugar de utilizar arbitrarias de los retrasos con el pause comando, el método ideal es esperar hasta que el elemento de interés viene a nuestro alcance.Por ejemplo, al hacer clic sobre un elemento después de esperar para que aparezca:

Command: waitForElementPresent
Target: css=span:contains('Do the funky thing')
Command: click
Target: css=span:contains('Do the funky thing')

Confiando en arbitraria pausas no es una buena idea ya que las diferencias temporales que resultan de la ejecución de las pruebas en diferentes navegadores o en diferentes máquinas harán los casos de prueba de hojaldre.

No puede hacer clic Elementos

Algunos de los elementos no puede ser desencadenada por la click comando.Es debido a que el detector de eventos que en realidad está en el contenedor, viendo los eventos de ratón en sus elementos secundarios, que, finalmente, la burbuja de los padres.La ficha de control es un ejemplo.Haga clic en la pestaña, usted tiene que simular un mouseDown evento en la pestaña etiqueta:

Command: mouseDownAt
Target: css=.x-tab-strip-text:contains('Options')
Value: 0,0

Validación De Campo

Los campos de formulario (Ext.el formulario.* los componentes) que se han asociado expresiones regulares o vtypes para la validación se disparará la validación con un cierto retraso (véase el validationDelay la propiedad que se establece en 250 ms por defecto), después de que el usuario escribe texto o inmediatamente cuando el campo pierde el foco -- o desenfoques (véase el validateOnDelay de la propiedad).Con el fin de desencadenar la validación de campo después de emitir el tipo de Selenio comando para introducir texto dentro de un campo, que tiene que hacer cualquiera de los siguientes:

  • Activación Retardada De Validación

    ExtJS dispara la validación de temporizador de retardo cuando el campo recibe el evento keyup.Para activar el temporizador, basta con dar un maniquí evento keyup (no importa de qué tecla se utiliza como ExtJS ignora), seguida de una breve pausa más larga que la validationDelay:

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
  • Activación Inmediata De Validación

    Usted puede inyectar un desenfoque evento en el campo para activar inmediata de validación:

    Command: runScript
    Target: someComponent.nameTextField.fireEvent("blur")
    

La comprobación de los Resultados de la Validación

Tras la validación, se puede comprobar la presencia o ausencia de un campo de error:

Command: verifyElementNotPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Command: verifyElementPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Tenga en cuenta que la pantalla":ninguno de verificación" es necesario porque una vez que un campo de error que se muestra y, a continuación, se necesita ser ocultado, ExtJS simplemente ocultar campo de error en lugar de la totalidad de sacarla del árbol DOM.

Elemento específico de Consejos

Al hacer clic en un Ext.el formulario.Botón

  • Opción 1

    Comando:haga clic en Objetivo:css=botón:contains ("Guardar")

    Selecciona el botón de su título

  • Opción 2

    Comando:haga clic en Objetivo:css=#de guardar en las opciones de botón

    Selecciona el botón por su id

Al seleccionar un Valor de una Ext.el formulario.ComboBox

Command: runScript
Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

Primero, se establece el valor y, a continuación, de forma explícita desencadena el evento de selección en caso de que haya observadores.

Otros consejos

Este blog me ayudó mucho.Ha escrito bastante sobre el tema y parece que su todavía activo.El chico también parece apreciar un buen diseño.

Básicamente habla sobre el uso de envío de javascript para hacer consultas y el uso de la Ext.ComponentQuery.el método de consulta para recuperar cosas de la misma manera que en el ext de la aplicación internamente.De esa manera usted puede utilizar xtypes y itemIds y no tienen que preocuparse por tratar de analizar cualquiera de los locos auto-generados cosas.

He encontrado este artículo en particular, muy útil.

Podría publicar algo un poco más detallada de aquí pronto - aún tratando de conseguir mi cabeza alrededor de cómo hacerlo correctamente

He estado probando mi ExtJs aplicación web con selenio.Uno de los problema más grande fue la selección de un elemento de la cuadrícula con el fin de hacer algo con él.

Para ello, me escribió método auxiliar (en SeleniumExtJsUtils clase que es una colección de métodos útiles para facilitar la interacción con ExtJs):

/**
 * Javascript needed to execute in order to select row in the grid
 * 
 * @param gridId Grid id
 * @param rowIndex Index of the row to select
 * @return Javascript to select row
 */
public static String selectGridRow(String gridId, int rowIndex) {
    return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)";
}

y cuando yo lo necesitaba para seleccionar una fila, me acababa de llamar a:

selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) );

Para que esto funcione tengo que crear mi id en la red y no vamos a ExtJs generar su propio.

Para detectar que el elemento es visible que el uso de la cláusula:not(contains(@style, "display: none")

Es mejor usar esto:

visible_clause = "not(ancestor::*[contains(@style,'display: none')" +
    " or contains(@style, 'visibility: hidden') " + 
    " or contains(@class,'x-hide-display')])"

hidden_clause = "parent::*[contains(@style,'display: none')" + 
    " or contains(@style, 'visibility: hidden')" + 
    " or contains(@class,'x-hide-display')]"

Se puede proporcionar más información sobre los tipos de problemas que está teniendo con extjs pruebas?

Uno de Selenio extensión me parece útil es waitForCondition.Si tu problema no parece ser un problema con el Ajax de eventos, puede utilizar el waitForCondition a esperar los acontecimientos a suceder.

Ext JS páginas web, puede ser difícil de probar, debido a la complicada HTML que terminan generando como con Ext JS cuadrículas.

HTML5 Robot ofertas de hoteles con esta mediante el uso de una serie de mejores prácticas para el cómo de forma fiable y de búsqueda de interactuar con los componentes basados en atributos y condiciones que no son dinámicas.A continuación, proporciona accesos directos para hacer esto con todo el código HTML, Ext JS, y Sencha Touch componentes que usted necesita para interactuar con el.Viene en 2 versiones:

  1. Java - Familiares de Selenio y JUnit basado en la API que se ha construido en la web de soporte de controlador para todos los navegadores modernos.
  2. Gwen - Un estilo humano de idioma de forma rápida y sencilla la creación y mantenimiento de navegador de pruebas, que viene con su propio entorno de desarrollo integrado.Todo lo cual se basa en la API de Java.

Por ejemplo, si usted quiere encontrar el Ext JS cuadrícula de la fila que contiene el texto "Foo", se podría hacer lo siguiente en Java:

findExtJsGridRow("Foo");

...y podría hacer lo siguiente en Gwen:

extjsgridrow by text "Foo"

Hay un montón de documentación para ambos Java y Gwen de cómo trabajar con Ext JS componentes específicos.La documentación que se detalla también el HTML resultante de todos estos componentes Ext JS, que usted también puede encontrar útil.

Consejos útiles para la captura de la cuadrícula a través de la Identificación de la cuadrícula en la página:Creo que se puede extender más útil la función de esta API.

   sub get_grid_row {
        my ($browser, $grid, $row)  = @_;


        my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" .
            "var grid = doc.getElementById('$grid');\n" .
            "var table = grid.getElementsByTagName('table');\n" .
            "var result = '';\n" .
            "var row = 0;\n" . 
            "for (var i = 0; i < table.length; i++) {\n" .
            "   if (table[i].className == 'x-grid3-row-table') {\n".
            "       row++;\n" . 
            "       if (row == $row) {\n" .
            "           var cols_len = table[i].rows[0].cells.length;\n" .
            "           for (var j = 0; j < cols_len; j++) {\n" .
            "               var cell = table[i].rows[0].cells[j];\n" .
            "               if (result.length == 0) {\n" .
            "                   result = getText(cell);\n" .
            "               } else { \n" .
            "                   result += '|' + getText(cell);\n" .
            "               }\n" .
            "           }\n" .
            "       }\n" .
            "   }\n" .
            "}\n" .
            "result;\n";

        my $result = $browser->get_eval($script);
        my @res = split('\|', $result);
        return @res;
    }

Más fáciles de la prueba a través de HTML personalizado de datos de atributos

A partir de la Sencha documentación:

Un itemId puede ser utilizado como una forma alternativa para obtener una referencia a un componente cuando no hay ningún objeto de referencia está disponible.En lugar de utilizar una identificación con Ext.getCmp, uso itemId con Ext.contenedor.Contenedor.getComponent que van a recuperar itemId o id.Desde itemId son un índice del contenedor interno MixedCollection, la itemId es de ámbito local en el contenedor -- para evitar posibles conflictos con Ext.ComponentManager que requiere un identificador único.

La invalidación de la Ext.AbstractComponent's onBoxReady método, me puse una custom atributo de datos (cuyo nombre proviene de mi costumbre testIdAttr la propiedad de cada componente) para el componente de la itemId valor, si es que existe.Agregar el Testing.overrides.AbstractComponent la clase a su application.js archivo de la requires de la matriz.

/**
 * Overrides the Ext.AbstracComponent's onBoxReady
 * method to add custom data attributes to the
 * component's dom structure.
 *
 * @author Brian Wendt
 */
Ext.define('Testing.overrides.AbstractComponent', {
  override: 'Ext.AbstractComponent',


  onBoxReady: function () {
    var me = this,
      el = me.getEl();


    if (el && el.dom && me.itemId) {
      el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId);
    }


    me.callOverridden(arguments);
  }
});

Este método proporciona a los desarrolladores una forma de reutilizar un identificador descriptivo dentro de su código y los identificadores disponibles cada vez que se procesa la página.No más búsqueda a través de la no-descriptivo, que se genera dinámicamente ids.

Estamos desarrollando un marco de pruebas que utiliza el selenio y problemas con extjs (ya que del lado del cliente de representación).Me parece útil para buscar un elemento cuando el DOM está listo.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
    def maxSeconds = DEFAULT_WAIT_SECONDS * 10
    for (count in 1..maxSeconds) {
        Thread.sleep(100)
        def ready = isDOMReady(driver);
        if (ready) {
            break;
        }
    }
}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

Para la interfaz de usuario compleja que no es formal HTML, xPath es siempre algo que usted puede contar, pero un poco complejo cuando se trata de diferentes interfaz de usuario de la aplicación utilizando ExtJs.

Usted puede utilizar Firebug y Firexpath como extensiones de firefox para probar un determinado elemento del xpath, y pase sencillo lleno de xpath como parámetro de selenio.

Por ejemplo, en el código java:

String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button"

selenium.click(fullXpath);

Cuando estaba probando ExtJS aplicación que utiliza WebDriver he utilizado la siguiente aproximación:Miré para el campo de texto de la etiqueta y consiguió @for atributo de la etiqueta.Por ejemplo, tenemos una etiqueta

<label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for">
Name Of Needed Label
<label/>

Y necesitamos a punto de WebDriver algunos datos de entrada: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)].

Así, se recogerá la identificación de @for atributo y uso posterior.Este es probablemente el caso más simple, pero se le da la forma de localizar el elemento.Es mucho más difícil cuando usted no tiene etiqueta pero entonces usted necesita para encontrar algún elemento y escriba su xpath buscando hermanos, descender/ascender elementos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top