我有一个服务,它公开了一个接收解析后的CSV(使用papaparse)的函数,以及反映解析状态的promise:
如果文件缺少必填字段,则拒绝承诺
否则,它会将每行解析为一个项目并自动填充缺少的字段(自动填充过程是异步的)
当所有项都被填充时,该函数使用items数组
我要测试的函数是onCsvParse:
angular.module('csvParser', [])
.factory('csvParser', ['$http',
function($http) {
var service = {
onCsvParse: function(results, creatingBulkItems) {
var errors = this.getCsvErrors(results);
if (errors.length > 0) {
//reject
creatingBulkItems.reject(errors);
} else {
var items = this.parseCsv(results);
var autoPopulateItems = [],
populatedItems = [];
for (var i = 0; i < populatedItems.length; i++) {
var item = items[i];
if (item.name === "" /*or some any field is missing */ ) {
// auto populate item
autoPopulateItems.push(this.autoPopulateItem(item));
} else {
var populatedItem = $q.when(item);
populatedItems.push(populatedItem);
}
}
populatedItems =autoPopulateItems.concat(populatedItems);
var populatingAllItems = $q.all(populatedItems);
populatingAllItems.then(function(items) {
creatingBulkItems.resolve(items);
}, function(err) {
creatingBulkItems.resolve(err);
});
}
},
autoPopulateItem: function(newItem) {
var populatingItem = $q.defer();
var item = angular.copy(newItem);
$http.post('api/getItemData', { /*.....*/ })
.success(function(response) {
//----Populate item fields
item.name = response.name;
//....
//resolve the promise
populatingItem.resolve(item)
}).error(err) {
// resolving on error for $q.all indication
populatingItem.resolve(item)
};
return populatingItem.promise;
}
}
return service;
}
])
我对此方法的测试如下(简化):
describe('bulk items upload test', function() {
//upload csv & test scenarios...
var $rootScope, $q, csvResults = {};
var $httpBackend, requestHandler;
beforeEach(module('csvParser'));
beforeEach(inject(function(_$rootScope_, _$q_) {
$rootScope = _$rootScope_;
$q = _$q_;
}));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
requestHandler = $httpBackend.when('POST', 'api/getItemData')
.respond({
name: "name",
description: "description",
imageUrl: "www.google.com"
});
// afterEach(function(){ $rootScope.$apply();});
}));
it('Should parse csv string', function(done) {
var csvString = "Name,Description of the page";//...
Papa.parse(csvString, {
complete: function(results) {
csvResults = results;
done();
}
});
});
it('Should fail', function(done) {
var creatingBulkItems = $q.defer();
console.log("here..");
csvParser.onCsvParse(csvResults, creatingBulkItems);
creatingBulkItems.promise.then(function() {
console.log("1here..");
//promise is never resolved
expect(1).toEqual(1);
done();
}, function() {
//promise is never rejeceted
console.log("2here..");
expect(1).toEqual(1);
done();
});
$rootScope.$apply();
});
});
有了这个,我得到错误:错误:超时 - 在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超时内没有调用异步回调。
承诺没有得到解决,虽然我调用了$ rootScope。$ apply()而且我也没有调用真正的异步调用(只有mocks,除了$ q.all)。 我怎样才能使它发挥作用?答案 0 :(得分:1)
语法无效。您需要将函数传递给error
回调。
}).error(function(err) {
// resolving on error for $q.all indication
populatingItem.resolve(item)
});
return populatingItem.promise;
此外,jasime测试需要更多初始化: http://plnkr.co/edit/wjykvpwtRA0kBBh3LcX3?p=preview
答案 1 :(得分:0)
阅读本文后:https://gist.github.com/domenic/3889970我发现了我的问题 关键是使用 promise.then 返回值来压缩承诺链。
这个[promise.then]函数应该返回一个新的promise,当给定的fulfilledHandler或errorHandler回调完成时,它将被满足。这允许将承诺操作链接在一起。回调处理程序返回的值是返回的promise的履行值。如果回调引发错误,则返回的promise将被移至失败状态。
而不是在内部promise中成功/失败回调中解析外部promise,外部promise在内部promise中解析。然后回调
所以我的修复是这样的:
onCsvParse: function(results) {
var errors = this.getCsvErrors(results);
if (errors.length > 0) {
var deferred = $q.defer();
//reject
return deferred.reject(errors);
} else {
var items = this.parseCsv(results);
var autoPopulateItems = [],
populatedItems = [];
for (var i = 0; i < populatedItems.length; i++) {
var item = items[i];
if (item.name === "" /*or some any field is missing */ ) {
// auto populate item
autoPopulateItems.push(this.autoPopulateItem(item));
} else {
var populatedItem = $q.when(item);
populatedItems.push(populatedItem);
}
}
populatedItems = autoPopulateItems.concat(populatedItems);
var populatingAllItems = $q.all(populatedItems);
return populatingAllItems.then(function(items) {
return items;
}, function(err) {
return err;
});
}
},
测试代码:
it('Should not fail :)', function(done) {
csvParser.onCsvParse(csvResults).then(function(items) {
//promise is resolved
expect(items).not.toBeNull();
done();
}, function() {
//promise is rejeceted
//expect(1).toEqual(1);
done();
});
$rootScope.$apply();});