Protractor: corvée (core): ajouter un meilleur message d'erreur pour les redirections côté client

Créé le 28 oct. 2015  ·  49Commentaires  ·  Source: angular/protractor

Si le test clique sur un lien ou quelque chose qui provoque une redirection en dehors de browser.get ou browser.refresh , la prochaine fois que waitForAngular sera appelé, l'utilisateur rencontrera probablement ce message d'erreur ( car nous n'avons pas attendu le chargement d'Angular), ce qui n'est pas très utile.

Les utilisateurs doivent être informés de ce qui ne va pas et des solutions de contournement potentielles (par exemple, en utilisant browser.get ou browser.refresh pour corriger le bootstrap).

debuggability

Commentaire le plus utile

@sjelin pourriez-vous expliquer un peu plus ce qui peut être fait pour atténuer ce problème?

Mon cas d'utilisation: j'ai un test qui saisit le nom d'utilisateur / mot de passe et appuie sur un bouton de connexion, qui redirige vers une autre page en cas de connexion réussie.

Tous les 49 commentaires

@sjelin pourriez-vous expliquer un peu plus ce qui peut être fait pour atténuer ce problème?

Mon cas d'utilisation: j'ai un test qui saisit le nom d'utilisateur / mot de passe et appuie sur un bouton de connexion, qui redirige vers une autre page en cas de connexion réussie.

Si les deux pages sont des pages angulaires, vous devez simplement ajouter un browser.refresh après le chargement de la nouvelle page pour résoudre le problème

Nous travaillons sur une fonctionnalité pour améliorer cela à l'avenir

Je me débat avec ce problème depuis une semaine maintenant. browser.refresh() ne fonctionne pas si je fais un POST.

C'est bon à garder à l'esprit, merci. Pour l'instant, vous pouvez probablement atténuer le problème en faisant simplement attendre votre test quelques centaines de millisecondes après la redirection côté client. Cela empêchera Protractor de lancer le message d'erreur, même si cela ne permettrait pas à Protractor de démarrer correctement, ce qui pourrait causer d'autres problèmes inattendus (en particulier si vous utilisez des plugins ou des modules simulés).

En fait, j'utilise quelque chose comme ça comme solution de contournement où je sais qu'il y aura une redirection:

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

@tassoevan , c'est parfait! C'est ce à quoi je m'attendrais à waitForAngular: attendre que angular soit disponible.

Lorsque le rapporteur démarre, il va toujours à baseUrl puis à ma page de test. Est-ce considéré comme la redirection dont vous parlez?

Pas tout à fait @patrickliechty , je veux dire lorsque vous cliquez sur un lien (comme <a href='google.com'> ) et qu'il dirige le navigateur vers google.cm

@juliemr avec @hankduan parti, y a-t-il encore quelqu'un qui travaille sur le correctif à plus long terme pour cela?

@sjelin , est-ce que ce problème existe toujours dans le rapporteur 3.1.1, je peux le voir

+1 pour une meilleure solution. Je suis entré dans ce problème aujourd'hui sans savoir comment le contourner de manière fiable. Merci!

Avoir le même problème !!! merci @tassoevan pour une solution fiable

+1 pour un correctif.

J'ai eu cette erreur en faisant element (). GetText () en dehors des spécifications (sans qu'un browser.get () ne se soit produit) - essayait de créer un raccourci pour la sortie d'un div particulier en dehors des spécifications. Je l'ai transformé en une fonction et tout allait bien.

J'obtiens cette erreur lors de l'exécution contre \ node_modules \ protractor \ example \ conf.js, l'exemple conf.js devrait sûrement toujours fonctionner indépendamment ??

Pour les personnes utilisant Protractor sans Angular, existe-t-il une solution de contournement?

@Overdrivr Vous pouvez définir browser.ignoreSynchronization = true; pour dire au rapporteur de ne pas attendre Angular.

browser.ignoreSynchronization = true fonctionne pour moi lorsque je change de fenêtre.

OK mais alors vous devez définir browser.ignoreSynchronization = false;

J'obtiens cette erreur et elle contient un lien vers ce problème github.

Voici ce que j'ai:

