Protractor: Rapporteur et bootstrap manuel angulaire

Créé le 30 août 2013  ·  49Commentaires  ·  Source: angular/protractor

J'ai un problème lors de l'exécution du rapporteur 0.8 et j'ai des problèmes pour exécuter le rapporteur sur notre application qui est démarrée manuellement.

Voici quelques extraits révélant les parties pertinentes de l'application et de la configuration :
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']);

Cela fonctionne dans la pratique et Angular est démarré correctement. Lorsque je visualise la source html, je ne vois pas l'attribut ng-app apparaître sur l'élément html. Peut-être que Protractor ne le fait pas non plus ?

J'utilise l'exemple de configuration du rapporteur et j'ai modifié les valeurs pertinentes en fonction de mon application :

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

Échantillon test:

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

Lorsque je lance ce test, deux erreurs apparaissent :

 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

et

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)

La première erreur semble être la plus importante, mais la dernière erreur est également assez intéressante. Il me semble que la ligne : ptor.By.input ne fonctionne pas.

Des idées?

untriaged discussion

Commentaire le plus utile

@sjelin Quelle est la manière documentée de prendre en charge le démarrage manuel? Je ne trouve pas les informations pertinentes pour le rapporteur 5.0.

Tous les 49 commentaires

Le code Angular est-il inclus sur la page ? Il semble que vous ayez besoin de shim, bootstrap et autres, mais angular.min.js n'est pas affiché.

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

L'extrait ci-dessus réside à l'intérieur de l'élément shim{}, je l'ai laissé en dehors des extraits car il ne me semblait pas très pertinent. Mais c'est ainsi que angular.js est chargé.

Salut,

Oui, Protractor attend actuellement une ng-app, donc les sites démarrés manuellement auront des problèmes. En espérant obtenir une solution de contournement pour ce document bientôt.

Ok merci pour la mise à jour. Une fois que vous avez trouvé une solution de contournement, pouvez-vous la publier dans ce numéro ?

Désolé pour la lenteur de la réponse - vous devriez pouvoir réparer en faisant

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

Avez-vous configuré la variable ptor quelque part ? par exemple var ptor = protractor.getInstance() ?

Une mise à jour pour ceci? Votre correctif suggéré ne fonctionne pas pour moi ([email protected], [email protected])

J'ai une combinaison maladroite d'un écran de connexion non angulaire suivi d'une application requirejs, démarrée manuellement :

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

    });
});

Et mon 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]);
});

La partie connexion fonctionne et je peux voir un flash du chargement de la page protégée avant que les erreurs de rapporteur ne sortent avec UnknownError: javascript error: angular is not defined . J'ai essayé de recharger la page avec driver.get('...') et même ptor.get('...') mais rien ne fonctionne.

Tous les conseils / astuces / correctifs sont reçus avec gratitude.

@magnetised vous aurez besoin d'un moyen de dire à votre test d'attendre que la connexion soit terminée avant d'essayer d'autres tests. Je pense que ce qui se passe, c'est que vous essayez d'utiliser ptor.findElement avant qu'Angular ne soit chargé sur la page.

Votre spécification "Peut se connecter" doit se terminer par une instruction d'attente qui vérifie certaines conditions de votre application. Découvrez l'exemple ici - https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js

@juliemr Brillant, ça marche parfaitement.

J'avais compris que le rapporteur ferait "attendre que angular soit chargé" mais je suppose que vous ne pouvez pas couvrir tous les cas.

Merci encore.

J'ai exactement la même configuration. @juliemr cela vous dérange de partager votre solution. Quelle est votre condition d'attente ? Merci!

@jorgenfb Je me demande si vous vouliez dire que ce commentaire m'était adressé ?

Ma solution impliquait simplement d'attendre que le routeur angulaire démarre et de changer l'URL du simple '/' vers lequel le système de connexion vous redirige vers la route par défaut - dans notre cas '/#view'.

J'en ai fait une fonction que je pourrais réutiliser dans tous les tests :

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

Je ne sais pas si cela fonctionnera pour vous, cela dépend de votre configuration de routage.

@juliemr Merci, fonctionne comme un charme :)

