Protractor: Aufgabe (Kern): Bessere Fehlermeldung für clientseitige Weiterleitungen hinzufügen

Erstellt am 28. Okt. 2015  ·  49Kommentare  ·  Quelle: angular/protractor

Wenn der Test auf einen Link oder etwas klickt, das eine Umleitung außerhalb von browser.get oder browser.refresh , wird der Benutzer beim nächsten Aufruf von waitForAngular wahrscheinlich auf diese Fehlermeldung stoßen ( da wir nicht darauf gewartet haben, dass Angular geladen wird), was nicht sehr hilfreich ist.

Benutzer sollten darüber informiert werden, was falsch läuft und über mögliche Problemumgehungen (z. B. Verwenden von browser.get oder browser.refresh , um das Bootstrapping zu beheben).

debuggability

Hilfreichster Kommentar

@sjelin Würden Sie bitte etwas näher erläutern, wie dieses Problem

Mein Anwendungsfall: Ich habe einen Test, der Benutzername / Passwort eingibt und auf eine Anmeldeschaltfläche klickt, die bei erfolgreicher Anmeldung auf eine andere Seite umleitet.

Alle 49 Kommentare

@sjelin Würden Sie bitte etwas näher erläutern, wie dieses Problem

Mein Anwendungsfall: Ich habe einen Test, der Benutzername / Passwort eingibt und auf eine Anmeldeschaltfläche klickt, die bei erfolgreicher Anmeldung auf eine andere Seite umleitet.

Wenn beide Seiten eckige Seiten sind, sollten Sie nach dem Laden der neuen Seite nur ein browser.refresh hinzufügen, um das Problem zu beheben

Wir arbeiten an einer Funktion, um dies in Zukunft zu verbessern

Ich habe jetzt seit einer Woche mit diesem Problem zu kämpfen. browser.refresh() funktioniert nicht, wenn ich einen POST mache.

Das ist gut zu bedenken, danke. Im Moment könnten Sie das Problem wahrscheinlich abmildern, indem Sie Ihren Test einige hundert Millisekunden warten lassen, nachdem die clientseitige Umleitung erfolgt ist. Dadurch wird verhindert, dass Protractor die Fehlermeldung ausgibt, obwohl Protractor nicht ordnungsgemäß booten kann, sodass andere unerwartete Probleme auftreten können (insbesondere, wenn Sie Plugins oder Mock-Module verwenden).

Eigentlich verwende ich so etwas als Problemumgehung, wenn ich weiß, dass es eine Umleitung geben wird:

(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);

@assoevan , das ist perfekt! Ich würde erwarten, dass waitForAngular dies tut - warten Sie, bis Angular verfügbar ist.

Wenn der Winkelmesser startet, geht er immer zur baseUrl und dann zu meiner Testseite. Wird dies als die Weiterleitung angesehen, von der Sie sprechen?

Nicht ganz @patrickliechty , ich meine, wenn Sie auf einen Link klicken (wie <a href='google.com'> ) und der Browser auf google.cm geleitet wird

@juliemr mit @hankduan weg

@sjelin , ist dieses Problem noch in Winkelmesser 3.1.1.Ich kann das sehen

+1 für eine bessere Lösung. Ich bin heute darauf gestoßen, ohne zu wissen, wie ich es zuverlässig umgehen kann. Vielen Dank!

Das gleiche Problem haben !!! danke @tassoevan für eine zuverlässige Lösung

+1 für einen Fix.

Ich habe diesen Fehler erhalten, indem ich element (). GetText () außerhalb der Spezifikationen ausgeführt habe (ohne dass ein browser.get () aufgetreten ist) - habe versucht, eine Verknüpfung für die Ausgabe eines bestimmten div außerhalb der Spezifikationen zu erstellen. Verwandelte es in eine Funktion und alles war gut.

Ich erhalte diesen Fehler, wenn ich gegen \ node_modules \ protractor \ example \ conf.js laufe. Sicherlich sollte das Beispiel conf.js immer funktionieren, unabhängig davon?

