重新加载 Angular 应用程序时量角器测试有时会失败
Protractor test sometimes fails when reloading Angular app
我有一个 Protractor 测试,它会启动同一个 Angular 应用程序的重新加载。有时它会在 Travis 构建中失败,但会在构建一两次重新启动后通过。它很少在我的本地机器上失败。 Travis 构建使用 Firefox,但它在我的机器上失败的次数一直在使用 Firefox 和 Selenium 的 chromedriver。
我设置了 rootElement: 'html'
(按照 this GitHub issue on Protractor 中的建议),因为那是 ng-app
所在的位置,但我仍然收到此错误:
Error while waiting for Protractor to sync with the page: "root element (html) has no injector. this may mean it is not inside ng-app."
错误是 angular.element('html').injector()
返回错误的结果,即使 Protractor 代码中的 Angular has loaded. A previous test 证实了这一点。
测试涉及被重定向到另一个 index.html
而恰好是相同的 angular 应用程序。重定向的原因是提供语言选择,然后以该语言重新加载应用程序。
有多个语言环境(为简单起见,此处显示两个)。 app
是文档根,所以app/index.html
是入口点,检测系统语言或者默认为en-gb
,然后重定向到app/<locale>/index.html
。前者不是 Angular 应用程序 (app/
);后者是 (app/<locale>/
) 并链接到 ../common/
用于库和 Angular 模块文件。语言环境文件夹中的 index.html
文件是相同的。
访问文档根目录时会发生什么?
/
-> 重定向 /en-gb/#/language
什么时候选择德语?
/en-gb/#/language
重定向 ../de/#/menu
-> /de/#/menu
目录结构:
└── app
├── common
│ ├── fonts
│ ├── images
│ ├── lib
│ ├── modules
│ └── styles
├── de
│ ├── i18n.js
│ └── index.html
├── en-gb
│ ├── i18n.js
│ └── index.html
└── index.html
测试:
(function () {
'use strict';
describe('Module: app, language screen:', function () {
beforeEach(function () {
browser.get('http://localhost:9000/en-gb/#/language/');
this.$germanChoice = // get the clickable element to select German
this.$buttonContinue = // get the clickable element to continue
});
describe('continue button', function () {
it('should go forward to the menu', function () {
this.$germanChoice.click();
this.$buttonContinue.click();
expect(browser.getCurrentUrl()).toBe('http://localhost:9000/de/#/menu/');
});
});
});
}());
语言环境 index.html
使用缩小文件:
<!doctype html>
<!--[if IE 8]> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js lt-ie10 lt-ie9"> <![endif]-->
<!--[if IE 9]> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js lt-ie10"> <![endif]-->
<!--[if gt IE 9]><!--> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title ng-bind="app.page.title ? app.page.title + ' - ' + app.page.titleBase : app.page.titleBase"></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../common/lib/nouislider/jquery.nouislider.css" />
<!--[if gt IE 8]><!-->
<link rel="stylesheet" href="../common/styles/b8a085fb.main.css">
<!--<![endif]-->
<!--[if lt IE 9]>
<link rel="stylesheet" href="../common/styles/f71e8123.ie.css">
<![endif]-->
<!--[if lt IE 9]>
<script src="../common/scripts/a5663f12.lt-ie9.js"></script>
<![endif]-->
</head>
<body ng-class="{ 'ios6': app.environment.ios6, 'gt-ios6': app.environment.gtIos6, 'cordova': app.environment.cordova }">
<div ng-view="" autoscroll="true"></div>
<script src="../common/scripts/cbd2241e.app.js"></script>
<script src="i18n.js"></script>
</body>
</html>
我偶尔 运行 遇到非 Angular 登录页面的问题(其中一些有几个步骤)。我认为您的语言选择页面可能类似。解决方案是你的测试中的一些逻辑,结合 browser.driver
.
中公开的 Webdriver API
if ('some condition that determines you are on a non-Angular page') {
browser.driver.findElement(by.id('language-choice')).click();
}
测试的最佳条件是:
- 测试是否显示了一些独特的元素。
- 获取当前页面的 URL 并将其与预期值进行比较。
并在您不在 Angular 页面时随时使用 browser.driver
,因为它会绕过 Protractor。否则,Protractor 将查找 Angular,找不到它并抛出错误。您可以使用 browser.driver
执行的所有操作都可以在此处找到,位于菜单的下方区域:http://angular.github.io/protractor/#/api
然后,为了在使用 Protractor 之前等待 Angular 页面出现,请尝试以下代码段:
browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return url.toString().indexOf('my angular page url') !== -1;
}, function(err) {
throw err;
});
}, 5000, 'Timed out waiting for your Angular page to load.');
这在您的 onPrepare
语句中特别有用(只需在开头添加 return
,在 browser.driver.wait
之前)。测试将等待您的 Angular 页面加载,之后您可以根据自己的喜好使用量角器。
稍加改动,同样的代码片段可用于对多步骤非 Angular 介绍性页面做出反应。并且,封装到它自己的整洁的小函数中,它可以在 Protractor 可能被转储到非 Angular 页面的任何地方重复使用。
我有一个 Protractor 测试,它会启动同一个 Angular 应用程序的重新加载。有时它会在 Travis 构建中失败,但会在构建一两次重新启动后通过。它很少在我的本地机器上失败。 Travis 构建使用 Firefox,但它在我的机器上失败的次数一直在使用 Firefox 和 Selenium 的 chromedriver。
我设置了 rootElement: 'html'
(按照 this GitHub issue on Protractor 中的建议),因为那是 ng-app
所在的位置,但我仍然收到此错误:
Error while waiting for Protractor to sync with the page: "root element (html) has no injector. this may mean it is not inside ng-app."
错误是 angular.element('html').injector()
返回错误的结果,即使 Protractor 代码中的 Angular has loaded. A previous test 证实了这一点。
测试涉及被重定向到另一个 index.html
而恰好是相同的 angular 应用程序。重定向的原因是提供语言选择,然后以该语言重新加载应用程序。
有多个语言环境(为简单起见,此处显示两个)。 app
是文档根,所以app/index.html
是入口点,检测系统语言或者默认为en-gb
,然后重定向到app/<locale>/index.html
。前者不是 Angular 应用程序 (app/
);后者是 (app/<locale>/
) 并链接到 ../common/
用于库和 Angular 模块文件。语言环境文件夹中的 index.html
文件是相同的。
访问文档根目录时会发生什么?
/
-> 重定向 /en-gb/#/language
什么时候选择德语?
/en-gb/#/language
重定向 ../de/#/menu
-> /de/#/menu
目录结构:
└── app
├── common
│ ├── fonts
│ ├── images
│ ├── lib
│ ├── modules
│ └── styles
├── de
│ ├── i18n.js
│ └── index.html
├── en-gb
│ ├── i18n.js
│ └── index.html
└── index.html
测试:
(function () {
'use strict';
describe('Module: app, language screen:', function () {
beforeEach(function () {
browser.get('http://localhost:9000/en-gb/#/language/');
this.$germanChoice = // get the clickable element to select German
this.$buttonContinue = // get the clickable element to continue
});
describe('continue button', function () {
it('should go forward to the menu', function () {
this.$germanChoice.click();
this.$buttonContinue.click();
expect(browser.getCurrentUrl()).toBe('http://localhost:9000/de/#/menu/');
});
});
});
}());
语言环境 index.html
使用缩小文件:
<!doctype html>
<!--[if IE 8]> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js lt-ie10 lt-ie9"> <![endif]-->
<!--[if IE 9]> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js lt-ie10"> <![endif]-->
<!--[if gt IE 9]><!--> <html id="ng-app" ng-app="app" lang="{{ app.locale.html }}" class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title ng-bind="app.page.title ? app.page.title + ' - ' + app.page.titleBase : app.page.titleBase"></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../common/lib/nouislider/jquery.nouislider.css" />
<!--[if gt IE 8]><!-->
<link rel="stylesheet" href="../common/styles/b8a085fb.main.css">
<!--<![endif]-->
<!--[if lt IE 9]>
<link rel="stylesheet" href="../common/styles/f71e8123.ie.css">
<![endif]-->
<!--[if lt IE 9]>
<script src="../common/scripts/a5663f12.lt-ie9.js"></script>
<![endif]-->
</head>
<body ng-class="{ 'ios6': app.environment.ios6, 'gt-ios6': app.environment.gtIos6, 'cordova': app.environment.cordova }">
<div ng-view="" autoscroll="true"></div>
<script src="../common/scripts/cbd2241e.app.js"></script>
<script src="i18n.js"></script>
</body>
</html>
我偶尔 运行 遇到非 Angular 登录页面的问题(其中一些有几个步骤)。我认为您的语言选择页面可能类似。解决方案是你的测试中的一些逻辑,结合 browser.driver
.
if ('some condition that determines you are on a non-Angular page') {
browser.driver.findElement(by.id('language-choice')).click();
}
测试的最佳条件是:
- 测试是否显示了一些独特的元素。
- 获取当前页面的 URL 并将其与预期值进行比较。
并在您不在 Angular 页面时随时使用 browser.driver
,因为它会绕过 Protractor。否则,Protractor 将查找 Angular,找不到它并抛出错误。您可以使用 browser.driver
执行的所有操作都可以在此处找到,位于菜单的下方区域:http://angular.github.io/protractor/#/api
然后,为了在使用 Protractor 之前等待 Angular 页面出现,请尝试以下代码段:
browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return url.toString().indexOf('my angular page url') !== -1;
}, function(err) {
throw err;
});
}, 5000, 'Timed out waiting for your Angular page to load.');
这在您的 onPrepare
语句中特别有用(只需在开头添加 return
,在 browser.driver.wait
之前)。测试将等待您的 Angular 页面加载,之后您可以根据自己的喜好使用量角器。
稍加改动,同样的代码片段可用于对多步骤非 Angular 介绍性页面做出反应。并且,封装到它自己的整洁的小函数中,它可以在 Protractor 可能被转储到非 Angular 页面的任何地方重复使用。