$location.host() breaks angular tests. How to mock it? - javascript

I know that there are similar questions here, but I've tried them all without success.
I have a factory, that fetches texts for my application:
__resolveAngularModules__('checkoutWeb.interconnections', ['ngCookies', 'angular-hal', 'LocalStorageModule'])
.factory('msgData', ['$http', 'msgMock', '$location', function ($http, msgMock, $location) {
var url;
switch ($location.host()) {
case 'localhost':
url = '/texts/commerce?version=1';
break;
case 'www2-dev.xxx.com':
url = '/texts/commerce?version=2';
break;
}
return $http.get(url, {
headers: {
'ClientId': 'some-id'
}
}).then(function (response) {
return response;
}, function (response) {
Raven.captureException(new Error("Failed to load texts with status: " + response.status + " " + response.statusText));
return msgMock;
});
}]);
So, if I use directly '/blahblah' in $http.get(), tests are ok, but if I'm trying to use logic described above, I'm getting errors in tests.
I've tried to inject $location and use spyOn($location.prototype, "host").andReturn("localhost"); in beforeEach() block, or use $browser.url, but both didn't work for me.
What am I missing? I'm stuck wit this... Will appreciate any help..
UPDATE:
Just tried solution from here. This example is very similar to mine, but solution still doesn't work. What am I doing wrong? Thanks for help in advance.
So my test looks like this now:
describe('directive: accordionDir', function() {
var accordionDir, element, scope, $location, $rootScope;
beforeEach(module('checkoutWeb'));
beforeEach(inject(function(_$rootScope_, $compile, $httpBackend, _msgMock_, _$location_) {
$rootScope =_$rootScope_;
scope = $rootScope;
$location = _$location_;
spyOn($location, 'host').andReturn('localhost');
scope.msgData = _msgMock_;
$httpBackend.when('GET', '/api/open/texts/commerce?version=1').respond(scope.fmsData);
element ='<div accordion-dir><div class="details"></div><div class="answer" style="display: none;"></div></div>';
element = $compile(element)(scope);
scope.$digest();
}));
it('should call $location host: ', function () {
inject(function(accordionDir){
expect($location.host()).toHaveBeenCalled();
});
});
});
Erros stack:
PhantomJS 1.9.8 (Windows 7 0.0.0) directive: accordionDir should call
$location host: FAILED TypeError: 'undefined' is not an object
(evaluating 'parsed.protocol')
at urlIsSameOrigin (c:/source/checkout-web/bower_components/angular/angular.js:14560)
at sendReq (c:/source/checkout-web/bower_components/angular/angular.js:8419)
at c:/source/checkout-web/bower_components/angular/angular.js:8146
at c:/source/checkout-web/bower_components/angular/angular.js:11682
at c:/source/checkout-web/bower_components/angular/angular.js:11682
at c:/source/checkout-web/bower_components/angular/angular.js:11768
at c:/source/checkout-web/bower_components/angular/angular.js:12811
at c:/source/checkout-web/bower_components/angular/angular.js:12623
at c:/source/checkout-web/src/app/additional-directives/accordion-directve_test.js:18
at invoke (c:/source/checkout-web/bower_components/angular/angular.js:3965)
at workFn (c:/source/checkout-web/bower_components/angular-mocks/angular-mocks.js:2177)
undefined Error: [$injector:unpr] Unknown provider:
accordionDirProvider <- accordionDir
http://errors.angularjs.org/1.2.28/$injector/unpr?p0=accordionDirProvider%20%3C-%20accordionDir
at c:/source/checkout-web/bower_components/angular/angular.js:3801
at getService (c:/source/checkout-web/bower_components/angular/angular.js:3929)
at c:/source/checkout-web/bower_components/angular/angular.js:3806
at getService (c:/source/checkout-web/bower_components/angular/angular.js:3929)
at invoke (c:/source/checkout-web/bower_components/angular/angular.js:3956)
at workFn (c:/source/checkout-web/bower_components/angular-mocks/angular-mocks.js:2177)
at c:/source/checkout-web/bower_components/angular-mocks/angular-mocks.js:2163
at c:/source/checkout-web/src/app/additional-directives/accordion-directve_test.js:25
undefined

