I need help, been searching and thinking for hours but didn't come up with a good solution. I am experiencing error "Expected undefined to be defined" which is repeatedly occurs when I call $scope in my It() functions.
Spec.js
describe("C0001Controller", function(){
var $scope,
$rootScope,
$injector,
$controller,
$httpBackend,
$loading,
C0001Controller;
describe("initialize controllers",function(){
beforeEach(function(){
angular.module('app.c0001App');
})
beforeEach(inject(function(_$rootScope_, _$injector_, _$controller_, _$httpBackend_, _$loading_)
{
$rootScope = _$rootScope_;
$injector = _$injector_;
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$loading = _$loading_;
$scope = $rootScope;
C0001Controller = $controller('C0001Controller', {
$scope: $scope,
$loading : $loading
});
}));
});
it("should use the user ",function(){
var languages = [{id: "en", name: "English"}, {id: "jp", name: "Japanese"}];
expect(languages).toBeDefined();
it("should read if there are languages used", function(){
expect($scope).toBeDefined();
});
describe("checking connection to module and controller", function(){
it("should be connected to module", function(){
expect("app.c0001App.C0001Controller").toBeDefined();
});
it("contains C0001Spec Spec", function(){
expect(true).toBe(true);
});
it("should be equal to user", function(){
var user = {};
var c0001Data = user;
expect(c0001Data).toBe(user);
});
});
});
I was thinking if the format I did in the karma.conf.js file has a mistake.
// list of files / patterns to load in the browser
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'app/*.js',
'tests/*.js'
],
here's my Controller.js
angular.module('app.c0001App', [
'ui.router'
])
.config(function($stateProvider) {
$stateProvider.state('/c0001', {
url : '/c0001'
, templateUrl : 'pages/C0001.html'
, data : {
pageTitle: 'LOGIN'
}
});
})
.controller('C0001Controller', function ($rootScope, $scope, $http, $window, $location, $loading) {
var promise = $http.get('changeLanguage.do?lang=en');
promise.success(function(data, status, headers, config) {
//some codes here
Thank you in advance.
Related
angular.module('MyApp')
.controller('loginCtrl', function($scope, $rootScope, $location, $window, $auth) {
$scope.login = function() {
$auth.login($scope.user)
.then(function(response) {
if(response.data.users.status === 'success'){
$rootScope.currentUser = response.data.username;
$window.localStorage.user = JSON.stringify(response.data.users);
$location.path('/');
}
}).catch(function(response){
if(response.data.users.status === 'error'){
$scope.error = response.data.users.error;
}
})
};
});
I get the error:
users is undefined error
when testing above code with Karma and Jasmine.
The spec is below:
describe('LogController', function() {
var $scope, controller, $location, $window;
beforeEach(module('MyApp'));
beforeEach(inject(function($rootScope, $controller, _$location_ , _$window_ , _$httpBackend_) {
$scope = $rootScope.$new();
$window = _$window_
$httpBackend = _$httpBackend_;
$location = _$location_;
controller = $controller('loginCtrl', {
$scope: $scope,
$location: $location,
$window: $window
});
}))
it('should log in a user and redirect to homepage', function() {
$httpBackend.when('POST','/user/auth').respond(200);
//whitelist all view
$httpBackend.whenGET(/partials.*/).respond(200, '');
$scope.username = 'test';
$scope.password = '123456';
$scope.login();
$httpBackend.flush();
$scope.$apply();
expect($location.path()).toBe('/x');
});
})
What is users undefined? And how do I mock out a response from $window.localStorage so it won't be?
Youshould mock the response for login
$httpBackend.when('POST','/user/auth').respond(200, mockResponseData);
where:
mockResponseData = {
"data": {
"username": "someValue",
"users": {
"status": "success"
}
}
}
I'm trying to test the data received from an $http request in my controller.
I don't have too much experience testing with Angular so I'm struggling to under stand how to do it.
$scope. always comes back undefined and when I've tried fetching the data from the test, that seems to fail also. What am I missing?
Controller:
'use strict';
var myApp = angular.module('myApp.view1', ['ngRoute']);
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}]);
myApp.controller('View1Ctrl', [
'$scope',
'$http',
function($scope, $http) {
$http.get('view1/data.json')
.then(function(res){
$scope.data = res.data.data
});
}]);
Test:
'use strict';
describe('myApp.view1 module', function() {
beforeEach(module('myApp.view1'));
describe('view1 controller', function(){
var scope, testCont;
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
testCont = $controller('View1Ctrl', {$scope: scope});
}));
it('should....', function(){
expect($scope.data).toBeDefined();
});
});
});
The HTTP requests will not fire unless you call $httpBackend.flush().
More information can be found here: http://docs.angularjs.org/api/ngMock.$httpBackend
Test:
'use strict';
describe('myApp.view1 module', function() {
var $httpBackend, $rootScope, createController, jsonHandler;
beforeEach(module('myApp.view1'));
describe('view1 controller', function(){
var scope, testCont;
beforeEach(inject(function($rootScope, $controller, $injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
jsonHandler= $httpBackend.when('GET', '/view1/data.json')
.respond({data: '[XXX,XXX,XXX]'});
// Get hold of a scope (i.e. the root scope)
$rootScope = $injector.get('$rootScope');
// The $controller service is used to create instances of controllers
var $controller = $injector.get('$controller');
createController = function() {
return $controller('View1Ctrl', {'$scope' : $rootScope });
};
}));
it('should....', function(){
$httpBackend.expectGET('/view1/data.json');
var controller = createController();
$httpBackend.flush();
});
});
});
I have a controller that uses AngularFire's $firebaseObject.
When the controller initializes, it sets the reference to Firebase, and uses $loaded function to verify that data from Firebase is actually there. Here is a simplified code of the controller:
myModule.controller('VotingQuestionsCtrl', ['$scope', '$rootScope', '$firebaseObject',
function($scope, $rootScope, $firebaseObject) {
var baseRef = new Firebase("https://somefirebaserepo.firebaseio.com/pathtomyobjects"),
topicsRef = baseRef.child("topics");
var topics = $firebaseObject(topicsRef);
$scope.dataLoaded = false;
topics.$loaded().then(function() {
$scope.dataLoaded = true;
topics.$bindTo($scope, 'topics').then(function() {
//do some stuff
});
}, function(error) {
$scope.dataLoaded = true;
console.log("oh no!");
});
This controller works pretty good in real life. The problem is testing it with Karma. No matter what I tried, my test spec never reaches the callback for topics.$loaded (neither the success function nor the error function).
Here is the current state of my test spec:
describe('VotingQuestionsCtrl', function() {
var $controller, $scope, $rootScope, $firebaseObject, $stateParams, $q, baseRef, $timeout;
beforeEach(module('wsApp.controllers'));
beforeEach(inject(function ($injector) {
MockFirebase.override();
$controller = $injector.get('$controller');
$q = $injector.get('$q');
$rootScope = $injector.get('$rootScope');
$timeout = $injector.get('$timeout');
$scope = $rootScope.$new();
$firebaseObject = $injector.get('$firebaseObject');
$rootScope.user = {username: "user"};
$rootScope.selectedSim = {phase: "phase1"};
baseRef = new Firebase("https://somefirebaserepo.firebaseio.com/pathtomyobjects");
baseRef.set({topics: {simId: {phase1: "bla"}}, users: {}});
baseRef.flush();
}));
it('loads the controller', function(done) {
$controller('VotingQuestionsCtrl', {$scope: $scope, $rootScope: $rootScope, $firebaseObject: $firebaseObject});
$scope.$digest();
setTimeout(function() {
expect($scope.dataLoaded).toBeTruthy();
done();
}, 200);
});
});
I've tried all sorts of flushing, digesting, whatever... the test goes through the rest of the controller, but the async part just doesn't work.
Before i started, i have followed the advice found here without any success: How can I test a controller with resolve properties in AngularJS?
Im my app.js, i have a simple resolve:
var app = angular.module('myApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('index', {
url: '/index',
templateUrl: 'html/home.html',
controller: 'HomeController',
resolve: {
homeInfo: function() {
return {
subtitle : 'Welcome to tables, ladders and chairs'
};
}
}
})
And in my HomeController.js:
app.controller('HomeController', function($scope, srv1, srv2, homeInfo, $rootScope) {
$rootScope.$broadcast('brdSubtitle', homeInfo.subtitle);
});
My test:
describe('HomeController', function () {
var $rootScope, $scope, $controller, homeController;
beforeEach(module('myApp'));
beforeEach(inject(function (_$rootScope_, _$controller_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$controller = _$controller_;
homeController = $controller('HomeController', {'$rootScope': $rootScope, '$scope': $scope, homeInfo: { subtitle : 'Welcome to tables, ladders and chairs' }});
}));
it('should exist', function() {
expect(homeController).toBeDefined();
});
it('should have a subtitle', function() {
expect(homeController.homeInfo.subtitle.text()).toBe('Welcome to tables, ladders and chairs');
});
});
Error is:
TypeError: homeController.homeInfo is undefined in /path/to/specs.js
You should try to mock the service value in a beforeEach, because apparently putting the value in the $controller parameter does not work.
beforeEach(module(function($provide) {
$provide.value('homeInfo', {
subtitle : 'Welcome to tables, ladders and chairs'
});
}));
That's right, you didn't do this.homeInfo = homeInfo; in controller, and homeController.homeInfo should be undefined in this case.
There's no reason why mocked homeInfo local dependency should be tested. Test what happens in controller instead:
beforeEach(inject(function (_$rootScope_, _$controller_) {
...
brdSubtitleListener = jasmine.createSpy('brdSubtitleListener');
$scope.$on('brdSubtitle', brdSubtitleListener);
homeController = $controller('HomeController', {'$rootScope': $rootScope, '$scope': $scope, homeInfo: { subtitle : 'Welcome to tables, ladders and chairs' }});
}));
it('should broadcast a subtitle', function() {
expect(brdSubtitleListener).toHaveBeenCalledWith(jasmine.any(Object), 'Welcome to tables, ladders and chairs');
});
I've a unit tests that's keep failing with the error above not sure what exactly is wrong with this, by the looks of the error, its says that I need to declare a function. Can someone point me what is wrong with my code please:
unit test
describe('Test loginService', function() {
var $location, loginService, $scope, authentication, $rootScope;
beforeEach(function() {
module('app');
inject(function(_$location_, _$rootScope_, _loginService_,
_authentication_) {
$location = _$location_;
authentication = _authentication_;
loginService = _loginService_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
});
});
it('Should successfully login with correct credentials', function() {
$scope.username = 'a#a.com';
$scope.password = 'a';
spyOn($location, 'url');
loginService.login($scope);//Complains about this line
expect($location.url).toHaveBeenCalled();
expect($location.url).toHaveBeenCalledWith('/home');
});
login service
app.factory('loginService', function(parserService, $location,
authentication, $rootScope) {
return {
login : function(scope) {
parserService.getData().then(function(data) { //This line
if (scope.username === data.username
&& scope.password === data.password) {
...
$location.url("/home");
} else {
scope.loginError = "Invalid Credentials";
}
});
}
});
Json file reader service
app.factory('parserService', function($http, $q) {
return {
getData: function() {
var deferred = $q.defer();
$http.get('res/file.json').success(function(data) {
deferred.resolve(data);
}).error(function(){
deferred.reject();
});
return deferred.promise;
}
}
});
error log
Chrome 36.0.1985 (Windows 7) Test loginService Should successfully login with correct credentials FAILED
TypeError: undefined is not a function
at Object.login (D:../js/services/loginService.js:6:18)
at null.<anonymous> (D:/../test/unit/loginTest.js:92:16)
since you can't format a comment, I'm using an answer... :D
have you tried this?
var $location, loginService, $scope, authentication, $rootScope, parserService;
beforeEach(function() {
module('app');
inject(function(_$location_,
_$rootScope_,
_parserService_,
_loginService_,
_authentication_) {
$location = _$location_;
authentication = _authentication_;
loginService = _loginService_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
parserService = _parserService_;
});
});