使用 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的点击触发导航

我的具体问题:

  1. 我模拟导航 link 点击的策略是否正确?
  2. 我应该使用什么魔法元素(by.?) 语句来找到 "Admin" link
  3. 假设我有 "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);
});