Didn't manage to solve this problem with $location use. So my solution to get working tests here was to use window.location.hostname instead of $location in msgData factory. With window.location.hostname you don't need extra code in tests. Cheers!

Related

Javascript controller cannot be found by karma

I am attempting to test my node.js application using karma and jasmine frameworks. The issue I am facing is that the error below, saying that the name of my controller is not registered. I am trying to do a simple test to see if a scope variable is null.
Error:The controller with the name 'scheduleCtrl' is not registered.
I have been following the tutorials here
link: https://docs.angularjs.org/guide/controller
scheduleController.js
angular.module('myApp').controller('scheduleCtrl',
['$scope', '$http', function($scope, $http){
var indexOfHtml = window.
$scope.selectedPatient = null;
}
scheduleController_spec.js
describe("schedule Controller",function(){
beforeEach(angular.module('myApp'));
var $controller;
var $scope = {};
beforeEach(inject(function($rootScope, $controller){
$scope = $rootScope.$new();
//this creates a controller for us to use
$controller('scheduleCtrl', { $scope: $scope});
}));
it(" should expect null ", function(){
expect($scope.selectedPatient).toEqual(null);
});
//});
});
karma-config.js
files: [
'./node_modules/angular/angular.js',
'./node_modules/angular-ui-router/release/angular-ui-router.js',
'./node_modules/angular-mocks/angular-mocks.js',
'./web/static/scripts/app.js',
'./web/static/views/home.html',
'./web/static/scripts/homeController.js',
'./web/static/scripts/scheduleController.js',
'./spec/spec_test.js'
],
Error Output
Chrome 56.0.2924 (Mac OS X 10.11.2) schedule Controller should expect null FAILED
TypeError: queueableFn.fn.call is not a function
Error: [$controller:ctrlreg] The controller with the name 'scheduleCtrl' is not registered.
http://errors.angularjs.org/1.6.2/$controller/ctrlreg?p0=scheduleCtrl
at node_modules/angular/angular.js:68:12
at $controller (node_modules/angular/angular.js:10690:17)
at node_modules/angular-mocks/angular-mocks.js:2296:14
at Object.<anonymous> (spec/scheduleController_spec.js:18:3)
at Object.invoke (node_modules/angular/angular.js:4862:19)
at Object.WorkFn (node_modules/angular-mocks/angular-mocks.js:3170:20)
Error: Declaration Location
at window.inject.angular.mock.inject (node_modules/angular-mocks/angular-mocks.js:3133:25)
at Suite.<anonymous> (spec/scheduleController_spec.js:15:13)
at spec/scheduleController_spec.js:4:1
Expected undefined to equal null.
at Object.<anonymous> (spec/scheduleController_spec.js:26:35)
Chrome 56.0.2924 (Mac OS X 10.11.2): Executed 1 of 1 (1 FAILED) ERROR (0.046 secs / 0.033 secs)
You probably want to set the Karma basePath configuration option to the correct directory from which other paths (such as those in files) should be resolved.

Can't pass data between controllers?

I don't get what I'm doing wrong, I am trying to globally store and pass data from one controller to another via a service. I stored the data in one controller and confirmed that it was stored at the beginning of my buildReportController. Then, when I click a button on my UI, it opens reportResultsController. However, issue is, I can store the data correctly in buildReportController via locationHistoryService.store() but when I go to reportResultsController and calllocationHistoryService.get(), thepreviousLocationvariable inlocationHistoryService` is empty as if the data was never set. Any ideas on how why or how I can "globally" store data and pass it between controllers? Below is my attempt. Thanks!
In reportView.js
angular.module('reportView', [])
.service('locationHistoryService', function(){
var previousLocation = "";
return {
store: function(location){
previousLocation = location;
},
get: function(){
return previousLocation;
}
};
});
In buildReport.js
angular.module('buildReport', ['reportView'])
.controller('buildReportController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
$rootScope.$on('$locationChangeSuccess', function(e, newLocation, oldLocation){
locationHistoryService.store(oldLocation);
console.log("Old location: ", oldLocation);
});
}
In reportResults.js
angular.module('reportResults', ['reportView'])
.controller('reportResultsController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
console.log("location : ", locationHistoryService.get());
}
The locationHistoryService.get() method in reportResults.js is called before it is set in buildReport.js.
It would be better if you announce when the previousLocation variable has been set.
In reportView.js
angular.module('reportView', [])
.service('locationHistoryService',['$rootScope'] ,function($rootScope){
var previousLocation = "";
return {
store: function(location){
previousLocation = location;
$rootScope.$broadcast('previous-location-set');
},
get: function(){
return previousLocation;
}
};
});
In reportResults.js
angular.module('reportResults', ['reportView'])
.controller('reportResultsController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
$rootScope.$on('previous-location-set', function(){
console.log("location : ", locationHistoryService.get());
});
}
Your webapp should have only one module which is automatically bootstrapped by angular, and other modules as dependencies. The syntax of writing service is incorrect. You wrote .service but returning object which .factory should return. Here is working example of your code http://codepen.io/Chyngyz/pen/NxbdpW?editors=101
Also you wrote the safe for minification syntax of controllers incorrect, the function block of controller should be the last item in the array.

Angular Service Is Not A Function

I've created a simple logging service in Angular:
app.service('$userInteraction', [function() {
var userLog = "";
this.log = function (datetime, screen, logMessage) {
userLog.concat(datetime + "\t" + screen + " Screen\t" + logMessage + "\n");
}
this.getLog = function () {
return userLog;
}
this.clearLog = function () {
userLog = "";
}
}]);
And I use it in one of my controllers like so:
app.controller('myController', ['$scope', '$userInteraction', function($scope, $userInteraction) {
$userInteraction.log(Date(), 'Login', 'Some random message.');
}]);
But when I run my code I get the following error:
TypeError: $userInteraction.log is not a function
Though I could've sworn that it worked before. I'm fairly new to Angular so this might very well be a newbie mistake. Thanks in advance!
this question is old, but help someone... You code run on plunker, problably you have duplicate services name... Check all files angularjs and verify if exist another service with same name.
I had similar problem. Two services with same name and call did not have function called.

Trying to use $cachefactory throws an [$injector:unpr] error

I'm trying to use $cachefactory in my angular project.
I've created a cache service:
services.js
var AppServices = angular.module('Test.services', [])
.factory('testCache', function($cachefactory){
return $cachefactory('test');
});
and I'm trying to inject it in my controller like this:
TestController.js
var TestController =function($scope, $http, testCache) {
var cache = testCache.get('test');
if(cache) {
$scope.test = cache;
}
else {
var value = "Test Value";
$scope.test = value;
cache.put('test', value);
}
};
However when I run the application and try to retrieve data I get:
Error: [$injector:unpr] http://errors.angularjs.org/1.2.17/$injector/unpr?p0=%24cachefactoryProvider%20%3C-%20%24cachefactory%20%3C-%20testCache
u/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:6:443
ec/l.$injector<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:36:139
c#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:34:195
ec/p.$injector<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:36:209
c#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:34:195
d#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:34:409
ec/p.$injector<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:36:222
c#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:34:195
d#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:34:409
f/<.instantiate#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:35:101
Od/this.$get</<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:66:463
$ViewDirectiveFill/<.compile/<#https://rawgit.com/angular-ui/ui-router/0.2.10/release/angular-ui-router.js:2797:1
N#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:54:85
g#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:47:55
v/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:46:253
updateView#https://rawgit.com/angular-ui/ui-router/0.2.10/release/angular-ui-router.js:2733:1
$ViewDirective/directive.compile/</<#https://rawgit.com/angular-ui/ui-router/0.2.10/release/angular-ui-router.js:2697:11
Yd/this.$get</h.prototype.$broadcast#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:113:355
transitionTo/$state.transition<#https://rawgit.com/angular-ui/ui-router/0.2.10/release/angular-ui-router.js:2114:11
ze/e/l.promise.then/D#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:99:243
ze/f/<.then/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:100:407
Yd/this.$get</h.prototype.$eval#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:111:110
Yd/this.$get</h.prototype.$digest#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:108:180
Yd/this.$get</h.prototype.$apply#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:111:449
e/h<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:122:1
e#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:37:438
se/h.defer/c<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js:41:120
<div class="ng-scope" ui-view="">
I've read the error page which claims that I've missed defining a dependency. I'm not sure where I missed it though since app.js injects services module so $cachefactory should be visible, right?
Link to example on plunker
There is a typo. Use $cacheFactory instead of $cachefactory

TypeError: 'undefined' is not a function (evaluating 'mockBackend.expectPost(

I am trying to unit test an angularjs controller with Karma, and jasmine.
Here is my test suite:
describe('Controllers', function(){
var $scope, ctrl;
beforeEach(module('curriculumModule'));
describe('CreateCurriculumCtrl', function(){
var mockBackend, location;
beforeEach(inject(function($rootScope, $controller, _$httpBackend_, $location){
mockBackend = _$httpBackend_;
location = $location;
$scope = $rootScope.$new();
ctrl = $controller('CreateCurriculumCtrl', {
$scope: $scope
});
}));
it('should save the curriculum', function(){
mockBackend.expectPost('bignibou/curriculum/new');
$scope.saveCurriculum();
mockBackend.flush();
expect(location.path()).toEqual("/");
});
});
});
Here is the output of karma start:
PhantomJS 1.9.2 (Linux) Controllers CreateCurriculumCtrl should save the curriculum FAILED
TypeError: 'undefined' is not a function (evaluating 'mockBackend.expectPost('bignibou/curriculum/new')')
at /home/julien/Documents/projects/site-garde-enfants/bignibou/karma/test/spec/curriculum.test.js:16
PhantomJS 1.9.2 (Linux): Executed 2 of 2 (1 FAILED) (0.203 secs / 0.023 secs)
I don't understand why I get this error as I have correctly included the angular-mock.js file in my karma conf:
// list of files / patterns to load in the browser
files: [
'../src/main/webapp/js/libs/jquery-1.10.2.js',
'../src/main/webapp/js/libs/angular.js',
'../src/main/webapp/js/libs/bootstrap.js',
'../src/main/webapp/js/plugins/angularui.select2.js',
'test/vendor/angular-mocks.js',
'../src/main/webapp/js/custom/curriculum.js',
'test/spec/curriculum.test.js'
],
Can anyone please help?
edit: here is my controller:
function CreateCurriculumCtrl($scope, $http, $location, select2Options){
$scope.formData={};
$scope.select2Options = select2Options;
$scope.saveCurriculum = function(){
$http.post('bignibou/curriculum/new', $scope.formData).success(function(data) {
if(data.status=="OK"){}
if(data.status=="KO"){}
$location.path("/");
});
};
}
Changing line 16
from
mockBackend.expectPost('bignibou/curriculum/new');
to
mockBackend.expect('POST','bignibou/curriculum/new').respond({});
somehow fixed the issue...
edit: expectPOST would have worked too... Just a typo: notice the case I used...
Likely your situation will be similar to:
var a = {};
a.b();
a.b is undefined, trying to call it will give you that error.
Line 16 here is $scope.saveCurriculum(), is $scope.saveCurriculum undefined?

Categories

Resources