I have xf array: var xf = [];
And I have a function is a element in this array and a function to use it:
$scope.checkEmailValid = function () {
var result = false;
Iif (xf.validateEmail($scope.email, '256')) {
result = true;
}
return result;
};
xf.validateUsername = function (sText) {
var isValid = false;
do {
//Check for valid string.
isValid = typeof sText === 'string';
if (!isValid) {
break;
}
//Check that each special character does not exist in string.
for (var i = 0; i < sText.length; i++) {
if (xf.SPECIAL_CHARS.indexOf(sText.charAt(i)) !== -1) {
isValid = false;
break;
}
}
if (!isValid) {
break;
}
} while (false);
return isValid;
};
But when I run my spec:
it ('checkEmail', function(){
$controller('MyCtrl', { $scope: $scope });
xf.validateUsername();
spyOn(window,xf.validateUsername).and.callThrough();
});
It makes an error:
xf.validateUsername is not a function
How can I cover it?
I have xf array: var xf = [];
And I have a function is a element in this array and a function to use it:
$scope.checkEmailValid = function () {
var result = false;
Iif (xf.validateEmail($scope.email, '256')) {
result = true;
}
return result;
};
xf.validateUsername = function (sText) {
var isValid = false;
do {
//Check for valid string.
isValid = typeof sText === 'string';
if (!isValid) {
break;
}
//Check that each special character does not exist in string.
for (var i = 0; i < sText.length; i++) {
if (xf.SPECIAL_CHARS.indexOf(sText.charAt(i)) !== -1) {
isValid = false;
break;
}
}
if (!isValid) {
break;
}
} while (false);
return isValid;
};
But when I run my spec:
it ('checkEmail', function(){
$controller('MyCtrl', { $scope: $scope });
xf.validateUsername();
spyOn(window,xf.validateUsername).and.callThrough();
});
It makes an error:
xf.validateUsername is not a function
How can I cover it?
Share Improve this question edited Apr 1, 2016 at 11:11 Sergey Weiss 5,9748 gold badges32 silver badges40 bronze badges asked Jul 31, 2015 at 10:14 Pham Minh TanPham Minh Tan 2,0967 gold badges27 silver badges39 bronze badges 3-
is
xf
a property on$scope
, a property on the controller, or just some free-form variable in the controller function body? – Claies Commented Aug 3, 2015 at 4:38 - @Claies: xf is just a free-form variable in the controller body. – Pham Minh Tan Commented Aug 3, 2015 at 6:40
-
1
it's not really possible to test this in that manner. If it is not actually bound to
$scope
or exposed as a public property, it is only accessible in the function that it is defined, due to the way that JavaScript closures operate. – Claies Commented Aug 3, 2015 at 16:10
4 Answers
Reset to default 1The xf
variable is not acessible from the outside of the controller's scope (i.e. not accessible in the unit test files).
You must've done the following thing:
angular
.module('myModule')
.controller(function ($scope) {
var xf = [];
// etc.
});
You could attach the xf
variable to the MyController instance once Angular instantiates it:
angular
.module('myModule')
.controller(function ($scope) {
this.xf = [];
// etc.
});
But that's not really a clean way of doing it. A better way (in my opinion) would be to create a factory:
angular
.module('myModule')
.factory('xfService', function () {
var xf = [];
function validateUsername(text) {
// etc.
}
function get() {
return xf;
}
return {
get: get,
validateUsername: validateUsername
};
});
Now, you can inject the factory in your controller to use xf:
angular
.module('myModule')
.controller(function ($scope, xfService) {
// somewhere
var isValid = xfService.validateEmail($scope.email, '256');
// to get the values in the array
var values = xfService.get();
});
Finally, for the unit tests, it bees really easy to test the validateEmail
method.
describe('Unit tests - xfService', function () {
var xfService;
beforeEach(angular.module('myModule'));
beforeEach(angular.inject(function (_xfService_) {
xfService = _xfService_;
});
});
describe('xfService.validateUsername', function () {
it('should return a boolean value', function () {
// for example
expect(typeof xfService.validateUsername('test')).toBe('boolean');
});
// add more unit tests to check that the method works as expected
});
});
You'll need to add the angular-mocks
file to the Karma config.
Thanks to Paul Podlech and Claies for the hints in the ments/answers.
I'm not sure to pletely understand your question. But there are a few thinks i think you are doing wrong:
- If xf it's a global variable you should mock it, since you are testing the controller, not the global variable.
If you want to check the real function of your global variable, go to the
karma.conf.js
file and add the js file path to thefiles
option:files: [ ..., 'fx-script.js', ... ],
callThrough
should be used before the actual function is invoked:it ('checkEmail', function(){ var ctrl = $controller('MyCtrl', { $scope: $scope }); spyOn(window, ctrl.xf.validateUsername).and.callThrough(); ctrl.xf.validateUsername(); });
I remend you to separately test your controller
, service
, or global scripts, and add mocks whenever you need to inject a dependency or global variable, so if you can tell for sure which module
/script
is failing any time.
you should move functionality in xf into separate service/factory. Then inject it in controller. That makes it pretty easy to mock it while testing.
Try this in the controller
var xf = this.xf = [];
and this in your test
it ('checkEmail', function(){
var xf = $controller('MyCtrl', { $scope: $scope }).xf;
spyOn(xf, 'validateUsername').and.callThrough();
xf.validateUsername();
});
But you should realize that this exposes your xf object on the Controller as mentioned in the ment of Claies.