【问题标题】:How to mock call to navigator.geolocation in Protractor tests如何在量角器测试中模拟对 navigator.geolocation 的调用
【发布时间】:2014-05-02 14:53:52
【问题描述】:

假设您有一个显示地点列表的 Angular 应用。有一个按钮可以获取您当前的位置,单击该按钮会根据与您所在位置的距离对列表进行排序,最近的在前。

要在 Protractor 中进行测试,您希望能够单击按钮并检查列表:

it('Should order items according to distance', function () {
    locButton.click();
    expect(...).toBe(...); // Check that the first item on the list
                           // the closest to the given lat/long

});

现在,假设按钮调用控制器中的方法,控制器调用服务中的方法,服务调用 navigator.geolocation.getCurrentPosition()(并且,为了更好的衡量,该调用被包装在一个承诺中)。对此进行测试的最佳方法是模拟对 getCurrentPosition() 的调用并返回特定的纬度和经度,这样就可以一直返回到页面输出链的所需效果。你如何设置那个模拟?

我尝试了this answer to a similar question about Jasmine中的方法,在navigator.geolocation上创建了一个spy,结果:

ReferenceError: navigator is not defined

我还尝试使用类似于this answer 的内容来模拟服务,结果是:

ReferenceError: angular is not defined

更新: 找到了一个解决方案,所以我在下面回答了我自己的问题,但我真的非常希望有比这更好的答案。

【问题讨论】:

    标签: angularjs unit-testing mocking protractor


    【解决方案1】:

    通过使用browser.executeScript() 直接在浏览器中运行一些JavaScript 找到了way to do it。例如:

    describe('Testing geolocation', function () {
        beforeEach(function () {
            browser.executeScript('\
                window.navigator.geolocation.getCurrentPosition = \
                    function(success){ \
                        var position = { \
                            "coords" : { \
                                "latitude": "37",
                                "longitude": "-115" \
                            } \
                        }; \
                        success(position); \
                    }')
        });
    
        it('Should order items according to distance', function () {
            locButton.click();
            expect(...).toBe(...); // Check that the first item on the list
                                   // the closest to the given lat/long
        });
    });
    

    这行得通,但它很难看。我尽力使传递给browser.executeScript() 的字符串尽可能可读。

    编辑

    这是一个清理后的版本,其中包含两个模拟成功和错误的函数:

    describe('Geolocation', function () {
        function mockGeo(lat, lon) {
            return 'window.navigator.geolocation.getCurrentPosition = ' +
                '       function (success, error) {' +
                '           var position = {' +
                '               "coords" : {' +
                '                   "latitude": "' + lat + '",' +
                '                   "longitude": "' + lon + '"' +
                '               }' +
                '           };' +
                '           success(position);' +
                '       }';
        }
    
        function mockGeoError(code) {
            return 'window.navigator.geolocation.getCurrentPosition = ' +
                '       function (success, error) {' +
                '           var err = {' +
                '               code: ' + code + ',' +
                '               PERMISSION_DENIED: 1,' +
                '               POSITION_UNAVAILABLE: 2,' +
                '               TIMEOUT: 3' +
                '           };' +
                '           error(err);' +
                '       }';
        }
    
    
        it('should succeed', function () {
            browser.executeScript(mockGeo(36.149674, -86.813347));
            // rest of your test...
        });
    
        it('should fail', function () {
            browser.executeScript(mockGeoError(1));
            // rest of your test...
        });
    });
    

    【讨论】:

      【解决方案2】:

      量角器测试是 e2e,因此您实际上无法访问后端代码和结果。

      我有一个类似的问题,我想在单击表单中的提交时看到我的“帖子”输出。

      创建了这个在 dom 中填充测试结果,所以你可以看到这样的后端东西。

      不是最好的,但没有其他方法可以做到这一点。

      /////////////////////////////////////////////////////////////////
      //markup added for testing
      <div ng-controller="myTestDevCtrl"> 
          <button id="get-output" ng-click="getOutput()">get output</button> 
          <input ng-model="output" /> 
      </div>
      /////////////////////////////////////////////////////////////////
      
      
      /////////////////////////////////////////////////////////////////
      //test controller to show ajax data coming out
      myTestModule.controller('myTestDevCtrl', function($scope,dataProxy) {
          $scope.getOutput = function() {
              $scope.output = dataProxy.getData();
          }
      })
      //small service to capture ajax data
      .service('dataProxy',function() {
          var data;
          return {
              setData : function(_data) {
                  data = decodeURIComponent(_data);
              },
              getData : function() {
                  return data;
              }
          }
      })
      .run(function($httpBackend,dataProxy) {
          //the office information post or 'save'
          $httpBackend.when('POST',/\/api\/offices/)
          .respond(function (requestMethod, requestUrl, data, headers) {
              //capture data being sent
              dataProxy.setData(data);
              //just return success code
              return [ 200, {}, {} ];
          });
      });
      //make myTestModule require ngMockE2E, as well as original modules
      angular.module('myTestModule').requires = [
          'ngMockE2E'
      ];
      /////////////////////////////////////////////////////////////////
      

      【讨论】:

        猜你喜欢
        • 2017-08-17
        • 2021-07-05
        • 2021-04-26
        • 1970-01-01
        • 1970-01-01
        • 2013-12-06
        • 1970-01-01
        • 2022-01-10
        • 1970-01-01
        相关资源
        最近更新 更多