Protractor: Transportador y bootstrap manual angular

Creado en 30 ago. 2013  ·  49Comentarios  ·  Fuente: angular/protractor

Tengo un problema al ejecutar el transportador 0.8 y tengo problemas para ejecutar el transportador en nuestra aplicación que se inicia manualmente.

Aquí hay algunos fragmentos que revelan las partes relevantes de la aplicación y la configuración:
índice.html:

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

js/principal.js:

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

bootstrap.js:

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

Esto funciona en la práctica y Angular se inicia de forma correcta. Cuando veo la fuente html, no puedo ver el atributo ng-app que aparece en el elemento html. ¿Puede ser que Protractor tampoco lo haga?

Utilizo la configuración de muestra del transportador y cambié los valores relevantes para adaptarlos a mi aplicación:

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

Prueba de muestra:

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

Cuando ejecuto esta prueba aparecen dos errores:

 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

y

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)

El primer error parece ser el más importante, pero el último error también es bastante interesante. Me parece que la línea: ptor.By.input no funciona.

¿Algunas ideas?

untriaged discussion

Comentario más útil

@sjelin ¿Cuál es la forma documentada de admitir el arranque manual? No puedo encontrar la información relevante para el transportador 5.0.

Todos 49 comentarios

¿Se incluye el código angular en la página? Parece que necesita calzas, arranque y otros, pero no se muestra angular.min.js .

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

El fragmento anterior reside dentro del elemento shim{}, lo dejé fuera de los fragmentos porque no me pareció muy relevante. Pero esta es la forma en que se carga angular.js.

Hola,

Sí, Protractor actualmente espera una aplicación ng, por lo que los sitios que se inician manualmente tendrán problemas. Con la esperanza de obtener una solución para esto documentado pronto.

Ok, gracias por la actualización. Cuando haya descubierto una solución alternativa, ¿puede publicarla en este número?

Lo siento por la respuesta lenta, debería poder solucionarlo haciendo

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

¿Configuró la variable ptor en alguna parte? por ejemplo var ptor = protractor.getInstance() ?

¿Algún avance en esto? Su solución sugerida no funciona para mí ([email protected], [email protected])

Tengo una combinación incómoda de una pantalla de inicio de sesión no angular seguida de una aplicación de arranque manual requirejs:

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

    });
});

Y mi 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 parte de inicio de sesión funciona y puedo ver un destello de la carga de la página protegida antes de que el transportador se equivoque con UnknownError: javascript error: angular is not defined . Intenté volver a cargar la página con driver.get('...') e incluso ptor.get('...') pero nada funciona.

Cualquier sugerencia/consejo/solución recibida con gratitud.

@magnetizado , necesitará alguna forma de decirle a su prueba que espere hasta que se complete el inicio de sesión antes de intentar otras pruebas. Creo que lo que sucede es que intentas usar ptor.findElement antes de que Angular se haya cargado en la página.

Su especificación 'Puede iniciar sesión' debe terminar con una declaración de espera que verifique alguna condición para su aplicación. Consulte el ejemplo aquí: https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js

@juliemr Brillante, eso funciona perfectamente.

Había entendido que el transportador haría "esperar hasta que angular se haya cargado", pero supongo que no puedes cubrir todos los casos.

Gracias de nuevo.

Tengo exactamente la misma configuración. @juliemr , ¿te importaría compartir tu solución? ¿Cuál es su condición de espera? ¡Gracias!

@jorgenfb Me pregunto si quiso decir que ese comentario estaba dirigido a mí.

Mi solución solo consistía en esperar a que el enrutador angular se iniciara y cambiara la URL del '/' al que el sistema de inicio de sesión lo redirige a la ruta predeterminada, en nuestro caso '/#view'.

Lo convertí en una función que podía reutilizar en todas las pruebas:

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

No sé si esto funcionará para usted, depende de su configuración de enrutamiento.

@juliemr Gracias, funciona de maravilla :)

