Angular Test不调用promise回调



环境:

  • 角度1.5.8
  • Karma/Jasmine单元测试

这是我的控制器,它的目标是从$stateParams中获取一个值,并在以后使用该值执行DELETE请求。现在它应该询问用户是否删除该对象。这是一个甜蜜的提醒。

我已经删除了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().reject(),我希望这个电话真的会发生。

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

我在另一个测试中以同样的方式嘲笑了swal,它运行良好。我不明白为什么承诺得不到兑现。

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

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

感谢您的真知灼见。

如果执行$rootScope会发生什么$digest()?

根据我的经验,这样的东西对于在测试期间做出角度解析承诺是必要的(无论是那个还是$rootScope.$apply()或$httpBackend.flush())

最新更新