Protractor: Транспортир и угловой ручной бутстрап

Созданный на 30 авг. 2013  ·  49Комментарии  ·  Источник: angular/protractor

У меня возникла проблема при запуске транспортира 0.8 и возникли проблемы с запуском транспортира в нашем приложении, которое загружается вручную.

Вот несколько фрагментов, раскрывающих соответствующие части приложения и настройки:
индекс.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']);

бутстрап.js:

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

Это работает на практике, и Angular запускается правильно. Когда я просматриваю источник html, я не вижу атрибут ng-app, отображаемый в элементе html. Может быть, Protractor также не может этого сделать?

Я использую образец конфигурации транспортира и изменил соответствующие значения в соответствии с моим приложением:

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

Образец теста:

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

Когда я запускаю этот тест, появляются две ошибки:

 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

и

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)

Первая ошибка кажется самой важной, но последняя ошибка тоже весьма интересна. Мне кажется, что строка: ptor.By.input не работает.

Любые идеи?

untriaged discussion

Самый полезный комментарий

@sjelin Каков задокументированный способ поддержки ручной загрузки? Я не могу найти соответствующую информацию для транспортира 5.0.

Все 49 Комментарий

Включен ли код Angular на страницу? Похоже, вам требуются shim, bootstrap и другие, но angular.min.js не отображается.

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

Фрагмент выше находится внутри элемента shim{}, я исключил его из фрагментов, потому что он не показался мне очень важным. Но именно так загружается angular.js.

Привет,

Да, Protractor в настоящее время ожидает ng-приложение, поэтому у сайтов, загружаемых вручную, будут проблемы. Надеемся, что в ближайшее время будет задокументировано обходное решение.

Хорошо, спасибо за обновление. Когда вы найдете обходной путь, вы можете опубликовать его в этом выпуске?

Извините за медленный ответ - вы должны быть в состоянии исправить, выполнив

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

Вы где-то установили переменную ptor? например var ptor = protractor.getInstance() ?

Есть новости по этому поводу? Предложенное вами исправление не работает для меня (транспортир @ 0.10.0, угловой @ 1.0.7)

У меня есть неуклюжая комбинация неуглового экрана входа в систему, за которым следует приложение 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);

    });
});

И мой 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]);
});

Часть входа в систему работает, и я вижу вспышку загрузки защищенной страницы перед ошибками транспортира с UnknownError: javascript error: angular is not defined . Я пытался перезагрузить страницу с помощью driver.get('...') и даже ptor.get('...') , но ничего не работает.

Любые подсказки/советы/исправления с благодарностью получены.

@magnetized , вам понадобится какой-то способ сообщить вашему тесту, чтобы он дождался завершения входа в систему, прежде чем пытаться выполнить другие тесты. Я думаю, что происходит то, что вы пытаетесь использовать ptor.findElement до того, как Angular загрузится на страницу.

Ваша спецификация «Может войти в систему» ​​должна заканчиваться оператором ожидания, который проверяет какое-либо условие для вашего приложения. Посмотрите пример здесь - https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js .

@juliemr Великолепно, это работает отлично.

Я понял, что транспортир будет «ждать, пока загрузится angular», но я думаю, вы не можете охватить все случаи.

Еще раз спасибо.

У меня точно такая же установка. @juliemr , не могли бы вы поделиться своим решением? Каково ваше состояние ожидания? Спасибо!

@jorgenfb Интересно, вы имели в виду, что этот комментарий был адресован мне?

Мое решение просто включало ожидание загрузки углового маршрутизатора и изменение URL-адреса с голого «/», на который вас перенаправляет система входа, на маршрут по умолчанию — в нашем случае «/#view».

Я превратил это в функцию, которую я мог бы повторно использовать во всех тестах:

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

Я не знаю, сработает ли это для вас, это зависит от вашей конфигурации маршрутизации.

@juliemr Спасибо, работает как шарм :)

У меня аналогичная проблема (найденная на SO по адресу: http://stackoverflow.com/questions/19391813/protractor-fails-to-find-angular), когда Protractor не находит Angular, хотя Angular очень просто загружен и работает. Является ли простое решение (тестирование без попыток найти Angular) тем путем, которым мы должны идти? Кажется, это противоречит цели Protractor, специально созданного для тестирования приложений Angular.
редактировать: я также должен отметить, что предложенное решение в этом вопросе не работает для меня.

+1 за лучшую документацию по ручной загрузке angular

это еще актуально?

Я, честно говоря, не знаю, так как с тех пор я отказался от попыток, и у меня действительно нет времени вернуться и посмотреть, изменилось ли что-то. Учитывая изменения версии с тех пор, если вы хотите закрыть это, я бы не стал спорить. Его всегда можно открыть позже.

Я только начал использовать транспортир сегодня, и наше приложение использует require.js ... если были какие-либо обновления в отношении тестирования приложения, которое загружается вручную, я, например, заинтересован. :-)

Та же проблема здесь. Получил приложение со страницей входа вне углового приложения. Обходной путь в предыдущих комментариях кажется устаревшим. Очень хотелось бы обновить документ о том, как проверить такой сценарий.

@hankduan Да, я так думаю.

Я борюсь с этой проблемой прямо сейчас. Предыстория аналогична: у меня есть более крупное приложение, зависимости которого управляются через RequireJS.


Я уже обновил свое приложение, используя window.name='NG_DEFER_BOOTSTRAP!'; и angular.resumeBootstrap() , однако оно все еще не работает.

Сказал это, я не знаю, что делать дальше. Для дальнейших исследований я создал тестовый пример на 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 (Selenium-сервер)
  • npm run-script server (сервер демонстрационных приложений, обслуживающий мини-приложение AJS)
  • npm run-script e2e-test (запускает транспортир...)

Результат

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:

с последующим

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

Последняя ошибка немного странная и, возможно, даже вводит в заблуждение: тест был выполнен (успешный, насколько ожидания были в порядке и что мы видим в браузере).

Перепроверка: если я переключу демонстрационное приложение на неотложенную загрузку с ручным включением (этот вариант доступен в ветке no-deferred ), то оно будет работать успешно.


Я уже пробовал некоторые так называемые «обходные пути»:

  1. http://www.sebdangerfield.me.uk/2014/01/angularjs-protractor-app-already-bootstrapped-error/
    Неуместно или вводящее в заблуждение --> без разницы.
  2. https://github.com/angular/protractor/issues/325#issuecomment -36738048 с использованием protractor.getInstance() и ignoreSynchronization --> без разницы
  3. https://github.com/angular/protractor/issues/325#issuecomment -30701683 исправление clientSideScripts.js/waitForAngular --> без разницы

Вчера я написал свои первые тесты транспортира, и у меня была та же проблема, что и у knalli.

Спасибо за описание примера @knalli. посмотрю на днях

Итак, мой транспортир тестирует все работы (кроме одного сбоя, но это моя вина :-P).
Дайте мне знать, если это не поможет.
Вот моя установка:

версия транспортира:
Версия 1.0.0-rc4
селен отдельно:
до даты
хромдрайвер:
до даты

Определенно соответствующие файлы:

Конфигурация

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

Требовать/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");

Потенциально полезные файлы:

вид по умолчанию (руль)

<!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 (конфигурация сервера)

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

})();

сервер.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 (соответствующая выдержка)

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

файловая структура:

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.

Почти уверен, что это вся моя установка. Решил, что я бы пошел на подробный. Надеюсь, это поможет.

Что мне нужно было сделать, так это:

  1. добавить в URL-адрес часть, относящуюся к тесту, чтобы мой загрузочный код знал, работает ли он «нормально» или как тест транспортира, а затем только для тестов
  2. вызов angular.bootstrap из document.ready
  3. установить имя окна, чтобы оно начиналось с «NG_DEFER_BOOTSTRAP!» перед вызовом angular.bootstrap
  4. установите атрибут «ng-app» в моем элементе верхнего уровня
  5. установить window.angular, чтобы он указывал на angular

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

Могу ли я узнать, почему сценарии транспортира, которые отлично выполняются в браузерах Chrome и Firefox, не могут всегда выполняться в Internet Explorer?

Хотя одни и те же скрипты отлично выполняются в других браузерах, они не могут всегда выполняться одинаково в Internet Explorer. Я получаю частые ошибки, такие как исключение тайм-аута, поскольку
сообщение: 'время ожидания: истекло через 30000 мс ожидания завершения спецификации',
трассировка: { стек: не определено } } ]
а также элементы иногда не обнаруживаются в Internet Explorer.

Хотя я использовал временной интервал по умолчанию как defaultTimeou tInterval:1000000 , в своих сценариях я получаю вышеупомянутые ошибки при выполнении в Internet Explorer...

Может ли кто-нибудь помочь мне в этом?

С уважением,
Сантош Чунчу

Я не вижу проблемы только с ручной загрузкой? Или вы можете запускать приложения с ручной загрузкой уже в Chrome и Firefox?

@hankduan Вы уже изучили тестовый пример? Может быть, мы чем-нибудь сможем помочь?

У меня есть CL, который меняет способ работы начальной загрузки для транспортира (https://github.com/angular/protractor/pull/1155). Его основная цель - исправить ряд других проблем, но я думаю, что это должно исправить (или, по крайней мере, помочь) с ручной загрузкой в ​​​​зависимости от того, как вы загружаетесь. Однако я никогда не устанавливал ручную загрузку для тестирования, так что это чисто теоретически.

Этот PR требует изменения транспортира и изменения Angular, поэтому он может не быть выпущен в ближайшее время.

Эта проблема, кажется, является лучшим результатом поиска при поиске способов ручной загрузки Angular для использования с Protractor, поэтому я решил, что это так же хорошо, как и любое другое решение, чтобы предложить другое решение. Это работает в случае, когда весь ваш интерфейс является приложением Angular (вместо того, чтобы делать что-то вроде начальной загрузки в div после входа в систему, как в приведенных выше примерах).

Хотя можно отложить тесты Protractor до тех пор, пока не будет загружен Angular, в официальных документах Angular указано, что вы не можете выполнять ручную загрузку с помощью Protractor. Я склонен избегать обходных путей, которые, кажется, запрещает официальная документация.

Мое решение

Я использую Grunt для Concat/Uglify моего кода до одного JS-файла, который является единственным скриптом, упомянутым в index.html, с тегом script. Назовем его script.js. В разделе «Разработка» я запускаю другую задачу Grunt, которая объединяет только те файлы, которые мне нужны, чтобы загрузить остальные файлы JS по отдельности, асинхронно и с отметками времени для предотвращения кэширования. Этот объединенный набор скриптов заменяет script.js, пока я разрабатываю. В любом случае я загружаю script.js только из index.html и с тегом script.

Разработка

Итак, в разработке я должен выполнить ручную загрузку. Это легко, потому что я могу включить один файл, который я не объединяю, в производственный JS, и я обязательно загружу этот скрипт после того, как все остальные JS загрузятся.

bootstrap_dev.js

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

Производство / Транспортир

В продакшене я не могу вручную загрузиться, потому что Protractor это не нравится. И я использую Protractor для своего производственного кода. Я также удалил атрибут «ng-app» из моего HTML, чтобы приложение не загружалось преждевременно в процессе разработки, поэтому нормальная автоматическая загрузка не происходит. Я компенсирую это в производстве, помещая скрипт перед всеми остальными JS в script.js.

bootstrap_prod.js

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

Просто замените «myApp» на имя вашего основного модуля.

Вывод

В разработке, если вы сделаете вышеописанное, вы можете загрузить свой скрипт асинхронно и выполнить начальную загрузку вручную. Но если вы согласны запускать тесты Protractor только с производственным кодом (который можно загрузить из одного файла с помощью тега сценария), просто добавьте директиву ng-app перед загрузкой Angular, чтобы он выполнял автоматическую загрузку. Теперь у вас есть асинхронная загрузка ваших различных сценариев в разработке и запуск тестов Protractor для вашего производственного кода.

Что в итоге сработало для меня, так это добавление в мой 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
     }

Если есть лучший способ сделать это, пожалуйста, дайте мне знать =]

Была аналогичная проблема. Нашла полезную информацию:

Процесс загрузки

Нет никакой разницы, как приложение бустрепится в продакшене, но в тестах транспортир это делает:

  1. Изменяет имя окна, поэтому angular приостанавливается перед запуском: NG_DEFER_BOOTSTRAP! (это угловая функция!)
  2. Делает макеты, затем вызывает angular.resumeBoostrap(), и приложение фактически запускается.

Поэтому убедитесь, что ваш производственный код не конфликтует с этим процессом, потому что angular можно повысить только один раз, второй вызов angular.boostrap() или angular.resumeBoostrap() нарушит транспортир или приложение. Таким образом, ng-app в теле вообще не нужен, и вы можете сами вызвать angular.boostrap(), и он будет обрабатываться транспортиром с помощью NG_DEFER_BOOTSTRAP! должным образом.

окно.имя

Убедитесь, что window.name не изменено каким-либо кодом приложения во время загрузки и загрузки. В моем случае это делал jquery , не могу понять, почему. Полностью удалил jquery из моего проекта, и тесты заработали. В этом корень проблемы!

Я пока ищу, как вернуть jquery, не ломая тесты, потому что это нужно моему проекту!

Ну наконец то,

наша проблема заключалась в двух версиях jQuery на одной странице (вторая версия была загружена внешней библиотекой). Удалил его и оставил на странице только наш jQuery и все работает.

Некоторый код, может быть полезен:

index.html

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

конфигурация requirejs

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

прото.js

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

прото/main.js

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

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

и, собственно, тестовая спецификация

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

    });
});

Вывод

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

Ура!

Когда мы перешли с использования ng-app на angular.bootstrap() , добавление rootElement: 'div' в projotractor.conf было единственным изменением, которое нам было нужно, чтобы транспортир снова заработал. Мы используем угловой 1.3.0 и транспортир 1.3.1.

@jongunnip Да, мне тоже помогло, спасибо!

@mikaraento Мне помогло, спасибо~

Привет, ребята, странная вещь, имеющая отношение к этой теме.

У меня есть обычное угловое приложение - никаких требований или чего-то еще, я использую транспортир 2.0.0.

Когда я запускаю системные тесты в промежуточной среде, это работает.
Когда я запускаю его локально, он дает мне:
org.openqa.selenium.WebDriverException: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element ... сообщение

Когда я настраиваю сервер Nginx для обслуживания статического ресурса вместо grunt:server , все работает.

Действительно ли имеет значение, запускаю ли я его с livereload в разработке?

Похоже, что статические серверы ведут себя по-другому, и grunt обслуживает некоторые 404 или редиректы, поэтому веб-драйвер сходит с ума.

Всем привет,

после долгого чтения и чтения я нашел одно решение, которое хорошо работает для моего проекта ( исправить поток выполнения транспортира )

  1. при открытии приложения в транспортир добавьте ?protractor-test к URL-адресу ( код проекта )
  2. измените угловой код начальной загрузки, чтобы он был похож на приведенный ниже ( код проекта )
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]);
}

и, наконец, все снова за работу \o/

с копией @juliemr

Недавно (всего 1-2 недели) я начал использовать Protractor для тестирования моего приложения Angular. В моем приложении ng-App определен в теге body на странице входа. Мой тест продолжает жаловаться, говоря: «Angular не может быть найден на странице httP://(адрес веб-сайта): angular никогда не предоставлял резюмеBootstrap», но выполнение теста в порядке. Не уверен в проблеме (если я включу параметр ignoresync браузера, тогда он работает нормально, но это неправильный способ), я могу попробовать то, что предлагает Juliemr (использовать устаревший драйвер для навигации), но просто пытаюсь понять, почему мое приложение жалуется хотя в теге body есть ng-App. Функциональное поведение приложения выглядит следующим образом.. Страница входа.. После входа в систему щелкните какую-либо ссылку на домашней странице, и откроется другое окно/вкладка. Может ли кто-нибудь помочь мне найти шаги, которые все должны проверить, чтобы убедиться, что начальная загрузка выполняется автоматически (один из параметров ng-app в теге body)? Нужно ли мне что-то проверять в файле bootstrap.js (я не вижу никаких параметров ng-app в файле начальной загрузки, поэтому проверяю. Спасибо

Есть ли обновления по этому вопросу? Каковы передовые методы или методы настройки транспортира для работы с угловым приложением, у которого нет ng-приложения? @erkobridee , не могли бы вы объяснить свой пример подробнее? И может ли кто-нибудь объяснить, как правильно обрабатывать window.name в отношении того, как транспортир должен ждать, когда angular завершит загрузку?

@juliemr В Angular 1.5 ручная загрузка является предпочтительным способом загрузки. Есть ли на пути поддержка благословенного транспортира?

+1 Я думаю, что эта проблема должна быть более приоритетной. Если Protractor не работает с ручной загрузкой, то нет смысла использовать Protractor. Весь смысл использования Protractor поверх Webdriver заключается в том, что Protractor выполняет всю угловую синхронизацию за вас.

У меня такая же проблема. Любое обновление?

привет, есть ли какой-либо план или процесс, чтобы улучшить это?

Странно, что нет обратной связи. У меня в приложениях отсутствует ng-app и я не могу проверить
их с транспортиром

16 июля 2016 г., 5:01, «millerwx» [email protected] написал:

привет, есть ли какой-либо план или процесс, чтобы улучшить это?


Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/angular/protractor/issues/66#issuecomment-233104701 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

На сегодняшний день в 2016 году это все еще было для меня проблемой. Я последовал ответу Magnetized, чтобы решить проблему. Я просто сделал несколько изменений. Что приятно и выходит за рамки разговора, так это отслеживать перенаправления и возвращаться обратно в ваше приложение. * Я сделал это с помощью Babel, но вместо этого вы можете написать это на ES5.

`describe('экран входа', ()=>{

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

Если вы не хотите изучать перенаправления, просто дайте драйверу поспать, а затем начните работать с транспортиром.

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

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

На самом деле мы поддерживаем ручную загрузку, эта информация устарела. Начальная загрузка станет еще более надежной, когда мы также обработаем https://github.com/angular/protractor/issues/3857 .

@sjelin Каков задокументированный способ поддержки ручной загрузки? Я не могу найти соответствующую информацию для транспортира 5.0.

Я столкнулся с той же проблемой при ручной загрузке. и нашел решение работать с ворчанием.
используется транспортир версии 2.5.1.

  1. Упомяните об этом в своем файле 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. Установите npm install grunt-protractor-runner --save-dev и добавьте для задачи загрузки grunt.loadNpmTasks('grunt-protractor-runner')

  2. Запустите транспортир следующей командой:
    grunt protractor
    или с названием люкса
    grunt protractor --suite suite_name

Пожалуйста, дайте мне знать, если это работает для вас.

Это сработало для меня.
browser.ignoreSynchronization = истина;
браузер.получить(URL);
browser.ignoreSynchronization = ложь;

Была ли эта страница полезной?
0 / 5 - 0 рейтинги