/**
 * Waits for MR job to complete.
 * <strong i="7">@param</strong> {string} url The GET URL to kick off the map reduce job.
 * <strong i="8">@return</strong> {!webdriver.promise.Promise}
 */
function waitForMapReduceJobToComplete(url) {
  browser.ignoreSynchronization = true;
  browser.get(url);
  $('a[href*="/mapreduce"]').click();
  browser.wait(()=> {
    console.log('wait');
    return $('#auto-refresh').isPresent();
  });
  browser.controlFlow().execute(function() {
    console.log('after wait, before click');
  });
  browser.wait(()=> {
    console.log('isDisplayed');
    return $('#auto-refresh').isDisplayed();
  });
  $('#auto-refresh').click();
  browser.controlFlow().execute(function() {
    console.log('after click');
  });

  browser.wait(() => {
    return $('.status-box').isPresent().then((isPresent)=> {
      if(isPresent) {
        return hasClass($('.status-box'), 'status-done')
            .then((containsClass) => {
              if(!containsClass) {
                return browser.refresh().then(() => false);
              }
              return true;
            });
      }
      return browser.sleep(constants.BROWSER_WAIT_MS)
          .then(() => false);
    })
  });

  return browser.controlFlow().execute(function() {
    browser.ignoreSynchronization = false;
  });
}
  fit('mapreduce job is idempotent', function() {
    var subBuildingUrl = '/xyz/#all';
    var mapReduceJob = '/import/xyz/';
    helpers.waitForMapReduceJobToComplete(mapReduceJob);

    browser.get(subBuildingUrl);
    var tableView = new TableView();
    var originalCount = 0;
    tableView.count().then((cnt)=>{
      originalCount = cnt;
    });

    tableView.deleteRowNumber(1);
    browser.sleep(5000);
    browser.controlFlow().execute(function() {
      expect(tableView.count()).toBeLessThan(originalCount);
    });

    helpers.waitForMapReduceJobToComplete(mapReduceJob);
    browser.get(subBuildingUrl);
    browser.controlFlow().execute(function() {
      tableView = new TableView();
      expect(tableView.count()).toEqual(originalCount);
    });
  });

//Organiser
Le test démarre sur une application angulaire.
lance une tâche mapreduce sur une URL et non une application angulaire
retourne à l'application angulaire pour enregistrer le nombre de lignes

//Acte
supprime 1 enregistrement
vérifie que la suppression a lieu

// Affirmer
lance une tâche mapreduce sur une URL et non une application angulaire
_fails_ la deuxième fois avant que nous puissions confirmer que le travail mapreduce recrée les données (même nombre de lignes avant la suppression).

Voici les détails du journal pertinents:

wait
after wait, before click
isDisplayed
isDisplayed
after click
[17:48:09] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:24] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:40] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:55] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
wait
F

Failures:
  Message:
    Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"
  Stack:

Il échoue toujours la deuxième fois via waitForMapReduceJobToComplete sur le journal «d'attente».

La solution est "documentée" ici: https://github.com/angular/protractor/issues/2787

Dans le browser.wait, vous devez réinitialiser ignoreSynchronization. J'ai fait cela pour tous les browser.waits où ignoreSynchronization était déjà vrai.

  browser.wait(()=> {
    browser.ignoreSynchronization = true;
    return $('#auto-refresh').isPresent();
  });

Mon test passe maintenant.

Avez-vous une solution pour attendre en utilisant le navigateur.ExpectedConditions?

À quoi ressemblera le patch si vous utiliserez ce code?

browser.wait(EC.visibilityOf(element), timeout, message);?

Merci!

@azachar celui-ci semble fonctionner:

browser.wait(() => {
  browser.ignoreSynchronization = true;
  return EC.visibilityOf(element);
}, timeout, message);

Je ne sais pas ce qui se passe, pour une raison quelconque dans ce bloc ignoreSynchronization est toujours faux jusqu'à ce que vous le définissiez de force. J'ai suivi dans # 2787 avec ceci.

MISE À JOUR: Il y a des conditions de concurrence si vous définissez / réinitialisez ignoreSynchronization , mieux vaut mettre cela sur le flux de contrôle. Voir # 4061.