Gibt es eine Problemumgehung für Benutzer, die Winkelmesser ohne Winkel verwenden?

@Overdrivr Sie können browser.ignoreSynchronization = true festlegen. Winkelmesser zu sagen, nicht auf Angular zu warten.

browser.ignoreSynchronization = true funktioniert bei mir, wenn ich zwischen Windows wechsle.

OK, aber dann müssen Sie browser.ignoreSynchronization = false setzen.

Ich erhalte diesen Fehler und er enthält einen Link zu diesem Github-Problem.

Folgendes habe ich:

/**
 * 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);
    });
  });

//Ordnen
Der Test beginnt mit einer Winkel-App.
Startet einen Mapreduce-Job über eine URL, nicht über eine eckige App
kehrt zur Winkel-App zurück, um die Anzahl der Zeilen aufzuzeichnen

//Handlung
löscht 1 Datensatz
überprüft, ob das Löschen erfolgt

// Assert
Startet einen Mapreduce-Job über eine URL, nicht über eine eckige App
_fails_ das zweite Mal, bevor wir bestätigen können, dass der Mapreduce-Job die Daten neu erstellt (gleiche Zeilenanzahl vor dem Löschen).

Hier sind die relevanten Protokolldetails:

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:

Es schlägt immer beim zweiten Mal durch waitForMapReduceJobToComplete im 'wait'-Protokoll fehl.

Die Lösung ist hier "dokumentiert": https://github.com/angular/protractor/issues/2787

Innerhalb des browser.wait müssen Sie ignoreSynchronization zurücksetzen. Ich habe dies für alle browser.waits getan, bei denen ignoreSynchronization bereits wahr war.

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

Mein Test besteht jetzt.

Haben Sie eine Lösung für das Warten mit browser.ExpectedConditions?

Wie wird der Patch aussehen, wenn Sie diesen Code verwenden?

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

Vielen Dank!

@azachar dieser scheint zu funktionieren:

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

Ich weiß nicht, was los ist, aus irgendeinem Grund ist ignoreSynchronization in diesem Block immer noch falsch, bis Sie es zwangsweise einstellen. Ich folgte in # 2787 damit.

UPDATE: Es gibt Rennbedingungen, wenn Sie ignoreSynchronization setzen / zurücksetzen, setzen Sie dies besser auf den Kontrollfluss. Siehe # 4061.

Ich bekomme das ohne ignoreSynchronization mit so etwas ....

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 Laden von browser.wait scheint ein wenig zu helfen, schlägt aber immer noch fehl.

@tassoevan Hallo

(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 eckig (2) - Stellen Sie sicher, dass Ihre Spezifikation mit browser.get ('/') beginnt.

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');
});

Nachdem ich mir @tassoevans großartige Laufen gebracht hatte , dachte ich, ich würde meine TypeScript- und Angular2-Lösung teilen. Ich habe diese Funktion in meine abstrakte Seitenklasse eingefügt, aber ich denke, sie passt möglicherweise besser auf das Objekt 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);
}

Hier ist ein Beispiel, wie ich es in einem Test verwendet habe:

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

Meine Anmeldeseite ist eine Nicht-Angular-JS-Seite. Sobald ich mich bei der Anwendung anmelde, wird die Angular js-Seite erstellt. Also habe ich die Spezifikationsdatei wie folgt erstellt:

beschreiben ('Anmelden bei Anwendung', function () {
var userID = element (by.name ('Benutzername'));
var password = element (by.name ('password'));
var logInButton = element (by.id ('Submit'));

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

}}

beforeEach (function () {
browser.ignoreSynchronisation = true;
browser.get (''); // die zur Anmeldeseite der Anwendung navigiert
});

it ('Anmeldung bei Anwendung haben', function () {
loginToApplication ('77777', 'test')
browser.ignoreSynchronisation = false
erwarten (browser.getTitle ()). toEqual ('Software');
});
});

Unter der folgenden Fehlermeldung:
Fehlgeschlagen: Fehler beim Warten auf die Synchronisierung des Winkelmessers mit der Seite: "window.an
gular ist undefiniert. Dies kann entweder daran liegen, dass es sich um eine nicht eckige Seite handelt, oder
weil Ihr Test eine clientseitige Navigation beinhaltet, die Prot stören kann
Ractor's Bootstrapping. Siehe http://git.io/v4gXM für Details "

Hallo, werfen Sie einen Blick auf http://www.protractortest.org/#/timeouts # How-to-Disable-Warten-auf-Winkel
Insbesondere gibt es verschiedene Möglichkeiten, sich über eine Seite ohne Angular anzumelden. Versuchen Sie jedoch zunächst diese Show in den Dokumenten.
Freundliche Grüße
Kamel

Mir ist klar, dass es bereits eine lange Diskussion ist, aber das könnte jemandem helfen.

Eine solche Fehlermeldung kann auch auftreten, wenn die Seite aufgrund eines nicht behandelten Fehlers in einer Angular-Komponente unerwartet neu geladen wird. Die Tatsache, dass die Browserkonsole möglicherweise nicht beibehalten wird , und

Vielleicht könnte also etwas unternommen werden, was die Fehlermeldung betrifft, da der oben genannte Fall nicht per se 'clientseitige Navigation' ist :)

Hallo @ArnaudPel

Tnx für Ihre zusätzlichen Informationen. Vielleicht können Sie eine PR hinzufügen, um dies in den Dokumenten zu erklären, wenn Sie möchten?

Ich erhalte derzeit diesen Fehler, wenn ich zu unserer Anmeldeseite gehe (ein häufiges Problem):

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"

Den ignoreSync Trick zu machen scheint nicht zu helfen:

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

Der Link landet hier in diesem Thread, aber was als nächstes zu tun ist, ist nicht genau klar.

Getestet mit Winkelmesser-Versionen: 5.2.1, 5.1.1, 5.1.0, 5.0.0

@benjaminapetersen - Sie können versuchen, waitForAngularEnabled anstelle von ignoreSynchronization . Ich schaue auf die API-Referenzseite für Protractor v5.1.2 und sie enthält nicht mehr ignoreSynchronization , aber im CHANGELOG sehe ich nicht, wann, wenn überhaupt, diese Eigenschaft offiziell veraltet war ...

Ich habe waitForAngularEnabled ausprobiert, aber ich erhalte immer noch den gleichen Fehler wie @benjaminapetersen . Hier ist meine aktuelle Konfiguration:

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 danke! Obwohl es so aussieht, als wäre waitForAngularEnabled ebenfalls veraltet ....

@benjaminapetersen Dieses veraltete Dokument-Tag befindet sich in der Eigenschaft ignoreSynchronization , nicht in der Eigenschaft waitForAngularEnabled

waitForAngularEnabled funktioniert auch bei mir nicht. Es hat mit IgnoreSynchronization funktioniert, bevor ein Upgrade auf Protractor 5 durchgeführt wurde. Ich muss in einen nicht-Angular-Iframe wechseln und kann dies jetzt nicht. Bitte beraten. Vielen Dank

@ seel93 Versuchen Sie, rootElement: 'app' kommentieren, oder ersetzen Sie es durch rootElement: '*[ng-app]' .
Ich habe gerade die neueste Version von Winkelmesser installiert und ein paar Spezifikationen für eine Angular 1.6.1-App geschrieben und scheint bisher in Ordnung zu sein. Diese Fehlermeldung ist aufgetreten, als ich versucht habe, mich in meiner App anzumelden, aber ich verwende jetzt diesen Ansatz:

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);
}

Hinweis: Auf dem HTML-Tag ist ng-app festgelegt

rootElement: '*[ng-app]' ? funktioniert, um die Seite nur nach einem beliebigen Knoten zu durchsuchen? Ich habe das noch nie gesehen.

Ich habe gerade mein Problem gelöst. 🥇 Grundursache: Nebeneffekt der Entwicklerkonsole

Ich hatte dieses Problem und die Lösung für mich bestand darin, in meinem package.json zu Winkelmesser "^ 5.3.2" zu wechseln

Ich habe eine reguläre Anmeldeseite und leite dann zur eckigen Seite weiter.

Ich weiß also nicht genau, wie oder warum es funktioniert, weil ich für eckiges und eckiges e2e wirklich neu bin, aber ich habe es zum Laufen gebracht, als ich das browser.waitForAngularEnabled(false); zweimal verwendet habe.

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);
}

Ich hoffe es hilft.

Diese letzte Lösung funktioniert fast für mich, es sei denn, ich habe nach bestandenem Test einen Fehler erhalten:
Fehler: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:4444 Von: Aufgabe: WebDriver.getCurrentUrl ()

Ich habe diesen Fehler erhalten, indem ich element (). GetText () außerhalb der Spezifikationen ausgeführt habe (ohne dass ein browser.get () aufgetreten ist) - habe versucht, eine Verknüpfung für die Ausgabe eines bestimmten div außerhalb der Spezifikationen zu erstellen. Verwandelte es in eine Funktion und alles war gut.

Es funktioniert für alles, Sie können nicht mehr als ein 'element (). Anyfunction ()' außerhalb eines 'it' verwenden.
Fand es auf die harte Tour heraus ...

Beim Wechsel von einer Webseite zu einer anderen in Winkelmesser wurde ein Fehler angezeigt:

Fehlgeschlagen: Fehler beim Warten auf die Synchronisierung des Winkelmessers mit der Seite: "Sowohl die Winkel-JS-Testbarkeit als auch die Winkel-Testbarkeit sind nicht definiert. Dies kann entweder daran liegen, dass es sich um eine nicht eckige Seite handelt oder dass Ihr Test eine clientseitige Navigation umfasst, die die Winkelmesser stören kann Bootstrapping. Weitere Informationen finden Sie unter http://git.io/v4gXM. "

Der Code lautet:
var url = browser.params.login.Url;
browser.get (url + '/ #! / app / manage-users');

Ich bekam plötzlich diesen Fehler, den mein CT aufbaut. Ich habe festgestellt, dass dieser Fehler nur bei Firefox Headless auftritt und unter Chrome Headless unter Linux einwandfrei funktioniert. Ich habe ein Upgrade von Firefox v69 auf die neueste Version (derzeit Version 72.0.2) durchgeführt, mit der dieses Problem behoben wurde.

browser.ignoreSynchronization ist veraltet und sollte nicht verwendet werden. Wie aus dem ursprünglichen Beitrag hervorgeht, scheint die Verwendung von browser.get das Problem zu lösen.

Wenn Sie es in einer Weise nutzen möchten , dass Sie deaktivieren und aktivieren waitForAngularEnabled nach Belieben , müssen Sie verwenden browser.get nach der Einstellung waitForAngularEnabled(true) . Zum Beispiel:

// 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 blockiert, bis die Angular-Seite geladen ist.

Ich treffe gerade diesen Fehler:

_Ausnahme ist aufgetreten: Fehler: Fehler beim Warten auf die Synchronisierung des Winkelmessers mit der Seite: "Sowohl die Winkel-JS-Testbarkeit als auch die Winkel-Testbarkeit sind undefiniert. Dies kann entweder daran liegen, dass es sich um eine nicht eckige Seite handelt oder dass Ihr Test eine clientseitige Navigation umfasst kann das Bootstrapping von Protractor stören. Weitere Informationen finden Sie unter http://git.io/v4gXM "_

Aber nur, wenn Sie versuchen, entweder über den VS Code-Debugger oder den Chrome Inspector-Debug zu debuggen (befolgen Sie die Anweisungen hier für beide Fälle https://www.protractortest.org/#/debugging).

Hier ist meine launch.json Konfiguration in 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"
            ]
        }
    ]
}

Vielleicht habe ich etwas falsch eingestellt. Jede Hilfe wird geschätzt, es ist wahnsinnig schwierig, diese zu schreiben, ohne sie richtig debuggen zu können.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen