Protractor: Winkelmesser und eckiger manueller Bootstrap

Erstellt am 30. Aug. 2013  ·  49Kommentare  ·  Quelle: angular/protractor

Ich habe ein Problem beim Ausführen von Protractor 0.8 und Probleme beim Ausführen von Protractor in unserer App, die manuell gebootet wird.

Hier sind einige Ausschnitte, die die relevanten Teile der Anwendung und Einrichtung enthüllen:
index.html:

 <script type="text/javascript" data-main="js/main" src="js/libraries/require.js"></script>

js/main.js:

require({
    shim: {
        .... snip ..
            }
           }, 
  ['require', ..... ], function(require) {
    return require(['bootstrap']);

bootstrap.js:

var appElm = $('html');
appElm.addClass('ng-app'); // this
angular.bootstrap(document, ['app']);

Das funktioniert in der Praxis und Angular wird korrekt gestartet. Wenn ich die HTML-Quelle ansehe, kann ich das ng-app-Attribut nicht sehen, das auf dem HTML-Element erscheint. Kann es sein, dass Protractor dies auch nicht tut?

Ich verwende die Winkelmesser-Beispielkonfiguration und habe die relevanten Werte an meine App angepasst:

specs: [
    '../src/test/javascript/protractorSpec/*_spec.js',
  ],
  baseUrl: 'http://localhost:8080/Viewer/',
  rootElement: 'html',

Beispieltest:

describe('List SMC Charts', function() {
        var ptor= protractor.getInstance();

        beforeEach(function() {
          ptor.get('#/smcChart');
        });

        it('list, no filter', function() {
          var selectOption = ptor.findElement(ptor.By.input("selectOption"));
        });
});

Wenn ich diesen Test durchführe, erscheinen zwei Fehler:

 1) List SMC Charts   list, no filter
   Message:
     Error: Angular could not be found on the page http://localhost:8080/Viewer/#/smcChart
   Stacktrace:
     Error: Angular could not be found on the page http://localhost:8080/Viewer/#/smcChart
    at /usr/local/lib/node_modules/protractor/lib/protractor.js:392:15

und

2) List SMC Charts list, no filter
   Message:
     TypeError: Cannot call method 'input' of undefined
   Stacktrace:
     TypeError: Cannot call method 'input' of undefined
    at null.<anonymous> (/Users/........//Viewer/src/test/javascript/protractorSpec/some_spec.js:9:55)

Der erste Fehler scheint der wichtigste zu sein, aber der letzte Fehler ist auch ziemlich interessant. Es scheint mir, dass die Zeile: ptor.By.input nicht funktioniert.

Irgendwelche Ideen?

untriaged discussion

Hilfreichster Kommentar

@sjelin Was ist der dokumentierte Weg, um manuelles Bootstrapping zu unterstützen? Ich kann die relevanten Informationen für Winkelmesser 5.0 nicht finden.

Alle 49 Kommentare

Ist der Angular-Code auf der Seite enthalten? Es sieht so aus, als ob Sie Shim, Bootstrap und andere benötigen, aber angular.min.js wird nicht angezeigt.

'app': {
            deps: ['libraries/angular', 'libraries/angular-resource', 'libraries/angular-strap']
        },

Das obige Snippet befindet sich innerhalb des shim{}-Elements, ich habe es aus den Snippets weggelassen, weil es mir nicht sehr relevant erschien. Aber so wird angle.js geladen.

Hallo,

Ja, Protractor erwartet derzeit eine ng-App, sodass manuell gebootete Websites Probleme haben werden. In der Hoffnung, bald eine Problemumgehung für diese Dokumentation zu erhalten.

Ok danke für das Update. Wenn Sie eine Problemumgehung gefunden haben, können Sie sie in dieser Ausgabe posten?

Entschuldigen Sie die langsame Antwort - Sie sollten in der Lage sein, das Problem zu beheben, indem Sie es tun

describe('List SMC Charts', function() {
        var ptor= protractor.getInstance();

        beforeEach(function() {
          ptor.driver.get('#/smcChart'); // Just use the plain old webdriver here, it won't complain if Angular isn't loaded yet.
        });

        it('list, no filter', function() {
          var selectOption = ptor.findElement(ptor.By.input("selectOption"));
        });
});

Hast du irgendwo die Ptor-Variable angelegt? zB var ptor = protractor.getInstance() ?

Gibt es hierzu Neuigkeiten? Ihre vorgeschlagene Lösung funktioniert bei mir nicht ([email protected], [email protected])

Ich habe eine unangenehme Kombination aus einem nicht eckigen Anmeldebildschirm, gefolgt von einer requirejs, manuell gebootstrapped App:

describe('User levels', function() {
    var ptor, driver;

    var findByName = function (name) {
        return driver.findElement(protractor.By.name(name));
    };

    describe('Editors', function() {
        ptor = protractor.getInstance();
        driver = ptor.driver;
        it('Can log in', function() {
            driver.get('http://localhost:8000/');
            findByName('login').sendKeys('test_editor');
            findByName('pass').sendKeys('rubbish');
            driver.findElement(protractor.By.css('button[type="submit"]')).click();
        }, 20000);

        it('Shows the homepage', function() {
            var el = ptor.findElement(protractor.By.css('h1[field="pageTitle"]'));
            expect(el.getText()).toEqual('Welcome to Home');
        }, 30000);

    });
});

Und mein main.js :

require([
    'angular',
    'app'
], function (angular, app) {
    'use strict';
    var body = document.body, name = app.name;
    body.setAttribute('ng-app', name);
    body.setAttribute('id', 'ng-app');
    angular.bootstrap(body, [name]);
});

Der Anmeldeteil funktioniert und ich kann einen Blitz sehen, wie die geschützte Seite geladen wird, bevor Winkelmesserfehler mit UnknownError: javascript error: angular is not defined werden. Ich habe versucht, die Seite mit driver.get('...') und sogar ptor.get('...') neu zu laden, aber nichts funktioniert.

Alle Hinweise/Ratschläge/Korrekturen dankbar entgegengenommen.

@magnetised müssen Sie Ihrem Test mitteilen, dass er warten soll, bis die Anmeldung abgeschlossen ist, bevor Sie andere Tests ausprobieren. Ich denke, was passiert, ist, dass Sie versuchen, ptor.findElement zu verwenden, bevor Angular auf der Seite geladen wurde.

Ihre „Can log in“-Spezifikation sollte mit einer Wait-Anweisung enden, die eine Bedingung für Ihre App überprüft. Sehen Sie sich das Beispiel hier an – https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js

@juliemr Genial , das funktioniert perfekt.

Ich hatte verstanden, dass der Winkelmesser das "Warten, bis Winkel geladen wurde" übernehmen würde, aber ich denke, Sie können nicht alle Fälle abdecken.

Danke noch einmal.

Ich habe genau die gleiche Konstellation. @juliemr macht es dir etwas aus, deine Lösung zu teilen. Was ist Ihre Wartebedingung? Danke!

@jorgenfb Ich frage mich, ob du gemeint hast, dass dieser Kommentar an mich gerichtet ist?

Meine Lösung bestand nur darin, darauf zu warten, dass der eckige Router hochfährt und die URL von dem bloßen „/“, auf das Sie das Anmeldesystem umleitet, auf die Standardroute zu ändern – in unserem Fall „/#view“.

Ich habe daraus eine Funktion gemacht, die ich für alle Tests wiederverwenden kann:

var waitUntilLoaded = function() {
    ptor.wait(function() {
      return ptor.driver.getCurrentUrl().then(function(url) {
        return /view/.test(url);
      });
    });
};

Ich weiß nicht, ob dies für Sie funktioniert, es hängt von Ihrer Routing-Konfiguration ab.

@juliemr Danke, funktioniert wie ein Zauber :)

Ich habe ein ähnliches Problem (gefunden auf SO unter: http://stackoverflow.com/questions/19391813/protractor-fails-to-find-angular) mit Protractor, das Angular nicht findet, obwohl Angular sehr einfach geladen ist und ausgeführt wird. Ist die einfache Lösung (Testen ohne zu versuchen, Angular zu finden) der Weg, den wir gehen sollten? Es scheint den Zweck von Protractor zunichte zu machen, der speziell zum Testen von Angular-Apps entwickelt wurde.
Bearbeiten: Ich sollte auch beachten, dass die vorgeschlagene Lösung in diesem Problem für mich nicht funktioniert.

+1 für eine bessere manuelle Bootstrap-Dokumentation

ist das noch aktuell?

Ich weiß es ehrlich gesagt nicht, da ich es inzwischen aufgegeben habe und nicht wirklich die Zeit habe, zurückzugehen und zu sehen, ob sich etwas geändert hat. In Anbetracht der seitdem geänderten Version würde ich nicht argumentieren, wenn Sie dies schließen möchten. Es kann später immer wieder geöffnet werden.

Ich habe heute angefangen, den Winkelmesser zu verwenden, und unsere App verwendet require.js ... wenn es irgendwelche Updates in Bezug auf das Testen einer Anwendung gibt, die manuell gebootet wird, bin ich interessiert. :-)

Selbes Problem hier. Anwendung mit der Anmeldeseite außerhalb der Winkel-App erhalten. Problemumgehung in früheren Kommentaren scheint veraltet zu sein. Hätte gerne ein aktualisiertes Dokument darüber, wie man ein solches Szenario testen kann.

@hankduan Ja, ich denke schon.

Ich kämpfe gerade mit diesem Problem. Der Hintergrund ist ähnlich: Ich habe eine größere Anwendung, deren Abhängigkeiten über RequireJS verwaltet werden.


Ich habe meine App bereits mit window.name='NG_DEFER_BOOTSTRAP!'; & angular.resumeBootstrap() aktualisiert, aber es funktioniert immer noch nicht.

Sagte dies, ich weiß nicht, was ich als nächstes tun soll. Für weitere Untersuchungen habe ich einen Testfall unter https://github.com/knalli/protractor-with-deferred-bootstrap eingerichtet

  • git clone https://github.com/knalli/protractor-with-deferred-bootstrap.git
  • cd protractor-with-deferred-bootstrap
  • npm install
  • npm run-script webdriver (Selenium-Server)
  • npm run-script server (Demo-App-Server, der eine Mini-AJS-App bereitstellt)
  • npm run-script e2e-test (läuft Winkelmesser...)

Das Ergebnis ist

