【问题标题】:Angular Test does not call a promise callbackAngular Test 不调用承诺回调
【发布时间】:2017-02-01 15:15:23
【问题描述】:

环境:

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

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

我已经删除了 ngdoc cmets 和任意 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 模拟中的console.info(...) 记录了正确的回调函数。函数本身的日志也被记录下来,这告诉我,回调被触发了。 因为在下一行,我打电话给vm.promptDeferred.resolve() resp。 .reject(),我希望电话真的会发生。

不过,测试结果是Expected spy performDelete to have been called.

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

注意:当我不将承诺直接存储在控制器上而是从prompt() 返回并使用常规.prompt().then(...) 时,它也不起作用。 日志是一样的,我喜欢尽可能的拆分函数,这样更容易理解,更容易测试和记录。

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

感谢您提供任何见解。

【问题讨论】:

  • 另一件事:在实际应用程序中,它按预期运行。只有测试失败,这显然是一个测试问题。
  • 如果你在测试中调用 delete 之后执行 $rootScope.$digest() 会发生什么?根据我的经验,在测试期间做出角度解析承诺是必要的(或者在 http 后端模拟上应用或刷新)
  • 谢谢,就是这样。如果您想将此作为答案发布,我想将其标记为正确答案。
  • 酷 :) 没问题。添加它作为答案。

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


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 2014-04-27
    相关资源
    最近更新 更多