Tengo un problema similar (que se encuentra en SO en: http://stackoverflow.com/questions/19391813/protractor-fails-to-find-angular) con Protractor que no encuentra Angular a pesar de que Angular está claramente cargado y ejecutándose. ¿Es la solución fácil (probar sin tratar de encontrar Angular) el camino que deberíamos seguir? Parece anular el propósito de que Protractor se haya creado específicamente para probar aplicaciones Angular.
editar: también debo tener en cuenta que la solución propuesta en este problema no funciona para mí.

+1 por tener una mejor documentación de arranque manual angular

¿Sigue siendo relevante?

Honestamente, no lo sé, ya que dejé de intentarlo y realmente no tengo tiempo para regresar y ver si algo ha cambiado. Teniendo en cuenta los cambios de versión desde entonces, si está buscando cerrar esto, no lo discutiría. Siempre se puede volver a abrir más tarde.

Acabo de empezar a usar el transportador hoy y nuestra aplicación usa require.js... si ha habido alguna actualización con respecto a probar una aplicación que se arranca manualmente, yo, por mi parte, estoy interesado. :-)

El mismo problema aqui. Obtuve la aplicación con la página de inicio de sesión fuera de la aplicación angular. La solución en comentarios anteriores parece estar desactualizada. Me gustaría mucho un documento actualizado sobre cómo poder probar ese tipo de escenario.

@hankduan Sí, creo que sí.

Estoy luchando con este problema en este momento. El fondo es similar: tengo una aplicación más grande cuyas dependencias se administran a través de RequireJS.


Ya actualicé mi aplicación usando window.name='NG_DEFER_BOOTSTRAP!'; & angular.resumeBootstrap() , sin embargo, todavía no funcionará.

Dicho esto, no sé qué hacer a continuación. Para más investigaciones, configuré un caso de prueba en 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 (Servidor Selenium)
  • npm run-script server (Servidor de aplicaciones de demostración que sirve una aplicación mini AJS)
  • npm run-script e2e-test (ejecuta el transportador...)

El resultado es

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:

seguido por

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

El último error es un poco extraño y quizás incluso engañoso: la prueba se ha realizado (exitosa en la medida en que las expectativas estaban bien y lo que podemos ver en el navegador).

Comprobación cruzada: si cambio la aplicación de demostración a arranque no diferido con inclusión manual (esta variante está disponible en la rama no-deferred ), entonces funcionará correctamente.


Ya probé algunos de los llamados "workrounds":

  1. http://www.sebdangerfield.me.uk/2014/01/angularjs-protractor-app-already-bootstrapped-error/
    Irrelevante o engañoso --> ninguna diferencia.
  2. https://github.com/angular/protractor/issues/325#issuecomment -36738048 usando protractor.getInstance() y ignoreSynchronization --> sin diferencia
  3. https://github.com/angular/protractor/issues/325#issuecomment -30701683 parcheando clientSideScripts.js/waitForAngular --> sin diferencia

Escribí mis primeras pruebas de transportador ayer y tuve el mismo problema que knalli.

Gracias por escribir el ejemplo @knalli. le echare un vistazo en unos dias

Así que mi transportador prueba todo el trabajo (excepto por una falla, pero es mi culpa :-P).
Avíseme si esto no ayuda.
Aquí está mi configuración:

versión transportador:
Versión 1.0.0-rc4
selenio independiente:
está actualizado
controlador de cromo:
está actualizado

Definitivamente archivos relevantes:

Configuración

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

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

Requerir/principal.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");

Archivos potencialmente útiles:

vista predeterminada (manillar)

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

controlador.js (configuración del servidor)

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

})();

servidor.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 (extracto relevante)

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

estructura de archivos:

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.

Estoy bastante seguro de que esa es toda mi configuración. Pensé que iría por detallado. Espero que ayude.

Lo que tenía que hacer era:

  1. agregue una parte específica de la prueba a la URL, de modo que mi código de arranque sepa si se está ejecutando 'normalmente' o como una prueba de transportador, luego solo para las pruebas
  2. llame a angular.bootstrap desde document.ready
  3. establezca el nombre de la ventana para que comience con 'NG_DEFER_BOOTSTRAP!' antes de llamar a angular.bootstrap
  4. establecer el atributo 'ng-app' en mi elemento de nivel superior
  5. establecer window.angular para que apunte a angular

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