Using the selenium server at http://localhost:4444/wd/hub
Login: Click
Login: Waiting...
A Jasmine spec timed out. Resetting the WebDriver Control Flow.
The last active task was: 
unknown
F

Failures:

gefolgt von

UnknownError: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element '

Der letzte Fehler ist etwas seltsam und vielleicht sogar irreführend: Der Test wurde durchgeführt (erfolgreich, soweit die Erwartungen in Ordnung waren und was wir im Browser sehen können).

Crosscheck: Wenn ich die Demo-App auf Non Deferred Bootstrapping mit manuellen Includes umstelle (diese Variante gibt es im Zweig no-deferred ), dann funktioniert es erfolgreich.


Ich habe bereits einige sogenannte "Workrounds" ausprobiert:

  1. http://www.sebdangerfield.me.uk/2014/01/angularjs-protractor-app-already-bootstrapped-error/
    Irrelevant oder irreführend --> kein Unterschied.
  2. https://github.com/angular/protractor/issues/325#issuecomment -36738048 mit protractor.getInstance() und ignoreSynchronization --> kein Unterschied
  3. https://github.com/angular/protractor/issues/325#issuecomment -30701683 Patchen clientSideScripts.js/waitForAngular --> kein Unterschied

Ich habe gestern meine ersten Winkelmessertests geschrieben und hatte das gleiche Problem wie Knalli.

Danke, dass du das Beispiel @knalli geschrieben hast. Schau ich mir in ein paar Tagen an

Also testet mein Winkelmesser alle Arbeiten (bis auf einen Fehler, aber das ist meine Schuld :-P ).
Sag Bescheid, wenn das hilft/nicht hilft.
Hier ist mein Setup:

Winkelmesser-Version:
Version 1.0.0-rc4
Selen eigenständig:
ist aktuell
Chromtreiber:
ist aktuell

Definitiv relevante Dateien:

Konfig

/*jshint expr: true*/
/*global browser: true*/
var TEST_DIR =  '../tests/';
exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub'
,  specs : [     '../tests/e2e/_protractor.js'       ]
,  capabilities: {'browserName': 'chrome'    }
,  chromeDriver: './chromedriver'  // <---- I remember not being able to get chromedriver working 
                                                    // for some reason, so I just downloaded the executable and put it
                                                    // in my config directory
,  onPrepare: function() {
    "use strict";
    browser.driver.get('http://localhost:5000/register');
    browser.driver.wait(function() {
      return browser.driver.getCurrentUrl().then(function(url) {
        return /\#\/registration/.test(url);
      });
    });
  }
    //  chromeOnly: true,
    //  baseUrl: 'http://localhost:5000/register'
,  jasmineNodeOpts: {
    showColors: true
  }
};

_protractor.js

/*jshint expr: true, undef: true */
/* global element: true, by: true, browser: true, model:true */
(function(){
  "use strict";

var RegistrationPage = function(){
  browser.driver.wait(function() {
    return browser.driver.getCurrentUrl().then(function(url) {
      return /\#\/registration/.test(url);
    });
  });
};
  var account = new RegistrationPage();

  account.elem = element.all(by.name('account_exists'));
  account.accountNumber = element(by.name('account_number'));
  account.submitAccountButton = element(by.css('#account_input button'));

  account.selectHasAccount = function(){
    account.elem.get(0).click();
    return browser.getCurrentUrl();
  };

  account.enterAccountNumber = function(keys){

    account.selectHasAccount().then(function(){
      account.accountNumber.sendKeys(keys);
      return account.submitAccountButton.click()
        .then(function(){
          return browser.getCurrentUrl();
      });
      //this wont log because already returned ^
//      console.log('need to return again');
    });
  };
  account.noAccount = function(){
    account.elem.get(1).click();
  };

describe('registration page', function() {
  it("will survive", function(){
    var registrationPage = new RegistrationPage()
    , title = browser.getTitle();
    expect(title).toBe('Web Shop | Homepage');
  });
  it('will change route on account_exists radiobox click', function(){
    var elem = element.all(by.name('account_exists'))
    , _url;
    elem.get(0).click()
    .then(function(){
      _url = browser.getCurrentUrl().then(function(_url){
        expect(_url).toBe('http://localhost:5000/register#/registration/has');
      });
    })
    .then(function(){
        elem.get(1).click().then(function(){
          _url = browser.getCurrentUrl();
          expect(_url).toBe('http://localhost:5000/register#/registration/no');
        });
      });
  });
  describe('navigate the hasAccount path:', function(){
    it('will click hasAccount which will cause a route change.', function () {
      expect(account.selectHasAccount()).toBe('http://localhost:5000/register#/registration/has');
    });
    it("will submit a valid account number", function(){
      expect(account.enterAccountNumber('1231231231')).toBe('http://localhost:5000/register#/user');
    });
  });
  it('will click noAccount which will cause a route change.', function () {
    var  _url;
    account.noAccount();
    _url = browser.getCurrentUrl();
    expect(_url).toBe('http://localhost:5000/register#/registration/no');
  });
});
})();

Require/main.js:

var pathToJQuery
if('querySelector' in document
  && 'localStorage' in window
  && 'addEventListener' in window) {
  //ie9+ and all browsers
  pathToJQuery = 'lib/jquery/dist/jquery'
} else {
  //ie8 and ie7
  pathToJQuery = 'lib/jquery-1.7.2.min'
}
requirejs.config({

      paths : {

//        Paths

          "reg": 'js/registration'
        , "com": 'js/common'
        , "init": 'js/init'
        , "regD": 'js/registration/directives'
        , "regC": 'js/registration/controllers'
        , "regS": 'js/registration/services'
        , "regM": 'js/registration/modules'
//
//        Frameworks
        ,  "angular": "lib/angular/angular"
        ,  "angular.animate" : "lib/angular-animate/angular-animate"
        ,  "jquery": pathToJQuery   //< = == v    long story; don't judge me.
        ,  "jqueryMigrate" : "lib/jquery-migrate/jquery-migrate"
        ,  "mocks": "lib/angular-mocks/angular-mocks"
        ,  "ui_router": "lib/angular-ui-router/release/angular-ui-router"
        ,  "Q": "lib/q/q"

//        Init
        ,  "apps_init" : 'js/init/apps_init'
        ,  "apps_bootstrap" : 'js/init/apps_bootstrap'
//        ,  "jquery_bootstrap" : 'js/init/jquery_bootstrap'
        ,  "registration": "js/init/registration"

//       Common

//         Registration
        ,  "registration": "js/registration/registration"
//         Controllers
        ,  "account.controller" : 'js/registration/controllers/account.controller'
        ,  "user.controller" : 'js/registration/controllers/user.controller'
//         Directives
        ,  "account.directive" : 'js/registration/directives/account.directive'
//    Services
        , "user.service" : "js/registration/services/user.service"
    }
,     shim: {
        'angular': {
            exports : 'angular'
        }
    ,   'angular.animate' : {deps: ['angular']}
    ,   'jqueryMigrate' : {deps: ['jquery']}
    ,   'ui_router' : ['angular']
    ,   'mocks': { deps: ['angular'], 'exports': 'angular.mock' }
}
});

if( pathToJQuery ===  'lib/jquery/dist/jquery' ){
  requirejs([
        'angular' , 'jquery' , 'jqueryMigrate', 'init/jquery_bootstrap', 'init/apps_bootstrap' ]
      , function(angular, jquery, jquery_bootstrap, apps_bootstrap) {
      }
  );
} else {
  requirejs([
      'angular' , 'jquery' , 'jqueryMigrate', 'init/jquery_bootstrap', 'init/apps_bootstrap' ]
    , function(angular, jquery, jqueryMigrate, jquery_bootstrap, apps_bootstrap) {
    }
  );
}
console.log("working");

Potenziell hilfreiche Dateien:

Standardansicht (Lenker)

<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org"
            xmlns:fab="http://angularjs.org"
            xmlns:ui ="http://angularjs.org"
            lang = "en" class = "no-js" >
<head >
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/x-icon" media="all" href="/images/favicon.ico" />
<script type="text/javascript" src="lib/modernizr.js"></script>

<!-- Default ie theme files:-->
<!--[if lte IE 9]><script type="text/javascript">console = {}; console.log = function(){};</script><![endif]-->
<!--[if IE 8]><link type="text/css" rel="stylesheet" href="build/css/ie8/theme.css" /><![endif]-->

<!--[if IE 7]><link type="text/css" rel="stylesheet" href="build/css/ie7/theme.css" /><![endif]-->

<!-- Normal styles -->
<link type="text/css" href="css/style.css" rel="stylesheet">


<!--[if IE 8]> <link type="text/css" rel="stylesheet" href="build/css/ie8/ie_8.css"  /> <![endif]-->
<!--[if IE 7]> <link type="text/css" rel="stylesheet" href="build/css/ie7/lte_ie7.css"/> <link type="text/css" rel="stylesheet" href="build/css/ie7/ie_7.css" /><![endif]-->


<script data-main="main" src="lib/requirejs/require.js"></script>
</head >

<body class = "page-homepage language-en" >
<div id = "wrapper" >
    <div id = "page" data-currency-iso-code = "USD" >
        {{> _header}}
        <a href = "#skip-to-content" class = "skiptocontent" >Skip to content</a >
        <a href = "#skiptonavigation" class = "skiptonavigation" >Skip to navigation menu</a >
    <!--[if lte IE 10]> <p class="browsehappy" style="margin-top: 10px; ">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p><![endif]-->
    <main ng-cloak id = "content" role = "main" class = "page_main <!--[if IE7]>ng-cloak<![endif]-->" >

        </main>
    </div >
</div >
</body >

</html >

controller.js (Serverkonfiguration)

