我们目前正在尝试测试我们的 Angular 服务,它使用 promise 将值返回给 Controller 。问题是我们附加到 .then 的函数不会在 Jasmine 中被调用。
我们发现在返回 promise 后将 $rootScope.digest() 添加到函数中允许调用同步 promise,但它仍然不适用于异步 promises。
目前的代码是
beforeEach(inject(function (Service, $rootScope)
{
service = Service;
root = $rootScope;
}));
it('gets all the available products', function (done)
{
service.getData().then(function (data)
{
expect(data).not.toBeNull();
expect(data.length).toBeGreaterThan(0);
done();
});
root.$digest();
});
在这种情况下,promise 被调用得很好,但如果它是异步的,它将不会被调用,因为在调用 root.$digest() 时 promise 还没有准备好“消化”。
有没有什么方法可以判断 promise 何时在解决后才能调用 digest?或者也许可以自动执行此操作?谢谢 ;)
我们必须测试的部分服务(删除了错误处理):
var app = angular.module('service', []);
/**
* Service for accessing data relating to the updates/downloads
* */
app.factory('Service', function ($q)
{
... init
function getData()
{
var deffered = $q.defer();
var processors = [displayNameProc];
downloads.getData(function (err, data)
{
chain.process(processors, data, function (err, processedData)
{
deffered.resolve(processedData);
});
});
return deffered.promise;
}
...
在出现问题的情况下,当 service.getData 异步时,promise 已解决,但未调用测试代码中附加到该 promise 的函数,因为 root.$digest 已被调用。希望这能提供更多信息
解决方法
var interval;
beforeEach(inject(function ($rootScope)
{
if(!interval)
{
interval = function ()
{
$rootScope.$digest();
};
window.setInterval(interval, /*timing*/);
}
}));
我最终使用上面的解决方法重复调用摘要,这样每一层 promise 都有机会运行......它不理想或不漂亮但它适用于测试......
最佳答案
你应该把你的断言移到 then 之外,我相信:
beforeEach(inject(function (Service, $rootScope)
{
service = Service;
root = $rootScope;
}));
it('gets all the available products', function (done)
{
var result;
service.getData().then(function (data)
{
result = data;
done();
});
root.$digest();
expect(result ).not.toBeNull();
expect(result .length).toBeGreaterThan(0);
});
更新
fork plunkr在下面的评论中显示如何测试异步调用。
向服务添加了 $timeout:
var app = angular.module('bad-service', []);
app.service('BadService', function ($q, $interval, $timeout)
{
this.innerPromise = function(){
var task = $q.defer();
console.log('Inside inner promise');
$timeout(function() {
console.log('Inner promise timer fired');
task.resolve();
}, 500);
// $interval(function(){
// }, 500, 1);
return task.promise;
}
});
我在断言之前刷新 $timeout:
beforeEach(module('test'));
describe('test', function(){
var service, root, $timeout;
beforeEach(inject(function (Service, $rootScope, _$timeout_)
{
$timeout = _$timeout_;
console.log('injecting');
service = Service;
root = $rootScope;
}));
/**
Test one
*/
it('Should work', function(done){
console.log('Before service call');
service.outerPromise().then(function resolve(){
console.log('I should be run!');
expect(true).toBeTruthy();
done();
});
// You will have to use the correct "resolve" here. For example when using:
// $httpbackend - $httpBackend.flush();
// $timeout- $timeout.flush();
$timeout.flush();
console.log('After service call');
});
});
关于javascript - $rootScope.digest 没有完成 Jasmine 中的 promise ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32717897/