¿Puedo saber por qué las secuencias de comandos del transportador que se ejecutan perfectamente bien en los navegadores Chrome y Firefox no pueden ejecutarse siempre en Internet Explorer?

Aunque los mismos scripts se ejecutan perfectamente en otros navegadores, no se pueden ejecutar siempre de la misma manera en Internet Explorer. Recibo errores frecuentes como la excepción de tiempo de espera como
mensaje: 'tiempo de espera: agotado después de 30000 ms esperando que se complete la especificación',
rastrear: { pila: indefinido } } ]
y también, a veces, los elementos no se detectan en Internet Explorer.

Aunque utilicé el intervalo de tiempo predeterminado como defaultTimeou tInterval:1000000 , en mis scripts obtengo los errores mencionados anteriormente al ejecutar en Internet Explorer...

¿Puede alguien ayudarme con esto?

Saludos,
Santhosh Chunchu

No veo que sea un problema solo con el arranque manual. ¿O ya puede ejecutar aplicaciones de arranque manual en Chrome y Firefox?

@hankduan ¿Ya echaste un vistazo al caso de prueba? ¿Quizás algo en lo que podamos ayudar?

Tengo un CL que cambia la forma en que funciona el arranque para el transportador (https://github.com/angular/protractor/pull/1155). Su objetivo principal es solucionar una serie de otros problemas, pero creo que debería solucionar (o al menos ayudar) con el arranque manual dependiendo de cómo esté arrancando. Sin embargo, nunca configuré el arranque manual para probar, por lo que esto es solo teórico.

Este PR requiere un cambio en el transportador y un cambio en Angular, por lo que es posible que no se publique en un corto período de tiempo.

Este problema parece ser el principal resultado de búsqueda cuando se buscan formas de iniciar manualmente Angular para usar con Protractor, por lo que pensé que este es un lugar tan bueno como cualquier otro para sugerir otra solución. Esto funciona en el caso de que toda su interfaz sea una aplicación Angular (en lugar de hacer algo como arrancar en un div después de iniciar sesión, como en los ejemplos anteriores).

Si bien es posible retrasar las pruebas de Protractor hasta después de cargar Angular, los documentos oficiales de Angular indican que no puede realizar un arranque manual con Protractor. Tiendo a evitar las soluciones alternativas que la documentación oficial parece prohibir.

Mi solución

Estoy usando Grunt para Concat/Uglify mi código hasta un solo archivo JS, que es el único script al que se hace referencia en index.html, con una etiqueta de script. Llamémoslo script.js. En Desarrollo, ejecuto una tarea de Grunt diferente, que combina solo los archivos que necesito para cargar el resto de los archivos JS, por separado, de forma asíncrona y con marcas de tiempo para evitar el almacenamiento en caché. Este conjunto de scripts concatenados reemplaza script.js mientras estoy desarrollando. En cualquier escenario, solo estoy cargando script.js desde index.html y con una etiqueta de script.

Desarrollo

Entonces, en Desarrollo, tengo que hacer un arranque manual. Eso es fácil porque puedo incluir un solo archivo que no concateno en el JS de producción, y me aseguro de cargar este script después de que se hayan cargado todos los demás JS.

bootstrap_dev.js

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

Producción / Transportador

En producción, no puedo arrancar manualmente porque a Protractor no le gusta. Y estoy ejecutando Protractor contra mi código de Producción. También eliminé el atributo "ng-app" de mi HTML, por lo que la aplicación no se inicia prematuramente en Desarrollo, por lo que no se produce el arranque automático normal. Compenso esto en producción colocando un script antes que todos los demás JS en script.js.

bootstrap_prod.js

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

Simplemente reemplace "myApp" con el nombre de su módulo principal.

Conclusión

En desarrollo, si hace lo anterior, puede cargar su secuencia de comandos de forma asíncrona y hacer un arranque manual. Pero si está de acuerdo con ejecutar solo sus pruebas de Protractor contra el código de producción (que se puede cargar desde un solo archivo a través de una etiqueta de secuencia de comandos, simplemente agregue la directiva ng-app antes de que se cargue Angular para que realice su arranque automático. Ahora tiene carga asíncrona de secuencias de comandos de sus diversas secuencias de comandos en desarrollo y ejecución de pruebas de transportador para su código de producción.

Lo que terminó funcionando para mí fue agregar, en mi protractor.conf.js, la siguiente función:

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
     }

Si hay una mejor manera de hacerlo, por favor hágamelo saber =]

