问题
So I have such decorator in app config:
angular.module('app').config(['$provide', function ($provide) {
$provide.decorator('$rootScope', ['$delegate', function ($delegate) {
$delegate.constructor.prototype.$onRootScope = function (name, listener) {
var unsubscribe = $delegate.$on(name, listener);
this.$on('$destroy', unsubscribe);
};
$delegate.constructor.prototype.$watchRootScope = function (name, listener) {
var unsubscribe = $delegate.$watch(name, listener);
this.$on('$destroy', unsubscribe);
};
$delegate.constructor.prototype.$watchAfterLoad = function (watchExpression, listener, objectEquality) {
var initialLoad = true;
this.$watch(watchExpression, function () {
if (initialLoad) {
// note: this obviously runs outside of angular, so sometimes the timeout could run after initial load
setTimeout(function () { initialLoad = false; }, 25);
} else {
listener.apply(this, arguments);
}
}, objectEquality);
};
return $delegate;
}]);
}]);
As you can see this decorator lets me use $scope.$onRootScope instead of $rootScope.$on and takes care of automatic listeners removal on scope destroy event...
When I unit test my code which logic contains $scope.$onRootScope I'm getting such error: TypeError: undefined is not a constructor (evaluating 'scope.$onRootScope') in
Before each test I'm loading all required models and do inject which looks like this ~:
beforeEach(function () {
inject(function (_$rootScope_) {
$rootScope = _$rootScope_;
});
});
How should I overcome this problem? Is there a way to mock / mimic $scope.$onRootScope behaviour?
I'm quite new to unit testing & Jasmine so sorry for not very nicely formatted question.
EDIT #1:
As I'm mocking my $scope object (var $scope = {...}) before passing it as argument to service method which I'm testing I can avoid error by simply defining $scope method:
$scope = {
...
$onRootScope: function() {}
}
Still awaiting for some better ideas :-)
回答1:
I believe you need to build your $scope
based off of the decorated $rootScope
, as opposed to creating a new dummy object.
Like so:
var $root, $scope;
beforeEach(function () {
module('app');
inject(function ($rootScope) {
$root = $rootScope;
$scope = $root.$new();
});
});
it('should have the expected property', function () {
expect($scope.constructor.prototype).to.have.property('$watchRootScope');
});
I'll chuck in a link to the spec suite of a mini-lib I put together some time ago, doing roughly the same thing you are now.
来源:https://stackoverflow.com/questions/31313554/how-to-unit-test-custom-decorator-with-jasmine-angular-js