Pregunta

Estoy tratando de poner a prueba la página de inicio de sesión en mi sitio usando el transportador.

En caso de iniciar sesión correctamente, el sitio muestra un mensaje de "tostada" que aparece durante 5 segundos, luego desaparece (el uso de $timeout).

Estoy usando la siguiente prueba:

  describe('[login]', ()->
    it('should show a toast with an error if the password is wrong', ()->

      username = element(select.model("user.username"))
      password = element(select.model("user.password"))
      loginButton = $('button[type=\'submit\']')
      toast = $('.toaster')

      # Verify that the toast isn't visible yet
      expect(toast.isDisplayed()).toBe(false)

      username.sendKeys("admin")
      password.sendKeys("wrongpassword")
      loginButton.click().then(()->
        # Verify that toast appears and contains an error
        toastMessage = $('.toast-message')
        expect(toast.isDisplayed()).toBe(true)
        expect(toastMessage.getText()).toBe("Invalid password")
      )
    )
  )

El correspondiente marcado (jade) es el siguiente:

.toaster(ng-show="messages.length")
  .toast-message(ng-repeat="message in messages") {{message.body}}

El problema es el toastMessage la prueba está fallando (no puede encontrar el elemento).Parece ser que se espera para el brindis a desaparecer y entonces ejecución de la prueba.

También he intentado poner el toastMessage prueba fuera de la then() de devolución de llamada (creo que esto es bastante redundante de todos modos), pero me da exactamente el mismo comportamiento.

Mi mejor conjetura es que el transportador se ve que hay un $timeout en ejecución, y espera a que termine antes de ejecutar la siguiente prueba (ref transportador de flujo de control).¿Cómo puedo conseguir alrededor de esto, y asegúrese de que se ejecuta la prueba durante el tiempo de espera?

Actualización:

Siguiendo la sugerencia de abajo, he usado browser.wait() a esperar para el brindis a ser visible, y luego trató de ejecutar la prueba cuando la promesa resuelto.No trabajo.

console.log "clicking button"
loginButton.click()

browser.wait((()-> toast.isDisplayed()),20000, "never visible").then(()->
  console.log "looking for message"
  toastMessage = $('.toaster')
  expect(toastMessage.getText()).toBe("Invalid password")
)

La consola.las declaraciones de registro déjame ver lo que está pasando.Esta es la serie de eventos, la [] son lo que vemos que sucede en el navegador.

clicking button
[toast appears]
[5 sec pass]
[toast disappears]
looking for message
[test fails]

Para mayor claridad sobre lo que está pasando con la tostadora:Tengo un servicio que básicamente contiene una matriz de mensajes.El brindis de la directiva es siempre en la página (plantilla es la de jade arriba), y los relojes de los mensajes en el brindis de servicio.Si hay un mensaje nuevo, se ejecuta el siguiente código:

scope.messages.push(newMessage)
# set a timeout to remove it afterwards.
$timeout(
()-> 
  scope.messages.splice(0,1) 
, 
  5000
)

Esto empuja el mensaje en los mensajes de la matriz en el ámbito de aplicación de 5 segundos, que es lo que hace el brindis aparecen (a través de ng-show="messages.length").

¿Por qué es transportador de espera para el brindis de la $timeout a punto de expirar antes de pasar a las pruebas?

¿Fue útil?

Solución 2

Resulta que este es conocido el comportamiento de transportador.Creo que debe ser un error, pero en el momento en que el tema está cerrado.

La solución es utilizar $interval en lugar de $timeout, marcando el tercer argumento a 1, de modo que solo se llama una vez.

Otros consejos