(function(){
    "use strict";

    //  node requires
    //==============================
    // express-hbs
    // express
    //
    const express = require('express')
        , portN = 5000
        , hbs = require('express-hbs')
        , app = express()
        , path = require('path')
        , Server = require('./server')
        , bodyParser = require('body-parser')
        , serveStatic = require('serve-static')
        , session = require('express-session')

    , router = express.Router()
    , logger  = require('morgan')
        , methodOverride = require('method-override')
        , errorhandler = require('errorhandler')


    //  view paths
    //==============================
    //
    //
    //
        , viewsD = __dirname + '/views/'
        , partialsD = viewsD + 'partials/'
        , layoutsD = viewsD + 'layouts/'
        , testsD =  __dirname + '/tests/'
    , publicD = __dirname + '/public/'
    , styleguideD = publicD+ '/styleguide/'
        , defaultF = layoutsD + 'default.hbs';
    //  Express setup.
    //==============================
    //
    //
    //
    app.use(express.static(publicD))
            .use(bodyParser())
            .use(logger('dev'))
            .use(methodOverride())
            .use(serveStatic(path.join(__dirname, 'public')))
            .use(errorhandler());

    app.set('view engine', 'hbs')
            .set('port', process.env.PORT || portN)
            .set('cache', false)
            .set('views', viewsD);

    app.engine('hbs', hbs.express3({
        partialsDir: partialsD,
        defaultLayout: defaultF,
        layoutsDir: layoutsD
    }));

    var indx = {};

    app.get( '/' ,function (req, res) {
        res.render(partialsD + '_home.hbs', indx);
    });

    app.get( '/register' ,function (req, res) {
        res.render(partialsD + '_register.hbs', indx);
    });

    new Server(app);

})();

server.js

module.exports = function(app){
  "use strict";
    var http = require('http');
    http.createServer(app).listen(app.get('port'), function(){
        console.log('Express server listening on port ' + app.get('port'));
    });
};


module.exports = function (app) {
    "use strict";
    var http = require ('http');
    http.createServer (app).listen (app.get ('port'),function () {
        console.log ('Express server listening on port ' + app.get ('port'));
    }).on ('error', function (e) {
        console.log ("got error: " + e.message);
    });
};

package.json (relevanter Auszug)

"dependencies": {
    "body-parser": "^1.2.1",
    "bower": "^1.3.2",
    "errorhandler": "^1.0.1",
    "express": "^4.3.1",
    "express-hbs": "^0.7.9",
    "express-session": "^1.2.0",
    "node-dev": "^2.3.0"
  },

  "scripts": {
    "start": "node --harmony $* ./node_modules/.bin/node-dev controller.js",
  },
"devDependencies": {
  "browserstack-webdriver": "^2.41.1",
  "grunt-protractor-runner": "^1.0.0",
  "method-override": "^1.0.2",
    "morgan": "^1.1.1",
    "protractor": "^0.23.1",
    "requirejs": "^2.1.11",
    "serve-static": "^1.1.0",
},
  "author": "Andrew Luhring"

Dateistruktur:

config/
   protractor.config.js
    chromedriver

server.js
controller.js

public/
   main.js
   js/
   lib/

tests/
   e2e/
      _protractor.js    <=== test file.

views/
  layouts/
      default.hbs

  partials/
      _head.hbs
      _register.hbs   <=== file being tested.

Ich bin mir ziemlich sicher, dass das mein ganzes Setup ist. Dachte, ich würde mich für wortreich entscheiden. Ich hoffe, das hilft.

Was ich tun musste, war:

  1. Fügen Sie der URL einen testspezifischen Teil hinzu, damit mein Bootstrap-Code weiß, ob er "normal" oder als Winkelmessertest ausgeführt wird, dann nur für die Tests
  2. rufen Sie angle.bootstrap von document.ready auf
  3. setze den Fensternamen so, dass er mit 'NG_DEFER_BOOTSTRAP!' vor dem Aufruf von angle.bootstrap
  4. setze das Attribut „ng-app“ für mein Element der obersten Ebene
  5. setze window.angular so, dass es auf angle zeigt

Siehe https://github.com/mikaraento/protractor-reuse/blob/master/index.js

Darf ich wissen, warum die Winkelmesser-Skripte, die in Chrome- und Firefox-Browsern einwandfrei ausgeführt werden, in Internet Explorer nicht immer ausgeführt werden können?

Obwohl die gleichen Skripte in anderen Browsern perfekt ausgeführt werden, können sie im Internet Explorer nicht immer gleich ausgeführt werden. Ich erhalte häufige Fehler wie Timeout-Ausnahme wie
Nachricht: 'Zeitüberschreitung: Zeitüberschreitung nach 30000 ms Warten auf Abschluss der Spezifikation',
Trace: { Stapel: undefiniert } } ]
und auch Elemente werden manchmal nicht im Internet Explorer erkannt.

Obwohl ich das Standardzeitintervall als defaultTimeou tInterval:1000000 verwendet habe, erhalte ich in meinen Skripts die oben genannten Fehler beim Ausführen in Internet Explorer ...

Kann mir jemand dabei helfen?

Grüße,
Santhosh Chunchu

Ich sehe nicht, dass das ein Problem nur mit manuellem Bootstrapping ist? Oder können Sie manuelle Bootstrap-Apps bereits in Chrome und Firefox ausführen?

@hankduan Hast du schon mal in den Testfall geschaut? Vielleicht können wir helfen?