J'obtiens ça sans ignoreSynchronization avec quelque chose comme ça ....

afterAll(function(){
    adminPage.header.logout();
    // FIXME: WTF why isn't even this working 100% of the time
    setTimeout(function(){
      expect(loginPage.isVisible()).toBeTruthy();
    }, 1000 )
  })

loginPage semble prendre une seconde à charger et ce setTimeout n'aide pas. browser.wait semble aider un peu mais échoue toujours.

@tassoevan salut mec, pourriez-vous me dire comment configurer ce browser.wait () comme votre description et où le configurer

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

in angular (2) - Assurez-vous que vos spécifications commencent avec / browser.get ('/');

import { browser, element, by } from 'protractor';

it('should display message saying app works', () => {
    browser.get('/');

    let title = element(by.id('title')).getText();
    expect<any>(title).toEqual('cool');
});

Après avoir examiné la bonne solution de contournement de browser .

/**
  Wait for the page to make it to the next URL before continuing.
  A supplement to browser.waitForAngular() because protractor will continue control
  flow before navigation starts.

  Inputs:
    necessaryUrlFragment: a portion of the url that signifies you have successfully navigated
    timeout: the number of ms to wait before throwing an error. Defaults to the browsers default
      page timeout.
 */
waitForRedirect(necessaryUrlFragment: string, timeout: number = browser.getPageTimeout) {
  // Before we tell the browser to wait, assume it has not navigated
  let hasRedirected = false;

  // Passing a function to browser.wait() tells protractor to call that function repeatedly.
  // This function returns the closure variable hasRedirected, which will be set to true once the
  // necessaryUrlFragment has been found in the url
  browser.wait(() => {
    browser.getCurrentUrl()
      // Check to see if necessaryUrlFragment is in the current url
      .then(url => url.includes(necessaryUrlFragment))
      // Update our navigation status
      .then(hasNavigated => {
        hasRedirected = hasNavigated;
      });

    // Return our navigation status every time protractor asks for it - even if navigation is
    // not complete
    return hasRedirected;
  }, timeout);
}

Voici un exemple de la façon dont je l'ai utilisé dans un test:

it('Should be able load the preferences page', () => {
  page.navigateToMarketing();
  page.clickButton('Manage Preferences');
  page.waitForRedirect('preferences/preferences');
  expect(page.getPageTitle()).toBe('MY PREFERENCES');
});

Ma page de connexion est une page js non angulaire. Une fois que je me suis connecté à l'application, la page Angular js est créée. J'ai donc créé le fichier de spécifications comme indiqué ci-dessous:

describe ('Connexion à l'application', function () {
var userID = element (by.name ('username'));
var mot de passe = élément (par.nom ('mot de passe'));
var logInButton = élément (by.id ('Soumettre'));

function loginToApplication (stringSSOID, stringPassword) {
userID.sendKeys (stringSSOID);
password.sendKeys (stringPassword);
logInButton.click ();

}

beforeEach (fonction () {
browser.ignoreSynchronisation = true;
browser.get (''); // qui naviguera vers la page de connexion de l'application
});

it ('avoir la connexion à l'application', function () {
loginToApplication ('77777', 'test')
browser.ignoreSynchronisation = false
expect (browser.getTitle ()). toEqual ('Logiciel');
});
});

Obtenir ci-dessous le message d'erreur:
Échec: erreur lors de l'attente de la synchronisation de Protractor avec la page: "window.an
gular n'est pas défini. Cela peut être dû au fait qu'il s'agit d'une page non angulaire ou
car votre test implique une navigation côté client, ce qui peut interférer avec Prot
bootstrap de ractor. Voir http://git.io/v4gXM pour plus de détails "

Bonjour, jetez un œil à http://www.protractortest.org/#/timeouts # how-to-disable-wait-for-angular
En général, il existe deux façons de se connecter à l'aide d'une page non angulaire, mais essayez d'abord celle-ci dans la documentation.
Meilleures salutations
chameau

Je sais que c'est déjà une longue discussion, mais cela pourrait aider quelqu'un.

Un tel message d'erreur peut également se produire lorsque la page se recharge de manière inattendue en raison d'une erreur non gérée se produisant dans un composant angulaire. Le fait que la console du navigateur ne soit pas persistante , ainsi que la rapidité d'exécution des tests, ne m'a pas permis de comprendre ce qui se passait.

Alors peut-être que quelque chose pourrait être fait en ce qui concerne le message d'erreur, car le cas susmentionné n'est pas une `` navigation côté client '' en soi :)

Salut @ArnaudPel

Tnx pour vos informations supplémentaires. Peut-être pouvez-vous ajouter un PR pour expliquer cela dans la documentation si vous le souhaitez?

J'obtiens actuellement cette erreur en faisant le voyage sur notre page de connexion (un problème courant):

Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"

Faire l'astuce ignoreSync ne semble pas aider:

browser.ignoreSynchronization = true;
// do work here with browser.driver 
browser.ignoreSynchronization = false;

Le lien arrive ici à ce fil, mais ce qu'il faut faire ensuite n'est pas tout à fait clair.

Testé avec les versions de Protractor: 5.2.1, 5.1.1, 5.1.0, 5.0.0

@benjaminapetersen - Vous pouvez essayer d'utiliser waitForAngularEnabled au lieu de ignoreSynchronization . Je regarde la page de référence de l'API pour Protractor v5.1.2 et elle n'inclut plus ignoreSynchronization , mais en regardant à travers le CHANGELOG, je ne vois pas quand, si jamais, cette propriété a été officiellement obsolète ...

J'ai essayé waitForAngularEnabled mais j'obtiens toujours la même erreur que @benjaminapetersen obtient. Voici ma configuration actuelle:

exports.config = {
    rootElement: 'app',
    baseUrl: 'http://localhost:1384/#/',
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['./tests/e2e/*.js'],
    multiCapabilities: [{
      'browserName': 'firefox',
      //'browserName': 'chrome',
    }, 
  ],
  jasmineNodeOpts: {
    showColors: true
  },
}

//example test: 

describe('Overall navigation', function () {
  it('test link', function () {
     browser.get('http://localhost:1384/#/registrerprodukt');
  });
});

@thompsnm merci! Bien qu'il semble que waitForAngularEnabled soit également obsolète ...

@benjaminapetersen cette balise doc obsolète se trouve sur la propriété ignoreSynchronization , et non sur waitForAngularEnabled

waitForAngularEnabled ne fonctionne pas non plus pour moi. Cela fonctionnait avec IgnoreSynchronization avant de passer à Protractor 5. Je dois passer en iframe non angulaire, et maintenant je ne peux pas. S'il vous plaît donnez votre avis. Merci

@ seel93 Essayez de commenter rootElement: 'app' , ou essayez de le remplacer par rootElement: '*[ng-app]' .
Je viens d'installer la dernière version de rapporteur et j'ai écrit quelques spécifications pour une application Angular 1.6.1 et semble fonctionner correctement jusqu'à présent. J'ai rencontré ce message d'erreur lorsque j'essayais de me connecter à mon application, mais j'utilise maintenant cette approche:

onPrepare: function () {
    browser.driver.manage().timeouts().setScriptTimeout(60000);

    browser.driver.get('http://app.local.dev'+ '/login');
    browser.driver.findElement(by.id('user_login')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('user_pass')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('submit')).click();

    // Login takes some time, so wait until it's done.
    return browser.driver.wait(function() {
        return browser.driver.getCurrentUrl().then(function(url) {
            return /students\/agenda/.test(url);
        });
    }, 30000);
}

Remarque: j'ai ng-app défini sur la balise html

rootElement: '*[ng-app]' ? fonctionne pour rechercher simplement la page pour n'importe quel nœud? Je n'ai jamais vu ça avant.

Je viens de résoudre mon problème. 🥇 Cause fondamentale

J'avais ce problème et le correctif pour moi a finalement été de passer au rapporteur "^ 5.3.2" dans mon package.json

J'ai une page de connexion régulière, puis je redirige vers la page angulaire.