J'ai un problème similaire (trouvé sur SO à: http://stackoverflow.com/questions/19391813/protractor-fails-to-find-angular) avec Protractor ne trouvant pas Angular même si Angular est très clairement chargé et en cours d'exécution. La solution facile (tester sans essayer de trouver Angular) est-elle la voie que nous devrions emprunter ? Cela semble aller à l'encontre de l'objectif de Protractor spécialement conçu pour tester les applications angulaires.
edit: Je dois également noter que la solution proposée dans ce problème ne fonctionne pas pour moi.

+1 pour avoir une meilleure documentation d'amorçage manuel angulaire

est-ce toujours d'actualité ?

Honnêtement, je ne sais pas car j'ai abandonné depuis et je n'ai pas vraiment le temps de revenir en arrière et de voir si quelque chose a changé. Compte tenu des changements de version depuis lors, si vous cherchez à fermer cela, je ne discuterais pas. Il peut toujours être rouvert plus tard.

Je viens de commencer à utiliser le rapporteur aujourd'hui et notre application utilise require.js... s'il y a eu des mises à jour concernant le test d'une application qui est démarrée manuellement, je suis, pour ma part, intéressé. :-)

Même problème ici. Vous avez une application avec la page de connexion en dehors de l'application angulaire. La solution de contournement dans les commentaires précédents semble être obsolète. J'aimerais beaucoup un document mis à jour sur la façon de pouvoir tester ce genre de scénario.

@hankduan Oui, je pense que oui.

Je suis aux prises avec ce problème en ce moment. Le contexte est similaire : j'ai une application plus grande dont les dépendances sont gérées via RequireJS.


J'ai déjà mis à jour mon application en utilisant window.name='NG_DEFER_BOOTSTRAP!'; & angular.resumeBootstrap() , mais cela ne fonctionnera toujours pas.

Cela dit, je ne sais pas quoi faire ensuite. Pour des investigations plus approfondies, j'ai mis en place un cas de test sur https://github.com/knalli/protractor-with-deferred-bootstrap

  • git clone https://github.com/knalli/protractor-with-deferred-bootstrap.git
  • cd protractor-with-deferred-bootstrap
  • npm install
  • npm run-script webdriver (Serveur Selenium)
  • npm run-script server (Demo App Server servant une mini application AJS)
  • npm run-script e2e-test (exécute le rapporteur...)

Le résultat est

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:

suivie par

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

La dernière erreur est un peu bizarre et peut-être même trompeuse : le test a été effectué (réussi dans la mesure où les attentes étaient correctes et ce que nous pouvons voir dans le navigateur).

Contre-vérification : si je passe l'application de démonstration à un amorçage non différé avec des inclusions manuelles (cette variante est disponible dans la branche no-deferred ), cela fonctionnera avec succès.


J'ai déjà essayé certaines soi-disant "solutions de contournement":

  1. http://www.sebdangerfield.me.uk/2014/01/angularjs-protractor-app-already-bootstrapped-error/
    Non pertinent ou trompeur --> pas de différence.
  2. https://github.com/angular/protractor/issues/325#issuecomment -36738048 en utilisant protractor.getInstance() et ignoreSynchronization --> aucune différence
  3. https://github.com/angular/protractor/issues/325#issuecomment -30701683 correctif clientSideScripts.js/waitForAngular --> pas de différence

J'ai écrit mes premiers tests de rapporteur hier et j'ai eu le même problème que knalli.

Merci d'avoir écrit l'exemple @knalli. je vais voir dans quelques jours

Donc mon rapporteur teste tout le travail (sauf un échec mais c'est de ma faute :-P ).
Faites-moi savoir si cela ne vous aide pas.
Voici ma configuration :

version rapporteur :
Version 1.0.0-rc4
sélénium autonome :
est à jour
pilote chrome :
est à jour

Fichiers définitivement pertinents :

Configuration

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

Fichiers potentiellement utiles :

vue par défaut (guidon)

<!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 (configuration du serveur)

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

})();

serveur.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 (extrait pertinent)

"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"

structure du fichier :

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.

Je suis sûr que c'est toute ma configuration. J'ai pensé que j'irais pour verbeux. J'espère que cela pourra aider.

