Angular Test不会调用promise回调

时间:2017-02-01 15:15:23

标签: javascript angularjs unit-testing jasmine karma-runner

环境:

  • Angular 1.5.8
  • 使用Karma / Jasmine进行单元测试

这是我的控制器,它的目的是从$ stateParams获取一个值,然后使用它来执行DELETE请求。 现在它应该询问用户,删除对象。 这是通过sweetalert完成的。​​

我删除了ngdoc注释和任意SWAL配置。

ClientDeleteController.js:

angular.module('app.data').controller('ClientDeleteController', [
  '$stateParams', '$q',
  function ($stateParams, $q) {
    'use strict';

    var vm = this;
    vm.clientId = $stateParams.id;
    vm.promptDeferred = null;

    vm.prompt = function () {

      // create promise
      var d = $q.defer();
      vm.promptDeferred = d;

      // create prompt
      swal({ .... }, vm.swalCallback);
    };

    vm.swalCallback = function (confirmed) {
      if (confirmed) {
        console.info('resolving...');
        vm.promptDeferred.resolve();
      } else {
        console.info('rejecting...');
        vm.promptDeferred.reject();
      }
    };

    vm.delete = function () {
      vm.prompt();
      vm.promptDeferred.promise.then(vm.performDelete);
    };

    vm.performDelete = function () {
      console.info('performing');
    };
  }]);

这是测试套件:

ClientDeletecontrollerSpec.js

describe('Controller:ClientDeleteController', function () {

  var controller
    , $httpBackend
    , $rootScope
    , $controller
    , scope
    , $q
    , $stateParams = {id: 1}
    , resolvePromise = true
    ;

  swal = function (options, callback) {
    console.info('i am swal, this is callback', callback+'', resolvePromise);
    callback(resolvePromise);
  };

  beforeEach(function () {
    module('app');
    module('app.data');
    module('ui.bootstrap');
    module(function ($provide) {
      $provide.service('$stateParams', function () {
        return $stateParams;
      });
    });

    inject(function (_$controller_, _$rootScope_, _$q_) {
      $controller = _$controller_;
      $rootScope = _$rootScope_;
      $q = _$q_;

      scope = $rootScope.$new();

      controller = $controller('ClientDeleteController', {$scope: scope, $q: $q});

    });
  });

  describe('basic controller features', function () {
    it('should be defined', function () {
      expect(controller).toBeDefined();
    });
    it('should get the client id from the state params', function () {
      expect(controller.clientId).toBeDefined();
      expect(controller.clientId).toEqual($stateParams.id);
    });
  });

  fdescribe('client delete process', function () {

    it('should ask the user if he really wants to delete the client', function () {
      spyOn(controller, 'prompt').and.callThrough();
      controller.delete();
      expect(controller.prompt).toHaveBeenCalled();
    });

    it('should create a promise', function () {
      controller.prompt();
      expect(controller.promptDeferred).toBeDefined();
    });

    it('should delete when the user clicked yes', function () {
      spyOn(controller, 'performDelete').and.callThrough();
      controller.delete();
      expect(controller.performDelete).toHaveBeenCalled();
    });

    it('should not delete when the user clicked no', function () {
      spyOn(controller, 'performDelete').and.callThrough();
      resolvePromise = false;
      controller.delete();
      expect(controller.performDelete).not.toHaveBeenCalled();
    });
  });

});

测试should delete when the user clicked yes失败,测试should not delete when the user clicked no返回误报。

swal mock中的console.info(...)会记录正确的回调函数。函数本身的日志也被记录,告诉我,回调被触发。 因为在下一行中,我调用了vm.promptDeferred.resolve() resp。 .reject(),我希望这个电话确实发生了。

尽管如此,测试结果为Expected spy performDelete to have been called.

我以同样的方式在另一个测试中嘲笑了swal并且它工作正常。 我不明白为什么承诺不会得到解决。

注意:当我没有直接将承诺存储在控制器上但从prompt()返回并使用常规.prompt().then(...)时,它也无法正常工作。 日志是一样的,我喜欢尽可能地分割函数,因此更容易理解,更容易测试和记录。

在这个应用程序中有数百个其他测试,但我不明白,为什么这个测试不能按预期工作。

感谢您的任何见解。

1 个答案:

答案 0 :(得分:1)

如果在测试中调用delete之后执行$ rootScope。$ digest()会发生什么?

根据我的经验,在测试期间(或者rootScope。$ apply()或$ httpBackend.flush())有必要做出类似角度解析的承诺。