Tenía un problema similar. Encontré esta información útil:

Proceso de arranque

No hay diferencia, cómo se impulsa la aplicación en producción, pero en las pruebas, el transportador está haciendo eso:

  1. Cambia window.name para que angular se detenga antes de comenzar: NG_DEFER_BOOTSTRAP! (¡Esta es una característica angular!)
  2. Se burla de cosas, luego llama a angular.resumeBoostrap() y la aplicación realmente se inicia.

Así que asegúrese de que su código de producción no entre en conflicto con este proceso, ya que angular solo se puede impulsar una vez, la segunda llamada a angular.boostrap() o angular.resumeBoostrap() romperá el transportador o la aplicación. Por lo tanto, no se necesita ng-app en el cuerpo en absoluto, y puede llamar a angular.boostrap() usted mismo y será manejado por un transportador usando NG_DEFER_BOOTSTRAP. adecuadamente.

ventana.nombre

Asegúrese de que el código de la aplicación no cambie window.name durante la carga y el arranque. En mi caso, jquery estaba haciendo eso, no puedo entender por qué. Eliminé completamente jquery de mi proyecto y las pruebas funcionaron. ¡Esta es la raíz del problema!

Por ahora, estoy buscando cómo recuperar jquery sin romper las pruebas, ¡porque mi proyecto lo necesita!

Por fin,

nuestro problema estaba en dos versiones de jQuery en una página (la biblioteca externa cargó la segunda versión). Lo eliminé y dejé solo nuestro jQuery en la página y todo funciona.

Algún código, puede ser útil:

índice.html

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

requiere configuración js

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

proto.js

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

proto/principal.js

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

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

y, en realidad, la especificación de prueba

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

    });
});

Producción

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

¡Hora!

Cuando cambiamos de usar ng-app a angular.bootstrap() , agregar rootElement: 'div' a projotractor.conf fue el único cambio que necesitábamos para que el transportador volviera a funcionar. Estamos usando angular 1.3.0 y transportador 1.3.1.

@jongunnip Sí, eso también funcionó para mí, ¡gracias!

@mikaraento Funcionó para mí, gracias ~

Hola chicos, cosa extraña relevante para este hilo.

Tengo una aplicación angular normal, sin requisitos ni nada, estoy usando el transportador 2.0.0.

Cuando ejecuto las pruebas del sistema en el entorno de ensayo, funciona.
Cuando lo ejecuto localmente me da:
org.openqa.selenium.WebDriverException: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element ... mensaje

Cuando configuro un servidor Nginx para servir el recurso estático en lugar de grunt:server todo funciona.

¿Realmente importa si lo ejecuto con livereload en desarrollo?

Parece que los servidores estáticos se comportan de manera diferente, y grunt sirve algunos 404 o redirecciones, por lo que webdriver se vuelve loco.

Hola a todos,

después de mucho tiempo leyendo y leyendo, encontré una solución que funciona bien para mi proyecto ( corregir el flujo de ejecución del transportador )

  1. cuando abra la aplicación para el transportador, agregue ?protractor-test a la URL ( código del proyecto )
  2. cambie el código de arranque angular para que sea como el siguiente ( código del proyecto )
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]);
}

y finalmente todo de vuelta al trabajo \o/

con copia @juliemr

Recientemente (solo 1-2 semanas) comencé a usar Protractor para probar mi aplicación Angular. Mi aplicación tiene ng-App definida en la etiqueta del cuerpo en la página de inicio de sesión. Mi prueba sigue quejándose diciendo "No se pudo encontrar Angular en la página httP: // (Dirección del sitio web): angular nunca proporcionó resumeBootstrap" Pero la ejecución de la prueba está bien. No estoy seguro del problema (si enciendo el parámetro ignoresync del navegador, entonces funciona bien, pero esta no es la forma correcta), puedo intentar lo que sugiere Juliemr (usar un controlador heredado para navegar), pero solo trato de entender por qué mi aplicación se queja a pesar de que tiene ng-App en la etiqueta del cuerpo. El comportamiento funcional de la aplicación es así... Página de inicio de sesión... Una vez que inicie sesión, haga clic en algún enlace en la página de inicio y se abre otra ventana/pestaña. ¿Podría alguien ayudarme a encontrar los pasos que todos deben verificar para asegurarse de que el arranque se realice de manera automática (uno es el parámetro ng-app en la etiqueta del cuerpo)? ¿Necesito verificar algo en el archivo bootstrap.js (no veo ningún parámetro ng-app en el archivo bootstrap, por lo tanto, verifique). Gracias

¿Hay alguna actualización sobre este tema? ¿Cuáles son las mejores prácticas o métodos para configurar el transportador para que funcione con una aplicación angular que no tiene una aplicación ng? @erkobridee , ¿podría explicar más su ejemplo? ¿Y alguien puede explicar cómo manejar correctamente window.name con respecto a cómo debe esperar el transportador cuando se termina de cargar angular?

@juliemr Con Angular 1.5, el arranque manual es la forma preferida de arranque. ¿Hay bendito apoyo transportador en el camino?

+1 Creo que este problema debería tener mayor prioridad. Si Transportador no funciona con arranque manual, entonces no hay beneficio de usar Transportador. El objetivo de usar Protractor sobre Webdriver es que Protractor maneja toda la sincronización angular por usted.

Tengo el mismo problema. ¿Cualquier actualización?

hola, hay algun plan o proceso para mejorar esto?

Es extraño que no haya comentarios. Tengo aplicaciones que faltan ng-app y no puedo probar
ellos con transportador

El 16 de julio de 2016 a las 5:01 a. m., "millerwx" [email protected] escribió:

hola, hay algun plan o proceso para mejorar esto?


Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/angular/transportador/issues/66#issuecomment-233104701 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

A esta fecha en 2016, esto seguía siendo un problema para mí. Seguí la respuesta magnetizada para resolver el problema. Acabo de hacer algunos cambios. Lo que es bueno y está fuera del alcance de la conversación es rastrear también los redireccionamientos y aterrizar nuevamente dentro de su aplicación. *Lo hice con Babel, pero puedes escribirlo en ES5.

`describe('pantalla de inicio de sesión', ()=>{

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

En caso de que no quiera buscar redireccionamientos, simplemente haga que el controlador duerma y luego comience a trabajar con el transportador.

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

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

De hecho, admitimos el arranque manual, esta información es antigua. Bootstrapping será aún más confiable una vez que también manejemos https://github.com/angular/protractor/issues/3857 .

@sjelin ¿Cuál es la forma documentada de admitir el arranque manual? No puedo encontrar la información relevante para el transportador 5.0.

Estaba enfrentando el mismo problema durante el arranque manual. y encontré la solución para ejecutar con gruñido.
Transportador usado versión 2.5.1.

  1. Menciona esto en tu archivo grunt.

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. Instale npm install grunt-protractor-runner --save-dev y agregue para la tarea de carga grunt.loadNpmTasks('grunt-protractor-runner')

  2. Ejecute el transportador con el siguiente comando:
    grunt protractor
    o con el nombre de la suite
    grunt protractor --suite suite_name

Por favor, hágamelo saber si funciona para usted.

Esto funcionó para mí.
browser.ignoreSynchronization = true;
navegador.get(url);
browser.ignoreSynchronization = false;

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

koshkarov picture koshkarov  ·  3Comentarios

rafalf picture rafalf  ·  3Comentarios

mvolkmann picture mvolkmann  ·  3Comentarios

psech picture psech  ·  3Comentarios

vishalshivnath picture vishalshivnath  ·  3Comentarios