Protractor: 量角器和角度手动引导

创建于 2013-08-30  ·  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']);

bootstrap.js:

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

这在实践中有效,并且 Angular 以正确的方式启动。 当我查看 html 源代码时,我看不到 ng-app 属性出现在 html 元素上。 可能是量角器也没有这样做?

我使用量角器示例配置并更改了相关值以适合我的应用程序:

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-app,所以手动引导的站点会有问题。 希望尽快找到解决此问题的方法。

好的谢谢更新。 当您找到解决方法后,您可以在此问题中发布它吗?

抱歉回复慢 - 你应该可以通过这样做来解决

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('...')重新加载页面,但没有任何效果。

感激地收到任何提示/建议/修复。

@magnetised您需要某种方式告诉您的测试等到登录完成后再尝试其他测试。 我认为发生的事情是您在 Angular 加载到页面之前尝试使用 ptor.findElement 。

您的“可以登录”规范应以等待语句结束,该语句检查您的应用程序的某些条件。 在此处查看示例 - https://github.com/angular/protractor/blob/master/spec/login/viaConfigConf.js

@juliemr Brilliant,效果很好。

我知道量角器会做“等到加载角度”,但我想你不能涵盖所有情况。

再次感谢。

我有完全相同的设置。 @juliemr你介意分享你的解决方案吗? 你的等待条件是什么? 谢谢!

@jorgenfb我想知道你的意思是不是针对我的评论?

我的解决方案只涉及等待 Angular 路由器启动并将 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),即使 Angular 非常简单地加载和运行,Protractor 也找不到 Angular。 简单的解决方案(在不试图找到 Angular 的情况下进行测试)是我们应该采用的方式吗? 它似乎违背了 Protractor 专门用于测试 Angular 应用程序的目的。
编辑:我还应该注意,这个问题中提出的解决方案对我不起作用。

+1 以获得更好的角度手动引导文档

这仍然相关吗?

老实说,我不知道,因为我已经放弃了尝试,也没有时间回去看看是否发生了变化。 考虑到从那时起的版本变化,如果你想关闭它,我不会争辩。 它总是可以稍后重新打开。

我今天刚开始使用量角器,我们的应用程序使用 require.js... 如果在测试手动引导的应用程序方面有任何更新,我对此很感兴趣。 :-)

这里同样的问题。 在 Angular 应用程序之外获取登录页面的应用程序。 先前评论中的解决方法似乎已过时。 非常希望更新关于如何能够测试这种场景的文档。

@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 (硒服务器)
  • 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
  }
};

_量角器.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. 从 document.ready 调用 angular.bootstrap
  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 中未检测到元素。

虽然我使用默认时间间隔作为 defaultTimeoutInterval :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 将我的代码合并/Uglify 到单个 JS 文件,这是 index.html 中引用的唯一脚本,带有脚本标记。 我们称之为 script.js。 在开发中,我运行了一个不同的 Grunt 任务,它只将我需要的文件连接在一起,以便单独、异步地加载其余的 JS 文件,并带有时间戳以防止缓存。 在我开发时,这组连接的脚本替换了 script.js。 在任何一种情况下,我都只从 index.html 加载 script.js,并带有一个 script 标签。

发展

因此,在开发中,我必须进行手动引导。 这很容易,因为我可以将一个我没有连接到生产 JS 中的单个文件包含在内,并且我确保在所有其他 JS 加载后加载此脚本。

bootstrap_dev.js

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

生产/量角器

在生产中,我不能手动引导,因为 Protractor 不喜欢它。 我正在针对我的生产代码运行量角器。 我还从我的 HTML 中删除了“ng-app”属性,因此应用程序不会在开发中过早引导,因此不会发生正常的自动引导。 我在生产中通过在 script.js 中的所有其他 JS 之前放置一个脚本来弥补这一点。

bootstrap_prod.js

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

只需将“myApp”替换为主模块的名称即可。

结论

在开发中,如果您执行上述操作,您可以异步加载您的脚本并执行手动引导。 但是,如果您可以只针对生产代码运行 Protractor 测试(可以通过脚本标签从单个文件加载,只需在加载 Angular 之前添加 ng-app 指令,以便它自动引导。现在您有了异步脚本加载开发中的各种脚本,并为生产代码运行量角器测试。

最终为我工作的是在我的 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 只能被引导一次,第二次调用 angular.boostrap() 或 angular.resumeBoostrap() 将破坏量角器或应用程序。 所以,完全不需要body中的ng-app ,你可以自己调用angular.boostrap(),它会被protractor使用NG_DEFER_BOOTSTRAP处理! 适当地。

窗口名称

确保在加载和启动期间任何应用程序代码都不会更改window.name 。 就我而言, jquery正在这样做,不知道为什么。 从我的项目中完全删除jquery并且测试有效。 这是问题的根源!

现在,我正在搜索,如何在不破坏测试的情况下恢复 jquery,因为我的项目需要它!

最后,

我们的问题是在一个页面上有两个版本的 jQuery(第二个版本是由外部库加载的)。 删除它,只在页面上留下我们的 jQuery,一切正常。

一些代码,可能会有所帮助:

索引.html

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

需要配置

...
 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它对我有用,谢谢~

嗨,伙计们,与此线程相关的奇怪事情。

我有一个常规的 Angular 应用程序 - 没有 requirejs 或任何东西,我使用的是量角器 2.0.0。

当我在登台环境上运行系统测试时,它可以工作。
当我在本地运行它时,它给了我:
org.openqa.selenium.WebDriverException: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element ... 消息

当我将 Nginx 服务器配置为提供静态资源而不是grunt:server时,一切正常。

如果我在开发中使用 livereload 运行它真的很重要吗?

似乎静态服务器的行为不同,并且 grunt 提供一些 404 或重定向,所以 webdriver 发疯了。

大家好,

经过大量时间阅读和阅读,我找到了一种适用于我的项目的解决方案(修复量角器执行流程

  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 应用程序。 我的应用程序在登录页面的 body 标记中定义了 ng-App。 我的测试一直抱怨说“在页面 httP://(网站地址)上找不到 Angular:角度从未提供 resumeBootstrap”但测试执行很好。 不确定这个问题(如果我打开浏览器忽略同步参数,那么它工作正常,但这不是正确的方法),我可以尝试 Juliemr 的建议(使用旧版驱动程序导航),但只是想了解我的应用程序抱怨的原因即使它在 body 标签中有 ng-App。 应用程序功能行为是这样的..登录页面..一旦登录单击主页上的某个链接,它会打开另一个窗口/选项卡。 有人可以帮我找到所有需要验证的步骤,以确保引导是自动完成的(一个是正文标签中的 ng-app 参数)? 我是否需要检查 bootstrap.js 文件中的某些内容(我在 bootstrap 文件中没有看到任何 ng-app 参数,因此需要检查。谢谢

这个问题有更新吗? 配置量角器以使用没有 ng-app 的 Angular 应用程序的最佳实践或方法是什么? @erkobridee你能进一步解释你的例子吗? 有人可以解释如何正确处理 window.name 关于量角器在加载角度时应该如何等待的问题吗?

@juliemr使用 Angular 1.5,手动引导是引导的首选方式。 途中是否有祝福的量角器支持?

+1 我认为这个问题应该是更高的优先级。 如果 Protractor 不能与手动引导程序一起使用,那么使用 Protractor 没有任何好处。 在 Webdriver 上使用 Protractor 的全部意义在于 Protractor 为您处理所有角度同步。

我有同样的问题。 任何更新?

嗨,有什么计划或流程来改善这个吗?

奇怪的是没有反馈。 我的应用程序缺少 ng-app,我无法测试
他们用量角器

2016 年 7 月 16 日上午 5:01,“millerwx” [email protected]写道:

嗨,有什么计划或流程来改善这个吗?


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
https://github.com/angular/protractor/issues/66#issuecomment -233104701,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AOghFs2ff0e-88DLafNGD3iCH8uCOgVaks5qWEmIgaJpZM4A82d7
.

直到 2016 年的这个日期,这对我来说仍然是一个问题。 我按照磁化答案解决了这个问题。 我只是做了一些改变。 对话的好处和超出范围的是跟踪重定向并返回您的应用程序。 *我是用 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 的相关信息。

我在手动引导时遇到了同样的问题。 并找到了使用 grunt 运行的解决方案。
使用量角器 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 = true;
browser.get(url);
browser.ignoreSynchronization = false;

此页面是否有帮助?
0 / 5 - 0 等级