使用 MEANJS 导航的 Protractor e2e 测试
Protractor e2e tests with MEANJS navigation
大部分内容我仍处于学习模式。
我已经安装了MeanJS and am using the navigation that came out of the box. I am starting to implement end-to-end tests using Protractor and Jasmine。
我希望我的量角器测试与导航组件交互。在整页中,它很宽。在移动尺寸中,它是一个汉堡包。非常感谢任何有关编写/考虑测试的好方法的一般信息。
以下是我目前遇到的一些问题:
模拟菜单项选择
我想使用量角器模拟用户点击菜单项。 HTML 为全屏宽度呈现...
<li data-ng-repeat="item in menu.items | orderBy: 'position'"
data-ng-if="item.shouldRender(authentication.user);"
ng-switch="item.menuItemType" ui-route="/admin" class="dropdown"
ng-class="{active: ($uiRoute)}"
dropdown="item.menuItemType === 'dropdown'">
<!-- THIS NEEDS TO BE CLICKED TO MAKE THE CHILD LINKS VISIBLE -->
<a ng-switch-when="dropdown" class="dropdown-toggle ng-scope"
dropdown-toggle="" aria-haspopup="true" aria-expanded="false">
<span data-ng-bind="item.title" class="ng-binding">Admin</span>
<b class="caret"></b>
</a>
<ul ng-switch-when="dropdown" class="dropdown-menu ng-scope">
<li data-ng-repeat="subitem in item.items | orderBy: 'position'"
data-ng-if="subitem.shouldRender(authentication.user);"
ui-route="/admin/users" ng-class="{active: $uiRoute}" class="ng-scope">
<!-- THIS IS WHAT I WANT TO CLICK -->
<a href="/#!/admin/users" data-ng-bind="subitem.title" class="ng-binding">
Administer Users
</a>
</li>
</ul>
我认为我需要做的是模拟 "Admin" link 的点击以显示子菜单(在上面的第一条评论中注明)。然后模拟"Administer Users"link的点击触发导航
我的具体问题:
- 我模拟导航 link 点击的策略是否正确?
- 我应该使用什么魔法元素(by.?) 语句来找到 "Admin" link
- 假设我有 "Admin" link,找到 "Administer Users" link 来模拟该点击的最佳方法是什么?
我应该如何处理折叠/汉堡包模式
移动布局中的导航范式发生变化。我还没有研究布局,但是相同的 link 需要不同的点击次数。
此处的最佳做法是什么?关于我可以用来帮助发现该做什么的资源的任何建议?
我还要注意...
我确实想找到作为菜单子项的 link...而不是只找到其中包含 URL 的任何 link。
菜单项比显示的多...为了清楚起见,我只是减少了 html 示例。
来来回回...(自我回答)
我对量角器、JS等比刚开始的时候了解多了。我认为这是一个相当不错的解决方案。这将节省大量时间。希望对某人有所帮助...
首先,使用Page Object pattern.
接下来,创建一个点击导航栏链接的函数,包括点击expand/expose和children。它需要根据 MEANJS 导航的响应特性智能地工作(例如,汉堡包或不汉堡包):
commonPOs.clickNavBar = function(mainTab, linkUrl) {
var deferred = protractor.promise.defer();
var hamburger = element(by.id('nav-hamburger'));
hamburger.isDisplayed().then(function(result) {
if ( result ) {
hamburger.click().then(function() {
var navBar = hamburger
.element(by.xpath('../..'))
.element(by.id('myapp-navbar'));
return clickItNow(mainTab, linkUrl, navBar, deferred);
});
} else {
return clickItNow(mainTab, linkUrl, element(by.id('myapp-navbar')), deferred);
}
});
return deferred.promise;
};
function clickItNow(mainTab, linkUrl, navBar, deferred) {
var targetLink;
var linkCssExpression = 'a[href*="' + linkUrl + '"]';
expect(navBar.waitReady()).toBeTruthy();
if(mainTab) {
// if mainTab was passed, neet to
// click the parent first to expose the link
var parentTabLink;
if (mainTab == 'ACCTADMIN') {
parentTabLink = navBar.element(by.id('account-admin-menu'));
}
else {
parentTabLink = navBar.element(by.id('main-menu-' + mainTab.split(' ').join('')));
}
// expect(parentTabLink.isDisplayed()).toBeTruthy();
expect(parentTabLink.waitReady()).toBeTruthy();
parentTabLink.click();
targetLink = parentTabLink.element(by.xpath('..')).element(by.css(linkCssExpression));
}
else {
targetLink = navBar.element(by.css(linkCssExpression));
}
expect(targetLink.waitReady()).toBeTruthy();
targetLink.click().then(function() {
return deferred.fulfill();
});
}
我在上面的代码中引用了 waitReady() 函数。你可以发现 here.
上面的导航功能需要对量角器进行一些 html 标记更改,这样可以更轻松地找到导航元素:
/public/modules/core/views/header.client.view.html
使用 ID 标记这些元素:
- 'nav-hamburger'
- 'myapp-navbar'
- 'main-menu-{{item.title.split(' ').join('')}}' <<< 让标题中存在空格
- 'account-admin-menu'
/public/modules/core/views/header.client.view.html
<div class="container" data-ng-controller="HeaderController">
<div class="navbar-header">
<button id="nav-hamburger" class="navbar-toggle" type="button" data-ng-click="toggleCollapsibleMenu()"> . . . .
</button>
</div>
<nav id="myapp-navbar" class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
<ul class="nav navbar-nav" data-ng-if="menu.shouldRender(authentication.user);">
<li data-ng-repeat="item in menu.items | orderBy: 'position'" data-ng-if="item.shouldRender(authentication.user);" ng-switch="item.menuItemType" ui-route="{{item.uiRoute}}" class="{{item.menuItemClass}}" ng-class="{active: ($uiRoute)}" dropdown="item.menuItemType === 'dropdown'">
<a id="main-menu-{{item.title.split(' ').join('')}}" ng-switch-when="dropdown" class="dropdown-toggle" dropdown-toggle>
<ul class="nav navbar-nav navbar-right" data-ng-show="authentication.user">
<li class="dropdown" dropdown>
<a id="account-admin-menu" href="#" class="dropdown-toggle" data-toggle="dropdown" dropdown-toggle>
我已使用通用页面 object 命令将导航包装到特定元素:
commonPOs.navToSigninPage = function() {
var deferred = protractor.promise.defer();
this.clickNavBar(null, 'signin').then(function() {
expect(something).toBeTruthy();
deferred.fulfill(new SigninPage());
});
return deferred.promise;
};
最后,像这样在您的规范中使用它:
commonPOs.navToSigninPage().then(function(signInPage){
signInPage.loginWithCredentials(username, password);
});
大部分内容我仍处于学习模式。
我已经安装了MeanJS and am using the navigation that came out of the box. I am starting to implement end-to-end tests using Protractor and Jasmine。
我希望我的量角器测试与导航组件交互。在整页中,它很宽。在移动尺寸中,它是一个汉堡包。非常感谢任何有关编写/考虑测试的好方法的一般信息。
以下是我目前遇到的一些问题:
模拟菜单项选择
我想使用量角器模拟用户点击菜单项。 HTML 为全屏宽度呈现...
<li data-ng-repeat="item in menu.items | orderBy: 'position'"
data-ng-if="item.shouldRender(authentication.user);"
ng-switch="item.menuItemType" ui-route="/admin" class="dropdown"
ng-class="{active: ($uiRoute)}"
dropdown="item.menuItemType === 'dropdown'">
<!-- THIS NEEDS TO BE CLICKED TO MAKE THE CHILD LINKS VISIBLE -->
<a ng-switch-when="dropdown" class="dropdown-toggle ng-scope"
dropdown-toggle="" aria-haspopup="true" aria-expanded="false">
<span data-ng-bind="item.title" class="ng-binding">Admin</span>
<b class="caret"></b>
</a>
<ul ng-switch-when="dropdown" class="dropdown-menu ng-scope">
<li data-ng-repeat="subitem in item.items | orderBy: 'position'"
data-ng-if="subitem.shouldRender(authentication.user);"
ui-route="/admin/users" ng-class="{active: $uiRoute}" class="ng-scope">
<!-- THIS IS WHAT I WANT TO CLICK -->
<a href="/#!/admin/users" data-ng-bind="subitem.title" class="ng-binding">
Administer Users
</a>
</li>
</ul>
我认为我需要做的是模拟 "Admin" link 的点击以显示子菜单(在上面的第一条评论中注明)。然后模拟"Administer Users"link的点击触发导航
我的具体问题:
- 我模拟导航 link 点击的策略是否正确?
- 我应该使用什么魔法元素(by.?) 语句来找到 "Admin" link
- 假设我有 "Admin" link,找到 "Administer Users" link 来模拟该点击的最佳方法是什么?
我应该如何处理折叠/汉堡包模式
移动布局中的导航范式发生变化。我还没有研究布局,但是相同的 link 需要不同的点击次数。
此处的最佳做法是什么?关于我可以用来帮助发现该做什么的资源的任何建议?
我还要注意...
我确实想找到作为菜单子项的 link...而不是只找到其中包含 URL 的任何 link。
菜单项比显示的多...为了清楚起见,我只是减少了 html 示例。
来来回回...(自我回答)
我对量角器、JS等比刚开始的时候了解多了。我认为这是一个相当不错的解决方案。这将节省大量时间。希望对某人有所帮助...
首先,使用Page Object pattern.
接下来,创建一个点击导航栏链接的函数,包括点击expand/expose和children。它需要根据 MEANJS 导航的响应特性智能地工作(例如,汉堡包或不汉堡包):
commonPOs.clickNavBar = function(mainTab, linkUrl) {
var deferred = protractor.promise.defer();
var hamburger = element(by.id('nav-hamburger'));
hamburger.isDisplayed().then(function(result) {
if ( result ) {
hamburger.click().then(function() {
var navBar = hamburger
.element(by.xpath('../..'))
.element(by.id('myapp-navbar'));
return clickItNow(mainTab, linkUrl, navBar, deferred);
});
} else {
return clickItNow(mainTab, linkUrl, element(by.id('myapp-navbar')), deferred);
}
});
return deferred.promise;
};
function clickItNow(mainTab, linkUrl, navBar, deferred) {
var targetLink;
var linkCssExpression = 'a[href*="' + linkUrl + '"]';
expect(navBar.waitReady()).toBeTruthy();
if(mainTab) {
// if mainTab was passed, neet to
// click the parent first to expose the link
var parentTabLink;
if (mainTab == 'ACCTADMIN') {
parentTabLink = navBar.element(by.id('account-admin-menu'));
}
else {
parentTabLink = navBar.element(by.id('main-menu-' + mainTab.split(' ').join('')));
}
// expect(parentTabLink.isDisplayed()).toBeTruthy();
expect(parentTabLink.waitReady()).toBeTruthy();
parentTabLink.click();
targetLink = parentTabLink.element(by.xpath('..')).element(by.css(linkCssExpression));
}
else {
targetLink = navBar.element(by.css(linkCssExpression));
}
expect(targetLink.waitReady()).toBeTruthy();
targetLink.click().then(function() {
return deferred.fulfill();
});
}
我在上面的代码中引用了 waitReady() 函数。你可以发现 here.
上面的导航功能需要对量角器进行一些 html 标记更改,这样可以更轻松地找到导航元素:
/public/modules/core/views/header.client.view.html 使用 ID 标记这些元素:
- 'nav-hamburger'
- 'myapp-navbar'
- 'main-menu-{{item.title.split(' ').join('')}}' <<< 让标题中存在空格
- 'account-admin-menu'
/public/modules/core/views/header.client.view.html
<div class="container" data-ng-controller="HeaderController">
<div class="navbar-header">
<button id="nav-hamburger" class="navbar-toggle" type="button" data-ng-click="toggleCollapsibleMenu()"> . . . .
</button>
</div>
<nav id="myapp-navbar" class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
<ul class="nav navbar-nav" data-ng-if="menu.shouldRender(authentication.user);">
<li data-ng-repeat="item in menu.items | orderBy: 'position'" data-ng-if="item.shouldRender(authentication.user);" ng-switch="item.menuItemType" ui-route="{{item.uiRoute}}" class="{{item.menuItemClass}}" ng-class="{active: ($uiRoute)}" dropdown="item.menuItemType === 'dropdown'">
<a id="main-menu-{{item.title.split(' ').join('')}}" ng-switch-when="dropdown" class="dropdown-toggle" dropdown-toggle>
<ul class="nav navbar-nav navbar-right" data-ng-show="authentication.user">
<li class="dropdown" dropdown>
<a id="account-admin-menu" href="#" class="dropdown-toggle" data-toggle="dropdown" dropdown-toggle>
我已使用通用页面 object 命令将导航包装到特定元素:
commonPOs.navToSigninPage = function() {
var deferred = protractor.promise.defer();
this.clickNavBar(null, 'signin').then(function() {
expect(something).toBeTruthy();
deferred.fulfill(new SigninPage());
});
return deferred.promise;
};
最后,像这样在您的规范中使用它:
commonPOs.navToSigninPage().then(function(signInPage){
signInPage.loginWithCredentials(username, password);
});