Ce que je devais faire était de :

  1. ajouter une partie spécifique au test à l'URL, afin que mon code d'amorçage sache s'il s'exécute "normalement" ou en tant que test de rapporteur, puis uniquement pour les tests
  2. appeler angular.bootstrap depuis document.ready
  3. définir le nom de la fenêtre pour qu'il commence par 'NG_DEFER_BOOTSTRAP !' avant d'appeler angular.bootstrap
  4. définir l'attribut 'ng-app' sur mon élément de niveau supérieur
  5. définir window.angular pour pointer vers angular

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

Puis-je savoir pourquoi les scripts de rapporteur qui s'exécutent parfaitement dans les navigateurs Chrome et Firefox ne peuvent pas toujours s'exécuter dans Internet Explorer ?

Bien que les mêmes scripts s'exécutent parfaitement dans d'autres navigateurs, ils ne peuvent pas toujours s'exécuter de la même manière dans Internet Explorer. Je reçois des erreurs fréquentes comme l'exception de temps mort comme
message : 'timeout : expiration du délai après 30 000 msec en attente de la fin de la spécification',
trace : { pile : indéfini } } ]
et aussi des éléments ne sont parfois pas détectés dans Internet Explorer.

Bien que j'ai utilisé l'intervalle de temps par défaut comme defaultTimeou tInterval:1000000 , dans mes scripts, j'obtiens les erreurs mentionnées ci-dessus lors de l'exécution dans Internet Explorer...

Quelqu'un peut-il m'aider à ce sujet?

Salutations,
Santhosh Chunchu

Je ne vois pas que c'est un problème avec le démarrage manuel uniquement? Ou êtes-vous capable d'exécuter des applications amorcées manuellement déjà dans Chrome et Firefox ?

@hankduan Avez-vous déjà jeté un coup d'œil au cas de test ? Peut-être quelque chose que nous pouvons aider ?

J'ai une sortie CL qui change le fonctionnement de l'amorçage pour le rapporteur (https://github.com/angular/protractor/pull/1155). Son objectif principal est de résoudre un certain nombre d'autres problèmes, mais je pense que cela devrait résoudre (ou au moins aider) avec un démarrage manuel en fonction de la façon dont vous démarrez. Cependant, je n'ai jamais configuré le bootstrap manuel pour tester, donc c'est juste théorique.

Ce PR nécessite un changement de rapporteur et un changement d'Angular, il se peut donc qu'il ne soit pas publié dans un court laps de temps.

Ce problème semble être le premier résultat de recherche lorsque vous cherchez des moyens de démarrer manuellement Angular pour une utilisation avec Protractor, donc j'ai pensé que c'était aussi bon que n'importe quel endroit pour suggérer une autre solution. Cela fonctionne dans le cas où toute votre interface est une application angulaire (plutôt que de faire quelque chose comme un démarrage sur une div après la connexion, comme les exemples ci-dessus).

Bien qu'il soit possible de retarder les tests de Protractor jusqu'au chargement d'Angular, la documentation officielle d'Angular indique que vous ne pouvez pas effectuer d'amorçage manuel avec Protractor. J'ai tendance à éviter les solutions de contournement que la documentation officielle semble interdire.

Ma solution

J'utilise Grunt pour concaténer/Uglifier mon code dans un seul fichier JS, qui est le seul script référencé dans index.html, avec une balise de script. Appelons-le script.js. En développement, j'exécute une tâche Grunt différente, qui concatène uniquement les fichiers dont j'ai besoin pour charger le reste des fichiers JS, séparément, de manière asynchrone et avec des horodatages pour empêcher la mise en cache. Cet ensemble de scripts concaténés remplace script.js pendant que je développe. Dans les deux cas, je ne charge que script.js à partir de index.html et avec une balise de script.

Développement

Donc, dans Development, je dois faire un bootstrap manuel. C'est facile car je peux inclure un seul fichier que je ne concatène pas dans le JS de production, et je m'assure de charger ce script après le chargement de tous les autres JS.

bootstrap_dev.js

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

Production / Rapporteur

En production, je ne peux pas démarrer manuellement car Protractor ne l'aime pas. Et j'exécute Protractor sur mon code de production. J'ai également supprimé l'attribut "ng-app" de mon code HTML, afin que l'application ne démarre pas prématurément dans le développement, de sorte que le démarrage automatique normal ne se produit pas. Je compense cela en production en plaçant un script avant tous les autres JS dans script.js.

bootstrap_prod.js

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

Remplacez simplement "myApp" par le nom de votre module principal.

Conclusion

Dans Development, si vous faites ce qui précède, vous pouvez charger votre script de manière asynchrone et effectuer un bootstrap manuel. Mais si vous êtes d'accord pour n'exécuter vos tests Protractor que sur le code de production (qui peut être chargé à partir d'un seul fichier via une balise de script, ajoutez simplement la directive ng-app avant le chargement d'Angular afin qu'il effectue son démarrage automatique. Maintenant, vous avez chargement de scripts asynchrones de vos différents scripts en développement et exécution de tests Protractor pour votre code de production.

Ce qui a fini par fonctionner pour moi a été d'ajouter, dans mon protractor.conf.js, la fonction suivante :

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
     }

S'il y a une meilleure façon de le faire, s'il vous plaît faites le moi savoir =]

