angularjs - promise 没有在 Jasmine 中解决 - AngularJS

标签 angularjs unit-testing jasmine

我正在尝试测试一种在用户确认后从列表中删除项目的方法。

Controller :

app.controller('mainCtrl', ['$scope', '$window', 'dataService', function($scope, $window, dataService) {
  var vm = this;

  vm.delete = function(id, index) {
    if($window.confirm('Are you sure?')) {
      dataService.deleteById(id).then(function() {
        vm.list.splice(index, 1)
      });
    }
  };
}]);

服务:
app.service('dataService', ['$http', function($http) {
  this.deleteById = function(id) {
    return $http.delete('delete-item?id=' + id);
  };
}]);

测试:
describe('Testing RecipesController', function() {
  var scope, ctrl, dataServiceMock, q, deferred, window;

  beforeEach(function() {
    dataServiceMock = {
      deleteById: function() {
        deferred = q.defer();
        return deferred.promise;
      }
    };
  });

  beforeEach(function() {
    module('app');
    inject(function($rootScope, $controller, $q, $window) {
      q = $q;
      window = $window;
      scope = $rootScope.$new();
      ctrl = $controller('mainCtrl', {
        $scope: scope,
        dataService: dataServiceMock
      });
    });
  });

  it('should delete recipe if the user clicked "OK"', function() {
    spyOn(window, 'confirm').and.returnValue(true);
    spyOn(dataServiceMock, 'deleteById').and.callThrough();

    var item= {
      id: 2,
      name: 'Shirt'
    };

    ctrl.list = ['Hat', 'Shirt'];
    ctrl.delete(item, 1);

    expect(dataServiceMock.deleteById).toHaveBeenCalled();
    expect(ctrl.list.length).toBe(1);
  });
});

我成功地模拟了确认对话框和删除方法,并且检查该方法是否被调用的测试甚至通过了。
但是, promise.then() 不起作用。
运行测试后,我收到此消息“预期 2 为 1”。

最佳答案

我可以肯定地看到一件事,那就是你永远不会在数据服务模拟中解决或拒绝你的 promise 。尝试将模拟更改为:

beforeEach(function() {
  dataServiceMock = {
    deleteById: function() {
      deferred = q.defer();
      deferred.resolve({ /* whatever data you want to resolve with */ });
      return deferred.promise;
      // You could also shorten this whole mock function to just:
      //    return $q.resolve({ /* some data */ });
    }
  };
});

另外,不要忘记执行 $digest() $rootScope 上的功能在你的测试结束时......你实际上是在你的 Controller 范围内执行它,而不是根范围。

保留实际的 $rootScope 对象 - 更改您的 beforeEach到:
var $rScope;

beforeEach(function() {
    module('app');
    inject(function($rootScope, $controller, $q, $window) {
      q = $q;
      window = $window;
      $rScope = $rootScope;
      ctrl = $controller('mainCtrl', {
        $scope: $rootScope.$new(),
        dataService: dataServiceMock
      });
    });
});

然后在你的测试中,执行 $digest在最后的根范围上:
it('should delete recipe if the user clicked "OK"', function() {
  // all your test codez...

  $rScope.$digest();
});

关于angularjs - promise 没有在 Jasmine 中解决 - AngularJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41322998/

相关文章:

javascript - 当订单很重要时,如何在嵌套 promise 中使用 Jasmine 时钟(setTimeout)? (jasmine.DEFAULT_TIMEOUT_INTERVAL 错误)

angular - Jasmine 测试无法识别函数 getCurrentNavigation() : this. router.getCurrentNavigation 不是函数

javascript - 在angularjs中如何访问触发事件的元素?

java - 在一个类中只 stub 一个私有(private)静态方法

java - 使用测试用例数组调用 java 方法

unit-testing - 使用 Angular2 TestComponentBuilder 测试组件逻辑

javascript - 如何从 Jasmine 测试 Angular 2/4 触发文档级事件

angularjs - Ionic 框架与 nw.js 的集成

javascript - Angularjs 无法将数据服务响应添加到作用域变量

javascript - 使用 $http.get() 或 $http.post() 通过请求传递 JSON 数据