Ich habe eine CL heraus, die die Funktionsweise des Bootstrappings für Winkelmesser ändert (https://github.com/angular/protractor/pull/1155). Der Hauptzweck besteht darin, eine Reihe anderer Probleme zu beheben, aber ich denke, es sollte mit manuellem Bootstrap behoben werden (oder zumindest helfen), je nachdem, wie Sie Bootstrapping durchführen. Ich habe jedoch noch nie einen manuellen Bootstrap zum Testen eingerichtet, daher ist dies nur theoretisch.

Diese PR erfordert eine Änderung des Winkelmessers und eine Änderung des Winkels, sodass sie möglicherweise nicht in kurzer Zeit veröffentlicht wird.

Dieses Problem scheint das Top-Suchergebnis zu sein, wenn nach Möglichkeiten gesucht wird, Angular manuell für die Verwendung mit Protractor zu booten, also dachte ich, dass dies so gut wie jeder Ort ist, um eine andere Lösung vorzuschlagen. Dies funktioniert für den Fall, dass Ihre gesamte Benutzeroberfläche eine Angular-App ist (anstatt so etwas wie Bootstrapping auf einem div nach der Anmeldung durchzuführen, wie in den obigen Beispielen).

Während es möglich sein kann, die Tests von Protractor zu verzögern, bis Angular geladen ist, geben die offiziellen Angular-Dokumente an, dass Sie mit Protractor kein manuelles Bootstrapping durchführen können. Ich neige dazu, Workarounds zu vermeiden, die die offizielle Dokumentation zu verbieten scheint.

Meine Lösung

Ich verwende Grunt, um meinen Code mit einem Skript-Tag in eine einzelne JS-Datei zu konkatieren/zu verkleinern, die das einzige Skript ist, auf das in index.html verwiesen wird. Nennen wir es script.js. In der Entwicklung führe ich eine andere Grunt-Aufgabe aus, die nur die Dateien zusammenfasst, die ich benötige, um die restlichen JS-Dateien separat, asynchron und mit Zeitstempeln zu laden, um Caching zu verhindern. Dieser zusammengefügte Satz von Skripten ersetzt script.js, während ich entwickle. In beiden Szenarien lade ich nur script.js aus index.html und mit einem script-Tag.

Entwicklung

In der Entwicklung muss ich also einen manuellen Bootstrap durchführen. Das ist einfach, weil ich eine einzelne Datei, die ich nicht konkatiere, in das Produktions-JS einfügen kann, und ich stelle sicher, dass ich dieses Skript lade, nachdem alle anderen JS geladen wurden.

bootstrap_dev.js

        .element(document.body)
        .ready(function() {
            angular.bootstrap(document.body, ['App']);
        });

Produktion / Winkelmesser

In der Produktion kann ich nicht manuell booten, weil Protractor es nicht mag. Und ich führe Protractor gegen meinen Produktionscode aus. Ich habe auch das Attribut "ng-app" aus meinem HTML entfernt, damit die Anwendung in der Entwicklung nicht vorzeitig bootet, sodass das normale automatische Bootstrap nicht auftritt. Ich gleiche dies in der Produktion aus, indem ich ein Skript vor allen anderen JS in script.js einfüge.

bootstrap_prod.js

    window.document.body.setAttribute("ng-app", "myApp");

Ersetzen Sie einfach "myApp" durch den Namen Ihres Hauptmoduls.

Fazit

Wenn Sie in der Entwicklung wie oben beschrieben vorgehen, können Sie Ihr Skript asynchron laden und einen manuellen Bootstrap durchführen. Aber wenn Sie damit einverstanden sind, dass Sie Ihre Protractor-Tests nur gegen Produktionscode ausführen (der über ein Skript-Tag aus einer einzelnen Datei geladen werden kann), fügen Sie einfach die ng-app-Direktive hinzu, bevor Angular geladen wird, damit es das automatische Bootstrapping durchführt. Jetzt haben Sie es asynchrones Skriptladen Ihrer verschiedenen Skripte in der Entwicklung und Ausführen von Protractor-Tests für Ihren Produktionscode.

Was am Ende für mich funktionierte, war das Hinzufügen der folgenden Funktion in meiner protractor.conf.js:

onPrepare: function() 
    {
        // implicit and page load timeouts
        browser.manage().timeouts().pageLoadTimeout(40000);
        browser.manage().timeouts().implicitlyWait(25000);

        // for non-angular page
        browser.ignoreSynchronization = true;

        // sign in before all tests
     }

Wenn es einen besseren Weg gibt, lass es mich wissen =]

Hatte ähnliches Problem. Habe diese nützliche Info gefunden:

Bootvorgang

Es gibt keinen Unterschied, wie die App in der Produktion verstärkt wird, aber in Tests macht Protractor das:

  1. Ändert window.name so, dass eckig vor dem Start angehalten wird: NG_DEFER_BOOTSTRAP! (Dies ist eine Winkelfunktion!)
  2. Verspottet Sachen, ruft dann angle.resumeBoostrap() auf und die App startet tatsächlich.

Stellen Sie also sicher, dass Ihr Produktionscode nicht mit diesem Prozess in Konflikt steht, da Winkel nur einmal verstärkt werden kann, der zweite Aufruf von angle.boostrap() oder angle.resumeBoostrap() wird den Winkelmesser oder die App beschädigen. ng-app im Körper wird also überhaupt nicht benötigt, und Sie können angle.boostrap() selbst aufrufen und es wird vom Winkelmesser mit NG_DEFER_BOOTSTRAP gehandhabt! richtig.

Fenster.Name

Stellen Sie sicher, dass window.name während des Ladens und Bootens nicht durch App-Code geändert wird. In meinem Fall hat jquery das getan, kann nicht herausfinden, warum. Jquery vollständig aus meinem Projekt entfernt und Tests funktionierten. Das ist die Wurzel des Problems!