Avait un problème similaire. Trouvé cette information utile :

Processus de démarrage

Il n'y a aucune différence, comment l'application est boostée en production, mais dans les tests, le rapporteur fait cela :

  1. Modifie window.name afin que angular soit mis en pause avant le démarrage : NG_DEFER_BOOTSTRAP ! (c'est une fonction angulaire !)
  2. Fait des trucs fictifs, puis appelle angular.resumeBoostrap() et l'application démarre réellement.

Assurez-vous donc que votre code de production n'est pas en conflit avec ce processus, car angular ne peut être boosté qu'une seule fois, un deuxième appel à angular.boostrap() ou angular.resumeBoostrap() cassera le rapporteur ou l'application. Ainsi, ng-app dans le corps n'est pas du tout nécessaire, et vous pouvez appeler angular.boostrap() par vous-même et il sera géré par le rapporteur à l'aide de NG_DEFER_BOOTSTRAP ! correctement.

nom.fenêtre

Assurez-vous que window.name n'est modifié par aucun code d'application pendant le chargement et le démarrage. Dans mon cas, jquery faisait cela, je ne comprends pas pourquoi. jquery entièrement supprimé de mon projet et les tests ont fonctionné. C'est la racine du problème !

Pour l'instant, je cherche comment ramener jquery sans casser les tests, car il est nécessaire à mon projet !

Enfin,

notre problème était dans deux versions de jQuery sur une page (la deuxième version a été chargée par une bibliothèque externe). Je l'ai supprimé et je n'ai laissé que notre jQuery sur la page et tout fonctionne.

Un code, peut être utile:

index.html

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

configuration requise js

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

et, en fait, la spécification de test

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

    });
});

Sortir

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

Hourra !

Lorsque nous sommes passés de ng-app à angular.bootstrap() , l'ajout rootElement: 'div' à projotractor.conf était le seul changement dont nous avions besoin pour que le rapporteur fonctionne à nouveau. Nous utilisons angulaire 1.3.0 et rapporteur 1.3.1.

@jongunnip Ouais ça a marché pour moi aussi, merci !

@mikaraento Cela a fonctionné pour moi, merci ~

Salut les gars, chose étrange pertinente pour ce fil.

J'ai une application angulaire régulière - pas d'exigence ou quoi que ce soit, j'utilise le rapporteur 2.0.0.

Lorsque j'exécute les tests système sur l'environnement de staging, cela fonctionne.
Lorsque je l'exécute en local, cela me donne:
org.openqa.selenium.WebDriverException: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element ... message

Lorsque je configure un serveur Nginx pour servir la ressource statique au lieu de grunt:server , tout fonctionne.

Est-ce vraiment important si je l'exécute avec livereload en développement ?

On dirait que les serveurs statiques se comportent différemment, et le grognement sert des 404 ou des redirections, donc le pilote Web devient fou.

Salut tout le monde,

après beaucoup de temps à lire et à lire, j'ai trouvé une solution qui fonctionne bien pour mon projet ( corriger le flux d'exécution du rapporteur )

  1. lorsque vous ouvrez l'application au rapporteur, ajoutez ?protractor-test à l'URL ( code du projet )
  2. changer le code d'amorçage angulaire pour qu'il ressemble au soufflet ( code du projet )
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]);
}

et enfin tous de retour au travail \o/

avec copie @juliemr