Donc, je ne sais pas exactement comment ou pourquoi cela fonctionne, car je suis vraiment nouveau dans e2e angulaire et angulaire, mais je l'ai fait fonctionner une fois que j'ai utilisé le browser.waitForAngularEnabled(false); deux fois.

logIn() {
    const email = 'test';
    const password = 'test';

    browser.waitForAngularEnabled(false);
    browser.get('/login');

    element(by.id('username')).sendKeys(email);
    element(by.id('password')).sendKeys(password);
    element(by.css('[type="submit"]')).click();

    return browser.wait(function() {
        browser.waitForAngularEnabled(false);
        return browser.getCurrentUrl().then(function(url) {
            browser.waitForAngularEnabled(true);
            return /dashboard/.test(url);
        });
    }, 5000);
}

J'espère que cela aide.

Cette dernière solution fonctionne presque pour moi, sauf si j'ai une erreur après la réussite du test:
Erreur: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:4444 De: Tâche: WebDriver.getCurrentUrl ()

J'ai eu cette erreur en faisant element (). GetText () en dehors des spécifications (sans qu'un browser.get () ne se soit produit) - essayait de créer un raccourci pour la sortie d'un div particulier en dehors des spécifications. Je l'ai transformé en une fonction et tout allait bien.

Cela fonctionne pour tout, vous ne pouvez pas utiliser plus d'un 'element (). Anyfunction ()' en dehors d'un 'it'.
Je l'ai découvert à la dure ...

Erreur lors du passage d'une page Web à une autre dans Protractor:

Échec: erreur lors de l'attente de la synchronisation de Protractor avec la page: "la testabilité angularJS et la testabilité angulaire ne sont pas définies. Cela peut être soit parce qu'il s'agit d'une page non angulaire, soit parce que votre test implique une navigation côté client, ce qui peut interférer avec le rapporteur. bootstrapping. Voir http://git.io/v4gXM pour plus de détails "

le code est:
var url = browser.params.login.Url;
browser.get (url + '/ #! / app / manage-users');

J'ai commencé à recevoir cette erreur tout à coup mon CT construit. J'ai remarqué que cette erreur ne se produit qu'avec Firefox headless et fonctionnait bien avec Chrome headless sous Linux. J'ai mis à niveau Firefox v69 vers la dernière version (v72.0.2 pour le moment) qui a résolu ce problème.

browser.ignoreSynchronization est obsolète et ne doit pas être utilisé. Comme indiqué dans l'article original, l'utilisation de browser.get semble résoudre le problème.

Si vous souhaitez l'utiliser de manière à pouvoir désactiver et activer waitForAngularEnabled à volonté, vous devez utiliser browser.get après avoir défini waitForAngularEnabled(true) . Par exemple:

// do things on your Angular application

waitForAngularEnabled(false)

// do things on non-angular page

waitForAngularEnabled(true)
browser.get('/home') // this is a page from your Angular application

browser.get bloque jusqu'à ce que la page Angular soit chargée.

Je rencontre actuellement cette erreur:

_Exception s'est produite: Erreur: Erreur lors de l'attente de la synchronisation de Protractor avec la page: "la testabilité angularJS et la testabilité angulaire ne sont pas définies. Cela peut être soit parce qu'il s'agit d'une page non angulaire, soit parce que votre test implique une navigation côté client, ce qui peut interférer avec l'amorçage de Protractor. Voir http://git.io/v4gXM pour plus de détails "_

Mais seulement lorsque vous essayez de déboguer via le débogueur VS Code ou le débogage de l'inspecteur de chrome (suivez les instructions ici pour les deux cas https://www.protractortest.org/#/debugging).

Voici ma configuration de launch.json dans VSCode.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "E2E Test",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}\\node_modules\\protractor\\bin\\protractor",
            "args": ["${workspaceFolder}\\e2e\\protractor.conf.js"],
            "outFiles": [
                "${workspaceFolder}/e2e/**/*.js",
                "${workspaceFolder}/src/**/*.js"
            ]
        }
    ]
}

C'est peut-être quelque chose que j'ai mal configuré. Toute aide est appréciée, essayer de les écrire sans pouvoir déboguer correctement est incroyablement difficile.

Cette page vous a été utile?
0 / 5 - 0 notes