2

我们在使用 GhostDriver 运行 Selenium 测试时遇到问题。我们有一个受我们选择的技术影响的 Selenium 测试失败。我们的堆栈是由 AngularJS 前端支持的 Lift 后端。我们正在利用 CometActors 将数据推送到前端的两个不同的 AngularJS 控制器。

当用户访问该站点时,他们将首先看到由控制器一提供的主页。该控制器使用许多可导航元素呈现页面。第二个控制器通过主页上生成的链接(包含 $routeParams)链接到。

当我们为我们的模型列表页面加载页面时,我们的测试失败就会出现。此页面包含主控制器,它将我们从 Comet 接收到的数据绑定到模板。当项目在页面上可见时,我们可以单击它们以转换到第二个控制器。这个控制器向我们的 Lift 后端发出一个新请求,这导致 CometActor 将响应发送回前端。到目前为止,我们已经验证了所有功能都符合我们的预期,包括用于检索模型列表的初始 Comet 请求以及用于前端的相应响应。

问题出现在这里...前端从不执行我们 CometActor 响应中提供的 JavaScript 命令。我们的 CometDispatch.sendModels 函数永远不会被调用,从而防止事件触发对 ModelListController 的更新。我们的 Selenium 测试失败了,因为它找不到应在更新 ModelListController 时创建的预期 HTML 元素。我们不确定 Comet 提供的 JavaScript 命令会发生什么,因为它似乎从未在前端执行。我们通过将 GhostDriver 生成的页面源转储到控制台来验证我们的模型列表没有呈现。

这个问题给我们带来了很多困惑,因为我们的 selenium 测试在使用 Firefox 驱动时通过了。

CarRegistry.scala

class CarRegistry extends CometActor {
  implicit val formats = DefaultFormats
  private val adapter: ModelAdapter = new LiftActorModelAdapter

  override def lifespan = Full(5 minutes)

  def render: RenderOut = {
    adapter.handleMessage(ListMakesMessage(this))
    "#car-registry-uuid [value]" #> SHtml.jsonCall(Call("function(){}"), fetchModelsByMakeId _).guid
  }

  def fetchModelsByMakeId(requestJValue: JValue) = {
    requestJValue match {
      case JInt(makeId) => adapter.handleMessage(ListModelsMessage(this, makeId.toLong))
      case _ => ()
    }
    _Noop
  }

  override def lowPriority = {
    case s @ JObject(List(JField(key, JArray(_)))) if key =="make"  =>
      partialUpdate(Call("CometDispatch.sendMakes", s))
    case s @ JObject(List(JField(key, JArray(_)))) if key =="model" =>
      partialUpdate(Call("CometDispatch.sendModels", s))
    case _ => ()
  }
}

彗星调度.js

var CometDispatch = {
    sendMakes: function(makesJson) {
        $('body').trigger('makes-received', makesJson);
    },
    sendModels: function(modelsJson) {
        $('body').trigger('models-received', modelsJson);
    }
};

应用程序.js

'use strict';

angular.module('myApp', [
  'ngRoute',
  'myApp.filters',
  'myApp.services',
  'myApp.directives',
  'myApp.controllers'
]).
config(['$routeProvider', function($routeProvider, $routeScopeProvider) {
  $routeProvider.when('/', {templateUrl: 'static/pages/make-list.html', controller: 'MakeListController'});
  $routeProvider.when('/:makeId/list', {templateUrl: 'static/pages/model-list.html', controller: 'ModelListController'});
  $routeProvider.otherwise({redirectTo: '/'});
}]);

控制器.js

'use strict';

angular.module('myApp.controllers', []).
    controller('MakeListController', function($scope, DataStore) {

        $( 'body' ).on( 'makes-received', function( event, makesJsonObj ) {
            $scope.$apply(function() {
                DataStore.makes = makesJsonObj['makes'];
                $scope.makes = makesJsonObj['makes'];
            });
        });

        $scope.makes = $scope.makes || DataStore.makes;
    }).
    controller('ModelListController', function($scope, $routeParams, CometRequestService) {

        $( 'body' ).on( 'models-received', function( event, modelsJsonObj ) {
            $scope.$apply(function() {
                $scope.models = modelsJsonObj['models'];
            });
        });

        CometRequestService.getModelsFor($routeParams.makeId);
    });

服务.js

'use strict';

angular.module('myApp.services', []).
  factory('DataStore', function() {
      return {
          makes: []
      };
  }).
  factory('CometRequestService', function() {
     return {
         getModelsFor: function(makeId) {
             liftAjax.lift_ajaxHandler($('#car-registry-uuid').val() + "=" + makeId, null, null, null);
         }
     }
  });

索引.html

<div id="main" lift="surround?with=default;at=content">
   <h1>Model Directory</h1>

    <div lift="comet?type=CarRegistry&randomname=true">
        <input type="hidden" id="car-registry-uuid"/>
    </div>

    <div ng-view></div>
</div>

make-list.html

<div id="make-list">   
    <div ng-repeat="make in makes">
        <a ng-href="#/{{make.id}}/list/" data-dropdown="dd-{{make.id}}">
            {{make.name}}
        </a>
    </div>
</div>

模型列表.html

<div id="model-list">
    <div ng-repeat="model in models">
        <div>
            {{model.name}}
        </div>
    </div>
</div>

这个问题也在这个要点中描述。

4

0 回答 0