Im Moment suche ich, wie ich jquery zurückbringen kann, ohne Tests zu unterbrechen, da es von meinem Projekt benötigt wird!

Endlich,

Unser Problem lag in zwei Versionen von jQuery auf einer Seite (die zweite Version wurde von einer externen Bibliothek geladen). Habe es entfernt und nur unsere jQuery auf der Seite gelassen und alles funktioniert.

Etwas Code, kann hilfreich sein:

index.html

<body>
...
<script data-main="require.conf" type="text/javascript" src="bower_components/requirejs/require.js"></script>
</body>

requirejs-Konfiguration

...
 deps: ["proto/main"],
...

proto.js

// We just load deps and register the module:
 define(["deps"],function(){
   angular.module('proto'...
 }

proto/main.js

define(["require", "exports", "proto", "angular"], 
    function (require, exports) {

    angular.bootstrap(document, ['proto']);
});

und eigentlich die Testspezifikation

var protractor = require('protractor');
var ptor;
function prepareBrowser() {

    ptor = protractor.getInstance();

    return ptor.get(ptor["baseUrl"] + '/login').then(function () {
        console.log("got");       
        return ptor.waitForAngular().then(function () {
            console.log("ngwaited");
        });
    });
}
describe('container', function () {
    beforeEach(function () {
        return prepareBrowser();
    });
    describe('form tests', function () {
        it('form is shown', function () {
            expect($('[ng-controller=LoginContr]').isDisplayed()).toBeTruthy();
        });

    });
});

Ausgabe

Using the selenium server at http://localhost:4444/wd/hub
got
ngwaited
container
  form tests
    form is shown - pass


Finished in 3.112 seconds
1 test, 1 assertion, 0 failures

Hurra!

Als wir von ng-app zu angular.bootstrap() wechselten, war das Hinzufügen rootElement: 'div' zu projotractor.conf die einzige Änderung, die wir brauchten, um den Winkelmesser wieder zum Laufen zu bringen. Wir verwenden Winkel 1.3.0 und Winkelmesser 1.3.1.

@jongunnip Ja , das hat bei mir auch funktioniert, danke!

@mikaraento Es hat bei mir funktioniert, danke~

Hallo Leute, seltsame Sache relevant für diesen Thread.

Ich habe eine normale Winkel-App - keine Anforderungen oder ähnliches, ich verwende Winkelmesser 2.0.0.

Wenn ich die Systemtests in der Staging-Umgebung ausführe, funktioniert es.
Wenn ich es lokal ausführe, gibt es mir:
org.openqa.selenium.WebDriverException: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element ... Nachricht

Wenn ich einen Nginx-Server konfiguriere, um die statische Ressource anstelle von grunt:server bereitzustellen, funktioniert alles.

Spielt es wirklich eine Rolle, ob ich es mit Livereload in der Entwicklung betreibe?

Scheint, als würden sich statische Server anders verhalten, und Grunzen bedient einige 404-Fehler oder Weiterleitungen, sodass Webdriver verrückt spielt.

Hallo alle,

Nach viel Zeit des Lesens und Lesens habe ich eine Lösung gefunden, die für mein Projekt gut funktioniert ( korrigieren Sie den Ausführungsfluss des Winkelmessers ).

  1. Wenn Sie die App zum Winkelmesser öffnen, fügen Sie ?protractor-test zur URL hinzu ( Projektcode )
  2. Ändern Sie den eckigen Bootstrap-Code so, dass er wie unten ist ( Projektcode ).
if(location.href.indexOf("protractor-test") < 0){
  // start angular app
  angular.bootstrap(document, [module.name]);
} else {
  // start angular app to protractor tests
  window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
  angular.bootstrap(document, [module.name]);
}

und endlich wieder alle an die arbeit \o/

mit Kopie @juliemr

Ich habe vor kurzem (nur 1-2 Wochen) angefangen, Protractor zu verwenden, um meine Angular-Anwendung zu testen. Meine Anwendung hat ng-App im Body-Tag auf der Anmeldeseite definiert. Mein Test beschwert sich immer wieder und sagt: „Angular konnte auf der Seite httP://(WebSite Address) nicht gefunden werden: Angular hat nie ResumeBootstrap bereitgestellt.“ Aber die Testausführung ist in Ordnung. Ich bin mir über das Problem nicht sicher (wenn ich den Browser-Ignoresync-Parameter einschalte, funktioniert es einwandfrei, aber dies ist nicht der richtige Weg). obwohl es ng-App im Body-Tag hat. Das Funktionsverhalten der App ist wie folgt: Anmeldeseite. Sobald Sie sich angemeldet haben, klicken Sie auf einen Link auf der Startseite und es öffnet sich ein weiteres Fenster/Tab. Könnte mir jemand helfen, Schritte zu finden, die alle überprüft werden müssen, um sicherzustellen, dass das Bootstraping automatisch erfolgt (einer ist der ng-app-Parameter im Body-Tag)? Muss ich etwas in der Bootstrap.js-Datei überprüfen (ich sehe keinen ng-app-Parameter in der Bootstrap-Datei, daher Überprüfung. Danke

Gibt es Neuigkeiten zu diesem Thema? Was sind die Best Practices oder Methoden zum Konfigurieren des Winkelmessers für die Arbeit mit einer Winkel-App, die keine ng-App hat? @erkobridee könntest du dein Beispiel näher erläutern? Und kann jemand erklären, wie man window.name richtig handhabt, wenn es darum geht, wie der Winkelmesser warten soll, wenn der Winkel fertig geladen ist?

@juliemr Bei Angular 1.5 ist manuelles Bootstrapping die bevorzugte Methode zum Bootstrapping. Gibt es eine gesegnete Winkelmesserunterstützung auf dem Weg?

+1 Ich denke, dieses Problem sollte eine höhere Priorität haben. Wenn Protractor nicht mit manuellem Bootstrap funktioniert, hat die Verwendung von Protractor keinen Vorteil. Der springende Punkt bei der Verwendung von Protractor über Webdriver ist, dass Protractor die gesamte Winkelsynchronisierung für Sie übernimmt.

Ich habe das gleiche Problem. Irgendein Update?

Hallo, gibt es einen Plan oder Prozess, um dies zu verbessern?

Seltsamerweise gibt es keine Rückmeldung. Ich habe Apps, bei denen ng-app fehlt, und ich kann sie nicht testen
sie mit Winkelmesser

Am 16. Juli 2016 um 5:01 Uhr schrieb "millerwx" [email protected] :

Hallo, gibt es einen Plan oder Prozess, um dies zu verbessern?


Sie erhalten dies, weil Sie kommentiert haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/angular/protractor/issues/66#issuecomment -233104701,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

Bis zu diesem Datum im Jahr 2016 war dies immer noch ein Problem für mich. Ich folgte der Antwort von Magnetized, um das Problem zu lösen. Ich habe nur ein paar Änderungen vorgenommen. Was nett ist und außerhalb des Rahmens der Konversation liegt, ist, auch Weiterleitungen zu verfolgen und wieder in Ihrer App zu landen. *Ich habe es mit Babel gemacht, aber Sie können es stattdessen in ES5 schreiben.

`describe('Anmeldebildschirm', ()=>{

var urlTimeout = 9000;

const waitForUrlRegex = (regex, urlMatcher )=>{

    return driver.wait(()=>{
        return driver.getCurrentUrl().then( (url)=>{
            return regex.test(url);
        });
    }, urlTimeout, "Expectation error: Timeout for url not matching " + urlMatcher );
};

const waitForRoute = (route)=>{
    return waitForUrlRegex( new RegExp( route + "$" ), route  );
}

const waitForUrl = (url)=>{
    return waitForUrlRegex( new RegExp( "^https?:\/\/" + url ), url );
}

it('should go to homepage and click login button', ()=>{

    driver.get( app_url, urlTimeout);

    //there is a redirect to welcome route
    expect( waitForRoute("welcome") ).toBe(true);

    const loginButton = element.all(by.className("login_button")).get(0);
    loginButton.click();
});

it( 'should enter credentials', ()=>{
    expect( waitForUrl( non_angular_login_url ) ).toBe(true);
    driver.findElement( by.name("user")).sendKeys( "username");
    driver.findElement( by.name("password")).sendKeys( "userpassword");
    driver.findElement( by.tagName("button")).click();
});

it( 'should go back to app, and continue testing', ()=>{
    expect( waitForRoute( "user-screen") ).toBe(true);
});

});`

config.onPrepare

onPrepare: ()=>{ require("babel-register"); global.driver = browser.driver; }

Falls Sie sich keine Weiterleitungen ansehen möchten, lassen Sie den Treiber einfach schlafen und beginnen Sie dann mit der Arbeit mit dem Winkelmesser.

`driver.get( app_url+ "/#/welcome", urlTimeout);

    driver.sleep( 1000 );
    const loginButton = element.all(by.className("login_button")).get(0);
    loginButton.click();`

Wir unterstützen tatsächlich manuelles Bootstrapping, diese Informationen sind alt. Bootstrapping wird noch zuverlässiger, sobald wir auch https://github.com/angular/protractor/issues/3857 handhaben.

@sjelin Was ist der dokumentierte Weg, um manuelles Bootstrapping zu unterstützen? Ich kann die relevanten Informationen für Winkelmesser 5.0 nicht finden.

Ich hatte das gleiche Problem beim manuellen Bootstrapping. und fand die Lösung, mit Grunzen zu laufen.
verwendete Winkelmesser Version 2.5.1.

  1. Erwähnen Sie dies in Ihrer Grunt-Datei.

grunt.initConfig({ protractor: { options: { configFile: "protractor.conf.js", // Default protractor config file keepAlive: true, // If false, the grunt process stops when the test fails. noColor: false, // If true, protractor will not use colors in its output. args: { // Arguments passed to the command } }, e2e: { options: { // Stops Grunt process if a test fails keepAlive: true } } } })

  1. Installieren Sie npm install grunt-protractor-runner --save-dev und fügen Sie die Ladeaufgabe grunt.loadNpmTasks('grunt-protractor-runner') hinzu

  2. Führen Sie den Winkelmesser mit folgendem Befehl aus:
    grunt protractor
    oder mit Suite-Namen
    grunt protractor --suite suite_name

Bitte lassen Sie mich wissen, ob es für Sie funktioniert.

Das hat bei mir funktioniert.
browser.ignoreSynchronization = true;
browser.get(url);
browser.ignoreSynchronization = falsch;

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen