Protractor: рдЪрд╛рдВрджрд╛ рдФрд░ рдХреЛрдгреАрдп рдореИрдиреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк

рдХреЛ рдирд┐рд░реНрдорд┐рдд 30 рдЕрдЧре░ 2013  ┬╖  49рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: angular/protractor

рдореБрдЭреЗ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ 0.8 рдЪрд▓рд╛рддреЗ рд╕рдордп рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ рдФрд░ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд┐рдП рдЧрдП рд╣рдорд╛рд░реЗ рдРрдк рдкрд░ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдЪрд▓рд╛рдиреЗ рдореЗрдВ рдкрд░реЗрд╢рд╛рдиреА рд╣реЛ рд░рд╣реА рд╣реИред

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рд╕реЗрдЯрдЕрдк рдХреЗ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рднрд╛рдЧреЛрдВ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреБрдЫ рд╕реНрдирд┐рдкреЗрдЯ рдпрд╣рд╛рдВ рджрд┐рдП рдЧрдП рд╣реИрдВ:
index.html:

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

рдЬреЗрдПрд╕/рдореЗрди.рдЬреЗрдПрд╕:

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

рдмреВрдЯрд╕реНрдЯреНрд░реИрдк.рдЬреЗрдПрд╕:

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

рдпрд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдХреЛрдгреАрдп рдХреЛ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬрдм рдореИрдВ рдПрдЪрдЯреАрдПрдордПрд▓ рд╕реНрд░реЛрдд рджреЗрдЦрддрд╛ рд╣реВрдВ рддреЛ рдореИрдВ рдПрдЪрдЯреАрдПрдордПрд▓ рддрддреНрд╡ рдкрд░ рджрд┐рдЦрд╛рдИ рджреЗрдиреЗ рд╡рд╛рд▓реА рдПрдирдЬреА-рдРрдк рд╡рд┐рд╢реЗрд╖рддрд╛ рдирд╣реАрдВ рджреЗрдЦ рд╕рдХрддрд╛ред рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЪрд╛рдВрджрд╛ рднреА рдРрд╕рд╛ рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓ рд╣реЛ?

рдореИрдВ рдЪрд╛рдВрджрд╛ рдирдореВрдирд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдЕрдкрдиреЗ рдРрдк рдХреЗ рдЕрдиреБрд░реВрдк рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реВрдВ:

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.min.js рдирд╣реАрдВ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред

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

рдКрдкрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╕реНрдирд┐рдкреЗрдЯ рд╢рд┐рдо {} рддрддреНрд╡ рдХреЗ рдЕрдВрджрд░ рд░рд╣рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕реНрдирд┐рдкреЗрдЯ рд╕реЗ рдмрд╛рд╣рд░ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдмрд╣реБрдд рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдирд╣реАрдВ рдерд╛ред рд▓реЗрдХрд┐рди рдЗрд╕ рддрд░рд╣ angular.js рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред

рдирдорд╕реНрддреЗ,

рд╣рд╛рдВ, рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдХреЛ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдПрдХ рдПрдирдЬреА-рдРрдк рдХреА рдЙрдореНрдореАрдж рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХреА рдЧрдИ рд╕рд╛рдЗрдЯреЛрдВ рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рд╣реЛрдЧреАред рдЗрд╕ рджрд╕реНрддрд╛рд╡реЗрдЬ рдХреЗ рд▓рд┐рдП рдЬрд▓реНрдж рд╣реА рдПрдХ рдХрд╛рдордХрд╛рдЬ рдорд┐рд▓рдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИред

рдЕрдкрдбреЗрдЯ рдХреЗ рд▓рд┐рдП рдУрдХреЗ thxред рдЬрдм рдЖрдкрдХреЛ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓ рдЧрдпрд╛ рддреЛ рдХреНрдпрд╛ рдЖрдк рдЙрд╕реЗ рдЗрд╕ рдЕрдВрдХ рдореЗрдВ рдкреЛрд╕реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

рдзреАрдореА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЦреЗрдж рд╣реИ - рдЖрдкрдХреЛ рдРрд╕рд╛ рдХрд░рдХреЗ рдареАрдХ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП

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, [email protected])

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдЧреИрд░-рдХреЛрдгреАрдп рд▓реЙрдЧрд┐рди рд╕реНрдХреНрд░реАрди рдХрд╛ рдПрдХ рдЕрдЬреАрдм рд╕рдВрдпреЛрдЬрди рд╣реИ рдЬрд┐рд╕рдХреЗ рдмрд╛рдж рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд┐рдпрд╛ рдЧрдпрд╛ рдРрдк:

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 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдЖрдкрдХрд╛ 'рд▓реЙрдЧ рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ' рд╕реНрдкреЗрдХ рдПрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬреЛ рдЖрдкрдХреЗ рдРрдк рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╢рд░реНрдд рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗрдВ - https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js

@juliemr рдмреНрд░рд┐рд▓рд┐рдпрдВрдЯ, рдЬреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдореИрдВ рд╕рдордЭ рдЧрдпрд╛ рдерд╛ рдХрд┐ рдЪрд╛рдВрджрд╛ "рдХреЛрдгреАрдп рд▓реЛрдб рд╣реЛрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ" рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рд╕рднреА рдорд╛рдорд▓реЛрдВ рдХреЛ рдХрд╡рд░ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред

рдПрдХ рдмрд╛рд░ рдлрд┐рд░ рдзрдиреНрдпрд╡рд╛рджред

рдореЗрд░реЗ рдкрд╛рд╕ рдмрд┐рд▓реНрдХреБрд▓ рд╡рд╣реА рд╕реЗрдЯрдЕрдк рд╣реИред @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) рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдХреЗ рд╕рд╛рде рдХреЛрдгреАрдп рдирд╣реАрдВ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдХреЛрдгреАрдп рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд▓реЛрдб рдФрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реЛред рдХреНрдпрд╛ рдЖрд╕рд╛рди рд╕рдорд╛рдзрд╛рди рд╣реИ (рдХреЛрдгреАрдп рдЦреЛрдЬрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд┐рдП рдмрд┐рдирд╛ рдкрд░реАрдХреНрд╖рдг) рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рд╣рдореЗрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП? рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдПрдВрдЧреБрд▓рд░ рдРрдкреНрд╕ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдмрдирд╛рдП рдЬрд╛ рд░рд╣реЗ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдХреЛ рд╣рд░рд╛рдиреЗ рдХреЗ рд▓рд┐рдПред
рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдореБрдЭреЗ рдпрд╣ рднреА рдзреНрдпрд╛рди рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╕рдорд╛рдзрд╛рди рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

+1 рдмреЗрд╣рддрд░ рдХреЛрдгреАрдп рдореИрдиреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдкреНрд░рд▓реЗрдЦрди рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП

рдХреНрдпрд╛ рдпрд╣ рдЕрднреА рднреА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИ?

рдореИрдВ рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВрдиреЗ рдХреЛрд╢рд┐рд╢ рдХрд░рдирд╛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рд╣реИ рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╡рд╛рдкрд╕ рдЬрд╛рдиреЗ рдФрд░ рдпрд╣ рджреЗрдЦрдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИ рдХрд┐ рдХреБрдЫ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рддрдм рд╕реЗ рд╕рдВрд╕реНрдХрд░рдг рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП, рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рдмрдВрдж рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рдореИрдВ рдмрд╣рд╕ рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ред рдЗрд╕реЗ рдмрд╛рдж рдореЗрдВ рдХрднреА рднреА рдЦреЛрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдореИрдВрдиреЗ рдЖрдЬ рд╣реА рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд╣рдорд╛рд░рд╛ рдРрдк рдЖрд╡рд╢реНрдпрдХрддрд╛.рдЬреЗрдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ ... рдпрджрд┐ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд┐рдП рдЧрдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдХреЛрдИ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ, рдПрдХ рдХреЗ рд▓рд┐рдП, рджрд┐рд▓рдЪрд╕реНрдкреА рд╣реИред :-)

рдпрд╣рд╛рдВ рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ред рдХреЛрдгреАрдп рдРрдк рдХреЗ рдмрд╛рд╣рд░ рд▓реЙрдЧрд┐рди рдкреЗрдЬ рдХреЗ рд╕рд╛рде рдЖрд╡реЗрджрди рдорд┐рд▓рд╛ред рдкрд┐рдЫрд▓реА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рд╕рдорд╛рдзрд╛рди рдкреБрд░рд╛рдирд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред рдЙрд╕ рддрд░рд╣ рдХреЗ рдкрд░рд┐рджреГрд╢реНрдп рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрджреНрдпрддрди рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдХреЛ рдмрд╣реБрдд рдкрд╕рдВрдж рдХрд░реЗрдВрдЧреЗред

@hankduan рд╣рд╛рдБ, рдореБрдЭреЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИред

рдореИрдВ рдЕрднреА рдЗрд╕ рдореБрджреНрджреЗ рд╕реЗ рдЬреВрдЭ рд░рд╣рд╛ рд╣реВрдВред рдкреГрд╖реНрдарднреВрдорд┐ рд╕рдорд╛рди рд╣реИ: рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдмрдбрд╝рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ рдЬреЛ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ RequJS рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХреА рдЬрд╛рддреА рд╣реИрдВред


рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рд╣реА 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 (рд╕реЗрд▓реЗрдирд┐рдпрдо рд╕рд░реНрд╡рд░)
  • 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 -> рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ

рдореИрдВрдиреЗ рдХрд▓ рдЕрдкрдирд╛ рдкрд╣рд▓рд╛ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрд╛ рдерд╛ рдФрд░ рдирд▓реНрд▓реА рдЬреИрд╕реА рд╣реА рд╕рдорд╕реНрдпрд╛ рдереАред

@knali рдЙрджрд╛рд╣рд░рдг рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдореИрдВ рдХреБрдЫ рджрд┐рдиреЛрдВ рдореЗрдВ рджреЗрдЦ рд▓реВрдВрдЧрд╛

рддреЛ рдореЗрд░рд╛ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рд╕рднреА рдХрд╛рдореЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реИ (рдПрдХ рд╡рд┐рдлрд▓рддрд╛ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд▓реЗрдХрд┐рди рдпрд╣ рдореЗрд░реА рдЧрд▓рддреА рд╣реИ :-P)ред
рдореБрдЭреЗ рдмрддрд╛рдПрдВ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рдорджрдж рдирд╣реАрдВ рдХрд░рддрд╛/рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
рдпрд╣рд╛рдБ рдореЗрд░рд╛ рд╕реЗрдЯрдЕрдк рд╣реИ:

рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рд╕рдВрд╕реНрдХрд░рдг:
рд╕рдВрд╕реНрдХрд░рдг 1.0.0-рдЖрд░рд╕реА4
рд╕реЗрд▓реЗрдирд┐рдпрдо рд╕реНрдЯреИрдВрдбрдЕрд▓реЛрди:
рддрд╛рд░реАрдЦ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ
рдХреНрд░реЛрдордбреНрд░рд╛рдЗрд╡рд░:
рддрд╛рд░реАрдЦ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ

рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдлрд╛рдЗрд▓реЗрдВ:

рдХреЙрдиреНрдлрд╝рд┐рдЧ

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

_рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░.рдЬреЗрдПрд╕

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

рдЖрд╡рд╢реНрдпрдХрддрд╛/рдореБрдЦреНрдп.рдЬреЗрдПрд╕:

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 >

рдХрдВрдЯреНрд░реЛрд▓рд░.рдЬреЗрдПрд╕ (рд╕рд░реНрд╡рд░ рдХреЙрдиреНрдлрд┐рдЧ)

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

})();

рд╕рд░реНрд╡рд░.рдЬреЗрдПрд╕

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. document.ready . рд╕реЗ angular.bootstrap рдкрд░ рдХреЙрд▓ рдХрд░реЗрдВ
  3. рд╡рд┐рдВрдбреЛ рдХрд╛ рдирд╛рдо 'NG_DEFER_BOOTSTRAP!' рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ рдХрд░реЗрдВ angular.bootstrap . рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ
  4. рдореЗрд░реЗ рдЕрдкреВрд░реНрдг рддрддреНрд╡ рдкрд░ 'рдПрдирдЬреА-рдРрдк' рд╡рд┐рд╢реЗрд╖рддрд╛ рд╕реЗрдЯ рдХрд░реЗрдВ
  5. рд╡рд┐рдВрдбреЛ рд╕реЗрдЯ рдХрд░реЗрдВред рдХреЛрдгреАрдп рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдгреАрдп

рджреЗрдЦреЗрдВ https://github.com/mikaraento/protractor-reuse/blob/master/index.js

рдХреНрдпрд╛ рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдХреНрд░реЛрдо рдФрд░ рдлрд╝рд╛рдпрд░рдлрд╝реЙрдХреНрд╕ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣рдореЗрд╢рд╛ рдЗрдВрдЯрд░рдиреЗрдЯ рдПрдХреНрд╕рдкреНрд▓реЛрд░рд░ рдореЗрдВ рдХреНрдпреЛрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ?

рд╣рд╛рд▓рд╛рдВрдХрд┐ рд╡рд╣реА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЕрдиреНрдп рдмреНрд░рд╛рдЙрдЬрд╝рд░реЛрдВ рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛ рд░рд╣реА рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрдВрдЯрд░рдиреЗрдЯ рдПрдХреНрд╕рдкреНрд▓реЛрд░рд░ рдореЗрдВ рд╣рдореЗрд╢рд╛ рдПрдХ рдЬреИрд╕реА рдирд╣реАрдВ рдЪрд▓ рд╕рдХрддреА рд╣реИрдВред рдореБрдЭреЗ рдмрд╛рд░-рдмрд╛рд░ рддреНрд░реБрдЯрд┐рдпрд╛рдБ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ рдЬреИрд╕реЗ рдЯрд╛рдЗрдо рдЖрдЙрдЯ рдЕрдкрд╡рд╛рдж:
рд╕рдВрджреЗрд╢: 'рд╕рдордп рд╕рдорд╛рдкреНрдд: 30000 рдорд┐рд╕реЗ рдХреЗ рдмрд╛рдж рд╕рдордп рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдХрд▓реНрдкрдирд╛ рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рд╣реИтАЩ,
рдЯреНрд░реЗрд╕: тАЛтАЛ{рд╕реНрдЯреИрдХ: рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд}}]
рдФрд░ рдХрднреА-рдХрднреА рдЗрдВрдЯрд░рдиреЗрдЯ рдПрдХреНрд╕рдкреНрд▓реЛрд░рд░ рдореЗрдВ рддрддреНрд╡реЛрдВ рдХрд╛ рдкрддрд╛ рдирд╣реАрдВ рдЪрд▓ рд░рд╣рд╛ рд╣реИред

рд╣рд╛рд▓рд╛рдБрдХрд┐ рдореИрдВрдиреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рдордп рдЕрдВрддрд░рд╛рд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ defaultTimeou tInterval:1000000 рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рд╣реИ, рдореЗрд░реА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдореБрдЭреЗ рдЗрдВрдЯрд░рдиреЗрдЯ рдПрдХреНрд╕рдкреНрд▓реЛрд░рд░ рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╕рдордп рдЙрдкрд░реНрдпреБрдХреНрдд рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ ...

рдХреНрдпрд╛ рдХреЛрдИ рдЗрд╕ рдкрд░ рдореЗрд░реА рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИ?

рд╕рд╛рджрд░,
рд╕рдВрддреЛрд╖ рдЪреБрдирдЪреБ

рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдореЗрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рд╣реИ? рдпрд╛ рдХреНрдпрд╛ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреНрд░реЛрдо рдФрд░ рдлрд╝рд╛рдпрд░рдлрд╝реЙрдХреНрд╕ рдореЗрдВ рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд┐рдП рдЧрдП рдРрдкреНрд╕ рдЪрд▓рд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВ?

@hankduan рдХреНрдпрд╛ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реА рд╣реИ? рд╢рд╛рдпрдж рд╣рдо рдХреБрдЫ рдорджрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рд╕реАрдПрд▓ рдЖрдЙрдЯ рд╣реИ рдЬреЛ рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдХреЗ рд▓рд┐рдП рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ (https://github.com/angular/protractor/pull/1155)ред рдЗрд╕рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдХрдИ рдЕрдиреНрдп рдореБрджреНрджреЛрдВ рдХреЛ рдареАрдХ рдХрд░рдирд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХреЗ рд╕рд╛рде рдЗрд╕реЗ рдареАрдХ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП (рдпрд╛ рдХрдо рд╕реЗ рдХрдо рдорджрдж)ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдореИрдВрдиреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдХрднреА рднреА рдореИрдиреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рд╕реЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рд╕рд┐рд░реНрдл рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд╣реИред

рдЗрд╕ рдкреАрдЖрд░ рдХреЛ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдореЗрдВ рдмрджрд▓рд╛рд╡ рдФрд░ рдПрдВрдЧреБрд▓рд░ рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдереЛрдбрд╝реЗ рд╕рдордп рдореЗрдВ рдЬрд╛рд░реА рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдПрдВрдЧреБрд▓рд░ рдХреЗ рддрд░реАрдХреЛрдВ рдХреА рддрд▓рд╛рд╢ рдХрд░рддреЗ рд╕рдордп рдпрд╣ рд╕рдорд╕реНрдпрд╛ рд╢реАрд░реНрд╖ рдЦреЛрдЬ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рддреАрдд рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рд▓рдЧрд╛ рдХрд┐ рдпрд╣ рдХрд┐рд╕реА рдЕрдиреНрдп рд╕рдорд╛рдзрд╛рди рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрддрдиреА рд╣реА рдЕрдЪреНрдЫреА рдЬрдЧрд╣ рд╣реИред рдпрд╣ рдЙрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдЖрдкрдХрд╛ рдкреВрд░рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдПрдХ рдХреЛрдгреАрдп рдРрдк рд╣реИ (рд▓реЙрдЧрд┐рди рдХреЗ рдмрд╛рдж рдПрдХ div рдкрд░ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдЬреИрд╕рд╛ рдХреБрдЫ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреА рддрд░рд╣)ред

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреЛрдгреАрдп рд▓реЛрдб рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рддрдХ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рджреЗрд░реА рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдХреЛрдгреАрдп рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдмрддрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдЖрдк рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХреЗ рд╕рд╛рде рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВ рдЙрди рдХрд╛рдордХрд╛рдЬ рд╕реЗ рджреВрд░ рднрд╛рдЧрддрд╛ рд╣реВрдВ рдЬреЛ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рдордирд╛ рдХрд░рддреЗ рд╣реИрдВред

рдореЗрд░рд╛ рд╕рдорд╛рдзрд╛рди

рдореИрдВ рдЧреНрд░рдВрдЯ рдЯреВ рдХреЙрдирдХреИрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ/рдЕрдкрдиреЗ рдХреЛрдб рдХреЛ рдПрдХ рдЬреЗрдПрд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдиреАрдЪреЗ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЬреЛ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЯреИрдЧ рдХреЗ рд╕рд╛рде index.html рдореЗрдВ рд╕рдВрджрд░реНрднрд┐рдд рдПрдХрдорд╛рддреНрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣реИред рдЪрд▓рд┐рдП рдЗрд╕реЗ script.js рдХрд╣рддреЗ рд╣реИрдВред рд╡рд┐рдХрд╛рд╕ рдореЗрдВ, рдореИрдВ рдПрдХ рдЕрд▓рдЧ рдЧреНрд░рдВрдЯ рдХрд╛рд░реНрдп рдЪрд▓рд╛рддрд╛ рд╣реВрдВ, рдЬреЛ рдХреИрд╢рд┐рдВрдЧ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ, рдЕрд╕реАрдорд┐рдд рд░реВрдк рд╕реЗ, рдФрд░ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЗ рд╕рд╛рде рд╢реЗрд╖ рдЬреЗрдПрд╕ рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдЖрд╡рд╢реНрдпрдХ рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдХ рд╕рд╛рде рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдЬрдм рдореИрдВ рд╡рд┐рдХрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рддреЛ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдпрд╣ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕реЗрдЯ script.js рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рдкрд░рд┐рджреГрд╢реНрдп рдореЗрдВ, рдореИрдВ рдХреЗрд╡рд▓ index.html рд╕реЗ script.js рд▓реЛрдб рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдФрд░ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЯреИрдЧ рдХреЗ рд╕рд╛рдеред

рд╡рд┐рдХрд╛рд╕

рддреЛ, рд╡рд┐рдХрд╛рд╕ рдореЗрдВ, рдореБрдЭреЗ рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд░рдирд╛ рд╣реИред рдпрд╣ рдЖрд╕рд╛рди рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдПрдХ рдПрдХрд▓ рдлрд╝рд╛рдЗрд▓ рд╢рд╛рдорд┐рд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдЬрд┐рд╕реЗ рдореИрдВ рдкреНрд░реЛрдбрдХреНрд╢рди рдЬреЗрдПрд╕ рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛, рдФрд░ рдЕрдиреНрдп рд╕рднреА рдЬреЗрдПрд╕ рд▓реЛрдб рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдореИрдВ рдЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рд▓реЛрдб рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реВрдВред

рдмреВрдЯрд╕реНрдЯреНрд░реИрдк_рджреЗрд╡.рдЬреЗрдПрд╕

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

рдЙрддреНрдкрд╛рджрди / рдЪрд╛рдВрджрд╛

рдЙрддреНрдкрд╛рджрди рдореЗрдВ, рдореИрдВ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рдХреНрдпреЛрдВрдХрд┐ рдЪрд╛рдВрджрд╛ рдЗрд╕реЗ рдкрд╕рдВрдж рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдФрд░ рдореИрдВ рдЕрдкрдиреЗ рдкреНрд░реЛрдбрдХреНрд╢рди рдХреЛрдб рдХреЗ рдЦрд┐рд▓рд╛рдл рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдЪрд▓рд╛ рд░рд╣рд╛ рд╣реВрдВред рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдПрдЪрдЯреАрдПрдордПрд▓ рд╕реЗ "рдПрдирдЬреА-рдРрдк" рд╡рд┐рд╢реЗрд╖рддрд╛ рднреА рд╣рдЯрд╛ рджреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕рдордп рд╕реЗ рдкрд╣рд▓реЗ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдирд╣реАрдВ рд╣реЛ рд░рд╣рд╛ рд╣реИред рдореИрдВ script.js рдореЗрдВ рдЕрдиреНрдп рд╕рднреА JS рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдбрд╛рд▓рдХрд░ рдкреНрд░реЛрдбрдХреНрд╢рди рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд░рддрд╛ рд╣реВрдВред

рдмреВрдЯрд╕реНрдЯреНрд░реИрдк_рдкреНрд░реЛрдб.рдЬреЗрдПрд╕

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

рдмрд╕ "myApp" рдХреЛ рдЕрдкрдиреЗ рдореБрдЦреНрдп рдореЙрдбреНрдпреВрд▓ рдХреЗ рдирд╛рдо рд╕реЗ рдмрджрд▓реЗрдВред

рдирд┐рд╖реНрдХрд░реНрд╖

рд╡рд┐рдХрд╛рд╕ рдореЗрдВ, рдпрджрд┐ рдЖрдк рдЙрдкрд░реЛрдХреНрдд рдХрд╛рд░реНрдп рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЕрдкрдиреА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдореИрдиреНрдпреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк рдЙрддреНрдкрд╛рджрди рдХреЛрдб рдХреЗ рдЦрд┐рд▓рд╛рдл рдХреЗрд╡рд▓ рдЕрдкрдиреЗ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдиреЗ рдХреЗ рд╕рд╛рде рдареАрдХ рд╣реИрдВ (рдЬрд┐рд╕реЗ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЯреИрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдХреЛрдгреАрдп рд▓реЛрдб рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдмрд╕ рдПрдирдЬреА-рдРрдк рдирд┐рд░реНрджреЗрд╢ рдЬреЛрдбрд╝реЗрдВ рддрд╛рдХрд┐ рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдХрд░ рд╕рдХреЗред рдЕрдм рдЖрдкрдХреЗ рдкрд╛рд╕ рд╣реИ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдЖрдкрдХреА рд╡рд┐рднрд┐рдиреНрди рд▓рд┐рдкрд┐рдпреЛрдВ рдХреА рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓реЛрдбрд┐рдВрдЧ, рдФрд░ рдЖрдкрдХреЗ рдЙрддреНрдкрд╛рджрди рдХреЛрдб рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдирд╛ред

рдореЗрд░реЗ рд▓рд┐рдП рдЬреЛ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рдерд╛, рд╡рд╣ рдореЗрд░реЗ 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. рдкрд░рд┐рд╡рд░реНрддрди window.name рдЗрд╕рд▓рд┐рдП рдХреЛрдгреАрдп рдкреНрд░рд╛рд░рдВрдн рд╕реЗ рдкрд╣рд▓реЗ рд░реБрдХрд╛ рд╣реБрдЖ рд╣реИ: NG_DEFER_BOOTSTRAP! (рдпрд╣ рдХреЛрдгреАрдп рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИ!)
  2. рдирдХрд▓реА рд╕рд╛рдорд╛рди рдХрд░рддрд╛ рд╣реИ, рдлрд┐рд░ angular.resumeBoostrap() рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдРрдк рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИред

рдЗрд╕рд▓рд┐рдП рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХрд╛ рдЙрддреНрдкрд╛рджрди рдХреЛрдб рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рд╛рде рд╡рд┐рд░реЛрдз рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХреЛрдгреАрдп рдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдмрдврд╝рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, angular.boostrap() рдпрд╛ angular.resumeBoostrap() рдкрд░ рджреВрд╕рд░реА рдХреЙрд▓ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдпрд╛ рдРрдк рдХреЛ рддреЛрдбрд╝ рджреЗрдЧреАред рддреЛ, рд╢рд░реАрд░ рдореЗрдВ рдПрдирдЬреА-рдРрдк рдХреА рдмрд┐рд▓реНрдХреБрд▓ рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЖрдк 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>

рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдБ рд╡рд┐рдиреНрдпрд╛рд╕

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

рдкреНрд░реЛрдЯреЛ.рдЬреЗрдПрд╕

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

рдкреНрд░реЛрдЯреЛ/рдореЗрди.рдЬреЗрдПрд╕

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() #$ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд┐рдпрд╛, рддреЛ projotractor.conf рдореЗрдВ rootElement: 'div' рдЬреЛрдбрд╝рдирд╛ рд╣реА рдПрдХрдорд╛рддреНрд░ рдмрджрд▓рд╛рд╡ рдерд╛ рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рдВрджрд╛ рдХреЛ рдлрд┐рд░ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдерд╛ред рд╣рдо рдХреЛрдгреАрдп 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 ... рд╕рдВрджреЗрд╢

рдЬрдм рдореИрдВ grunt:server рдХреЗ рдмрдЬрд╛рдп рд╕реНрдерд┐рд░ рд╕рдВрд╕рд╛рдзрди рдХреА рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдПрдХ Nginx рд╕рд░реНрд╡рд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рд╕рдмрдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдХреНрдпрд╛ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорд╛рдпрдиреЗ рд░рдЦрддрд╛ рд╣реИ рдЕрдЧрд░ рдореИрдВ рдЗрд╕реЗ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рд▓рд╛рдЗрд╡рд░реЗрд▓реЛрдб рдХреЗ рд╕рд╛рде рдЪрд▓рд╛рддрд╛ рд╣реВрдВ?

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕реНрдерд┐рд░ рд╕рд░реНрд╡рд░ рдЕрд▓рдЧ рддрд░рд╣ рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЧреНрд░рдВрдЯ рдХреБрдЫ 404 рдпрд╛ рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рдХреА рд╕реЗрд╡рд╛ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╡реЗрдмрдбреНрд░рд╛рдЗрд╡рд░ рдкрд╛рдЧрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред

рдирдорд╕реНрддреЗ,

рдмрд╣реБрдд рд╕рдордп рдкрдврд╝рдиреЗ рдФрд░ рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж, рдореБрдЭреЗ рдПрдХ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛ рдЬреЛ рдореЗрд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ ( рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдареАрдХ рдХрд░реЗрдВ )

  1. рдЬрдм рдкреНрд░реЛрдЯреИрдХреНрдЯрд░ рдХреЗ рд▓рд┐рдП рдРрдк рдЦреЛрд▓реЗрдВ рддреЛ URL рдореЗрдВ ?protractor-test рдЬреЛрдбрд╝реЗрдВ ( рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛрдб )
  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 рд╕рдкреНрддрд╛рд╣) рдЕрдкрдиреЗ рдХреЛрдгреАрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рдореЗрд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рд▓реЙрдЧрд┐рди рдкреЗрдЬ рдкрд░ рдмреЙрдбреА рдЯреИрдЧ рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдПрдирдЬреА-рдРрдк рд╣реИред рдореЗрд░рд╛ рдЯреЗрд╕реНрдЯ рдпрд╣ рдХрд╣рддреЗ рд╣реБрдП рд╢рд┐рдХрд╛рдпрдд рдХрд░рддрд╛ рд░рд╣рддрд╛ рд╣реИ рдХрд┐ "рдкреГрд╖реНрда рдкрд░ рдХреЛрдгреАрдп рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: // (рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрддрд╛): рдХреЛрдгреАрдп рдиреЗ рдХрднреА рднреА рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд┐рдпрд╛рдмреВрдЯрд╕реНрдЯреНрд░реИрдк" рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдг рдирд┐рд╖реНрдкрд╛рджрди рдареАрдХ рд╣реИред рдЗрд╕ рдореБрджреНрджреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИ (рдпрджрд┐ рдореИрдВ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЗрдЧреНрдиреЛрд░рд╕рд┐рдВрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдЪрд╛рд▓реВ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдпрд╣ рдареАрдХ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕рд╣реА рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ), рдореИрдВ рдХреЛрд╢рд┐рд╢ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ рдЬреВрд▓рд┐рдорд░ рдХреНрдпрд╛ рд╕реБрдЭрд╛рд╡ рджреЗ рд░рд╣рд╛ рд╣реИ (рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд░рд╛рд╕рдд рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ), рд▓реЗрдХрд┐рди рд╕рд┐рд░реНрдл рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реИ рдХрд┐ рдореЗрд░рд╛ рдРрдк рд╢рд┐рдХрд╛рдпрдд рдХреНрдпреЛрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ рднрд▓реЗ рд╣реА рдЗрд╕рдореЗрдВ рдмреЙрдбреА рдЯреИрдЧ рдореЗрдВ рдПрдирдЬреА-рдРрдк рд╣реЛред рдРрдк рдлрдВрдХреНрд╢рдирд▓ рдмрд┐рд╣реЗрд╡рд┐рдпрд░ рдЗрд╕ рддрд░рд╣ рд╣реИ.. рд▓реЙрдЧ рдЗрди рдкреЗрдЬ..рд▓реЙрдЧ рдЗрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╣реЛрдо рдкреЗрдЬ рдкрд░ рдХрд┐рд╕реА рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ рдФрд░ рдпрд╣ рдПрдХ рдФрд░ рд╡рд┐рдВрдбреЛ / рдЯреИрдм рдЦреЛрд▓рддрд╛ рд╣реИред рдХреНрдпрд╛ рдХреЛрдИ рдореБрдЭреЗ рдЙрди рдЪрд░рдгреЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рддрд░реАрдХреЗ рд╕реЗ рдХреА рдЬрд╛рддреА рд╣реИ (рдмреЙрдбреА рдЯреИрдЧ рдореЗрдВ рдПрдХ рдПрдирдЬреА-рдРрдк рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ)? рдХреНрдпрд╛ рдореБрдЭреЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк.рдЬреЗрдПрд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХреБрдЫ рдЬрд╛рдБрдЪрдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ (рдореБрдЭреЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХреЛрдИ рдПрдирдЬреА-рдРрдк рдкреИрд░рд╛рдореАрдЯрд░ рдирд╣реАрдВ рджрд┐рдЦ рд░рд╣рд╛ рд╣реИ рдЗрд╕рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░ рд░рд╣рд╛ рд╣реВрдБред рдзрдиреНрдпрд╡рд╛рдж

рдХреНрдпрд╛ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдХреЛрдИ рдЕрдкрдбреЗрдЯ рд╣реИ? рдПрдХ рдХреЛрдгреАрдп рдРрдк рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд░реНрд╡реЛрддреНрддрдо рдЕрднреНрдпрд╛рд╕ рдпрд╛ рддрд░реАрдХреЗ рдХреНрдпрд╛ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдПрдирдЬреА-рдРрдк рдирд╣реАрдВ рд╣реИ? @erkobridee рдХреНрдпрд╛ рдЖрдк рдЕрдкрдирд╛ рдЙрджрд╛рд╣рд░рдг рдЖрдЧреЗ рд╕рдордЭрд╛ рд╕рдХрддреЗ рд╣реИрдВ? рдФрд░ рдХреНрдпрд╛ рдХреЛрдИ рд╕рдордЭрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдХреЛрдгреАрдп рд▓реЛрдб рд╣реЛрдиреЗ рдкрд░ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХреЛ рдХреИрд╕реЗ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ window.name рдХреЛ рдареАрдХ рд╕реЗ рдХреИрд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рд╣реИ?

@juliemr рдХреЛрдгреАрдп 1.5 рдХреЗ рд╕рд╛рде, рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреВрдЯрд╕реНрдЯреНрд░реИрдкрд┐рдВрдЧ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХрд╛ рдкрд╕рдВрджреАрджрд╛ рддрд░реАрдХрд╛ рд╣реИред рдХреНрдпрд╛ рд░рд╛рд╕реНрддреЗ рдореЗрдВ рдзрдиреНрдп рдЪрд╛рдВрджрд╛ рдХрд╛ рд╕рдорд░реНрдерди рд╣реИ?

+1 рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдЙрдЪреНрдЪ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреА рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдореИрдиреБрдЕрд▓ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рд▓рд╛рдн рдирд╣реАрдВ рд╣реИред рд╡реЗрдмрдбреНрд░рд╛рдЗрд╡рд░ рдкрд░ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреВрд░рд╛ рдмрд┐рдВрджреБ рдпрд╣ рд╣реИ рдХрд┐ рдкреНрд░реЛрдЯреНрд░реИрдХреНрдЯрд░ рдЖрдкрдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЛрдгреАрдп рд╕рд┐рдВрдХ рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред

рдореЗрд░реЗ рд╕рд╛рде рднреА рд╡рд╣реА рджрд┐рдХреНрдХрдд рд╣реИред рдХрд┐рд╕реА рднреА рдЕрджреНрдпрддрди?

рдирдорд╕реНрддреЗ, рдХреНрдпрд╛ рдЗрд╕реЗ рд╕реБрдзрд╛рд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдпреЛрдЬрдирд╛ рдпрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИ?

рдЕрдЬреАрдм рдХреЛрдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рд╣реИред рдореЗрд░реЗ рдкрд╛рд╕ рдПрдирдЬреА-рдРрдк рдЧрд╛рдпрдм рдРрдкреНрд╕ рд╣реИрдВ рдФрд░ рдореИрдВ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛
рдЙрдиреНрд╣реЗрдВ рдЪрд╛рдВрджрд╛ рдХреЗ рд╕рд╛рде

16 рдЬреБрд▓рд╛рдИ 2016 рдХреЛ рд╕реБрдмрд╣ 5:01 рдмрдЬреЗ, "рдорд┐рд▓рд░рд╡рдХреНрд╕" рдиреЛрдЯрд┐рдлрд┐рдХреЗрд╢рди @github.com рдиреЗ рд▓рд┐рдЦрд╛:

рдирдорд╕реНрддреЗ, рдХреНрдпрд╛ рдЗрд╕реЗ рд╕реБрдзрд╛рд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдпреЛрдЬрдирд╛ рдпрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИ?

-
рдЖрдк рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдиреЗ рдЯрд┐рдкреНрдкрдгреА рдХреА рдереАред
рдЗрд╕ рдИрдореЗрд▓ рдХрд╛ рд╕реАрдзреЗ рдЙрддреНрддрд░ рджреЗрдВ, рдЗрд╕реЗ GitHub рдкрд░ рджреЗрдЦреЗрдВ
https://github.com/angular/protractor/issues/66#issuecomment -233104701,
рдпрд╛ рдереНрд░реЗрдб рдХреЛ рдореНрдпреВрдЯ рдХрд░реЗрдВ
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

2016 рдореЗрдВ рдЖрдЬ рддрдХ, рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдЕрднреА рднреА рдПрдХ рд╕рдорд╕реНрдпрд╛ рдереАред рдореИрдВрдиреЗ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪреБрдВрдмрдХреАрдп рдЙрддреНрддрд░ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд┐рдпрд╛ред рдореИрдВрдиреЗ рдЕрднреА рдХреБрдЫ рдмрджрд▓рд╛рд╡ рдХрд┐рдП рд╣реИрдВред рдХреНрдпрд╛ рдЕрдЪреНрдЫрд╛ рд╣реИ рдФрд░ рдмрд╛рддрдЪреАрдд рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рдмрд╛рд╣рд░ рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдирд╛ рдФрд░ рдЕрдкрдиреЗ рдРрдк рдХреЗ рдЕрдВрджрд░ рд╡рд╛рдкрд╕ рдЖрдирд╛ рд╣реИред *рдореИрдВрдиреЗ рдЗрд╕реЗ рдмреИрдмреЗрд▓ рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЖрдк рдЗрд╕реЗ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп ES5 рдореЗрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВред

рд╡рд░реНрдгрди рдХрд░реЗрдВ ('рд▓реЙрдЧрд┐рди рд╕реНрдХреНрд░реАрди', () => {

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.onрддреИрдпрд╛рд░ рдХрд░реЗрдВ

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.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.ignoreрд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди = рд╕рдЪ;
рдмреНрд░рд╛рдЙрдЬрд░.рдЧреЗрдЯ (рдпреВрдЖрд░рдПрд▓);
browser.ignoreрд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди = рдЭреВрдард╛;

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

amedvedjev picture amedvedjev  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

psech picture psech  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

codef0rmer picture codef0rmer  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

tmeneau picture tmeneau  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jmcollin78 picture jmcollin78  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