J'ai récemment (seulement 1 à 2 semaines) commencé à utiliser Protractor pour tester mon application Angular. Mon application a ng-App défini dans la balise body sur la page de connexion. Mon test continue de se plaindre en disant "Angular n'a pas pu être trouvé sur la page httP://(WebSite Address) : angular n'a jamais fourni de CVBootstrap" Mais l'exécution du test est correcte. Je ne suis pas sûr du problème (si j'active le paramètre ignoresync du navigateur, cela fonctionne bien, mais ce n'est pas la bonne méthode), je peux essayer ce que suggère Juliemr (utiliser le pilote hérité pour naviguer), mais j'essaie simplement de comprendre pourquoi mon application se plaint même s'il a ng-App dans la balise body. Le comportement fonctionnel de l'application est comme ceci.. Page de connexion. Une fois connecté, cliquez sur un lien sur la page d'accueil et cela ouvre une autre fenêtre/onglet. Quelqu'un pourrait-il m'aider à trouver les étapes à vérifier pour s'assurer que l'amorçage est effectué de manière automatique (l'un est le paramètre ng-app dans la balise body ) ? Dois-je vérifier quelque chose dans le fichier bootstrap.js (je ne vois aucun paramètre ng-app dans le fichier bootstrap donc vérification. Merci

Y a-t-il des mises à jour sur ce problème ? Quelles sont les meilleures pratiques ou méthodes pour configurer le rapporteur pour qu'il fonctionne avec une application angulaire qui n'a pas d'application ng ? @erkobridee pourriez-vous expliquer davantage votre exemple ? Et quelqu'un peut-il expliquer comment gérer correctement window.name en ce qui concerne la façon dont le rapporteur doit attendre que le chargement angulaire soit terminé?

@juliemr Avec Angular 1.5, l'amorçage manuel est le moyen préféré d'amorçage. Y a-t-il un support de rapporteur béni sur le chemin ?

+1 Je pense que ce problème devrait être une priorité plus élevée. Si Protractor ne fonctionne pas avec le bootstrap manuel, il n'y a aucun avantage à utiliser Protractor. L'intérêt d'utiliser Protractor sur Webdriver est que Protractor gère toute la synchronisation angulaire pour vous.

J'ai le même problème. Toute mise à jour?

Salut, y a-t-il un plan ou un processus pour améliorer cela ?

Bizarre qu'il n'y ait pas de retour. J'ai des applications manquantes ng-app et je ne peux pas tester
eux avec rapporteur

Le 16 juillet 2016 à 5h01, "millerwx" [email protected] a écrit :

Salut, y a-t-il un plan ou un processus pour améliorer cela ?


Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/angular/protractor/issues/66#issuecomment -233104701,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

À ce jour en 2016, c'était toujours un problème pour moi. J'ai suivi la réponse magnétisée pour résoudre le problème. J'ai juste fait quelques modifications. Ce qui est agréable et hors de portée de la conversation, c'est de suivre également les redirections et de revenir dans votre application. *Je l'ai fait avec Babel, mais vous pouvez l'écrire en ES5 à la place.

`describe('écran de connexion', ()=>{

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

Si vous ne souhaitez pas examiner les redirections, mettez simplement le pilote en veille, puis commencez à travailler avec le rapporteur.

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

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

Nous prenons en charge le démarrage manuel, cette information est ancienne. L'amorçage deviendra encore plus fiable une fois que nous aurons également géré https://github.com/angular/protractor/issues/3857 .

@sjelin Quelle est la manière documentée de prendre en charge le démarrage manuel? Je ne trouve pas les informations pertinentes pour le rapporteur 5.0.

J'étais confronté au même problème lors du démarrage manuel. et a trouvé la solution pour courir avec grognement.
utilisé la version 2.5.1 du rapporteur.

  1. Mentionnez-le dans votre dossier de grognement.

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. Installez npm install grunt-protractor-runner --save-dev et ajoutez pour charger la tâche grunt.loadNpmTasks('grunt-protractor-runner')

  2. Exécutez le rapporteur avec la commande suivante :
    grunt protractor
    ou avec le nom de la suite
    grunt protractor --suite suite_name

S'il vous plaît laissez-moi savoir si cela fonctionne pour vous.

Cela a fonctionné pour moi.
navigateur.ignoreSynchronisation = true ;
navigateur.get(url);
navigateur.ignoreSynchronisation = faux ;

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