我有一个角度服务班:
angular.module('triggerTips') .service('userData',function ($rootScope,$http,$log,$firebase) { this._log = { service : 'userData' }; // Synchronized objects storing the user data var config; var userState; // Loads the user data from firebase this.init = function(readyCallback) { var log = angular.extend({},this._log); log.funct = 'init'; var fireRef = new Firebase('https://XYZfirebaseio.com/' + $rootScope.clientName); config = $firebase(fireRef.child('config')).$asObject(); userState = $firebase(fireRef.child('userState').child($rootScope.userName)).$asObject(); Promise.all([config.$loaded(),userState.$loaded()]). then( function() { if(config == null || Object.keys(config).length < 4) { log.message = 'Invalid config'; $log.error(log); return; } if(!userState.userProperties) { userState.userProperties = {}; } if(!userState.contentProperties) { userState.contentProperties = {}; } log.message = 'User Properties: ' + JSON.stringify(userState.userProperties); $log.debug(log); log.message = 'Content Properties: ' + JSON.stringify(userState.contentProperties); $log.debug(log); log.message = 'Loaded user data from firebase'; $log.debug(log); readyCallback(); },function() { log.message = 'Unable to load user data from firebase'; $log.error(log); } ); }; // Returns the initial tip configuration this.getConfig = function() { return config; }; // Set the value of a user property // A user property is something about the user himself this.setUserProperty = function(property,value) { if(!userState.userProperties) { userState.userProperties = {}; } userState.userProperties[property] = value; userState.$save(); $rootScope.$broadcast('user-property-change',property); }; // Get the value of a user property this.getUserProperty = function(property) { if(userState.userProperties) { return userState.userProperties[property]; } }; // Set the value of a user content property // A content property is something about a particular peice of content for a particular user this.setContentProperty = function(contentName,property,value) { if(!userState.contentProperties[contentName]) { userState.contentProperties[contentName] = {}; } userState.contentProperties[contentName][property] = value; userState.$save(); $rootScope.$broadcast('content-property-change',contentName,property); }; // Increment a count property on the user state for a given tip this.incrementContentProperty = function(contentName,property) { if(!userState.contentProperties[contentName]) { userState.contentProperties[contentName] = {}; } if(!userState.contentProperties[contentName][property]) { userState.contentProperties[contentName][property] = 0; } userState.contentProperties[contentName][property]++; userState.$save(); $rootScope.$broadcast('content-property-change',property); }; // Returns the user state for a given tip and property this.getContentProperty = function(contentName,property) { if(userState.contentProperties) { var t = userState.contentProperties[contentName]; if(t) { return t[property]; } } }; });
我试图用茉莉花单元测试这个服务:
我的单位测试是:
'use strict'; describe('Service: userData',function () { // load the service's module beforeEach(function() { module('triggerTips'); }); // instantiate service var userData; beforeEach(inject(function (_userData_) { userData = _userData_; })); it('should load correctly',function () { expect(!!userData).toBe(true); }); describe('after being initialized',function () { beforeEach(function(done) { // Unable to get this working because the callback is never called userData.init(function() { done(); }); jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000; }); it('should have a valid config',function (done) { setTimeout(function() { expect(Object.keys(userData.getConfig()).length == 0); done(); },1500);}); }); });
我阅读了关于Jasmine的异步支持,但是由于我相当新的使用JavaScript的单元测试无法使其工作.
我收到一个错误:
Async callback was not invoked within timeout specified by
jasmine.DEFAULT_TIMEOUT_INTERVAL
有人可以帮我提供我的代码的工作示例一些解释吗?
我建议您用$timeout替换setTimeout,以加快您的规格套件.您将需要
ngMock作为您的规格套件的一部分,以使其以预期的方式工作,但这似乎已被照顾您的规格.好东西.
原文链接:https://www.f2er.com/angularjs/140636.html那么为了使规范的异步性质“走开”,你会呼吁:
$timeout.flush([delay])其中延迟是可选的.
>如果没有延迟通过,所有待处理的异步任务(有角度的世界)将完成他们在做什么.
>如果传递延迟,则指定延迟内的所有待处理任务将完成.指定延迟之外的人将保持在“待定”状态.
这样,您可以删除完成的回调并编写您的测试:
describe('after being initialized',function () { var $timeout; beforeEach(function () { // Unable to get this working because the callback is never called userData.init(); inject(function ($injector) { $timeout = $injector.get('$timeout'); }); })); it('should have a valid config',function () { $timeout.flush(); // callback should've been called now that we flushed(). expect(Object.keys(userData.getConfig()).length).toEqual(0); }); });
你使用什么承诺?我看到Promise.all的电话,但是为了继续我的答案,我将假设它相当于$q.all.运行$timeout.flush应该处理这些值.
如果你想对茉莉花的承诺的拒绝/解决的价值写出期望,我会研究一下像jasmine-promise-matchers这样的东西,使它干净漂亮,但是禁止你这样做:
// $q function get () { var p1 = $timeout(function () { return 'x'; },250); var p2 = $timeout(function () { return 'y'; },2500); return $q.all([p1,p2]); } // expectation it('is correct',function () { var res; get().then(function (r) { res = r; }); $timeout.flush(2500); expect(res).toEqual(['x','y']); });
根据您的设置,您可能需要或可能不需要根据您的本地配置变量存储/监视(取决于您的框架定义的间谍)承诺,但这是我估计的另一个故事.
我不熟悉$firebase(某事)$asObject.$loaded – 因此我可能错过了这里的东西,但假设它的工作原理就像任何其他承诺一样,你应该很好.