He hackeado todo esto utilizando el siguiente bloque de código.Tenía una barra de notificación de una 3 ª parte nodo paquete (ng-notificaciones-bar), que utiliza $tiempo de espera en lugar de $intervalo, pero es necesario esperar que el texto de error fue de un valor determinado.Me puse utilizó una breve sleep() para permitir la notificación de la barra de animación a aparecer, cambió ignoreSynchronization a true para que el Transportador no iba a esperar que el $tiempo de espera hasta el final, puso mis esperar(), y cambió el ignoreSynchronization a false para Transportador puede continuar la prueba dentro de regular AngularJS cadencia.Sé que el que duerme no son las ideales, pero son muy breves.

browser.sleep(500);
browser.ignoreSynchronization = true;
expect(page.notification.getText()).toContain('The card was declined.');
browser.sleep(500);
browser.ignoreSynchronization = false;
you should wait for your toast displayed then do other steps

browser.wait(function() {
    return $('.toaster').isDisplayed();
}, 20000);

En caso de que alguien todavía está interesado, este código me funciona sin hacks para $timeout o $intervalo o pan Tostado.La idea es utilizar las promesas de haga clic en() y wait() para activar y desactivar la sincronización.Haga clic en cualquier cosa para llegar a la página con el brindis mensaje, e inmediatamente desactivar la sincronización, espere a que la notificación de mensajes, cerrar y, a continuación, gire de nuevo la sincronización (en el INTERIOR de la promesa).

element(by.id('createFoo')).click().then(function () {
    browser.wait(EC.stalenessOf(element(by.id('createFoo'))), TIMEOUT);
    browser.ignoreSynchronization = true;
    browser.wait(EC.visibilityOf(element(by.id('toastClose'))), TIMEOUT).then(function () {
      element(by.id('toastClose')).click();
      browser.ignoreSynchronization = false;
   })
});

Espero que esto puede ayudar a que tiene algunos problemas con el transportador de ángulos, jazmín, angulares y ngToast.

Puedo crear un CommonPage para manejar las Tostadas en cada una de las páginas sin duplicar código.Por ejemplo:

var CommonPage = require('./pages/common-page');
var commonPage = new CommonPage();
decribe('Test toast', function(){
    it('should add new product', function () {
            browser.setLocation("/products/new").then(function () {

                element(by.model("product.name")).sendKeys("Some name");    
                var btnSave = element(by.css("div.head a.btn-save"));
                browser.wait(EC.elementToBeClickable(btnSave, 5000));
                btnSave.click().then(function () {

                    // this function use a callback to notify
                    // me when Toast appears
                    commonPage.successAlert(function (toast) {
                        expect(toast.isDisplayed()).toBe(true);
                    });

                });
            });
        })
});

Y este es mi CommonPage:

var _toastAlert = function (type, cb) {
    var toast = null;

    switch (type) {
        case "success":
            toast = $('ul.ng-toast__list div.alert-success');
            break;
        case "danger":
            toast = $('ul.ng-toast__list div.alert-danger');
            break;
    }

    if (!toast) {
        throw new Error("Unable to determine the correct toast's type");
    }

    browser.ignoreSynchronization = true;
    browser.sleep(500);
    browser.wait(EC.presenceOf(toast), 10000).then(function () {
        cb(toast);
        toast.click();
        browser.ignoreSynchronization = false;
    })


}

var CommonPage = function () {    
    this.successAlert = function (cb) {
        _toastAlert("success", cb);
    };
    this.dangerAlert = function(cb) {
        _toastAlert("danger", cb);
    }
}

module.exports = CommonPage;

-Chris Traynor's respuesta trabajado para mí, pero tengo una actualización.

ignoreSynchronization está ahora en desuso.Para aquellos que utilizan angular y transportador para probar esto, el siguiente funciona muy bien para mí.

$(locators.button).click();
await browser.waitForAngularEnabled(false);
const isDisplayed = await $(locators.notification).isPresent();
await browser.waitForAngularEnabled(true);
expect(isDisplayed).toEqual(true);

He simplificado este para que sea más fácil de ver, me gustaría que normalmente esta en el interior de un método para hacer que los localizadores dinámico.

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