Unit testing angular $log with jasmine - angularjs

I am running into some challenges unit testing $log.
I wanted to try a simple test that took the value I injected and tested. I am not hooking the spec up to a restful call yet. I am using angular mocks. Here are my before each statements. I have the module defined through angular mocks. Some of what I have been testing has came from this blog
http://www.bradoncode.com/blog/2015/06/08/ngmock-fundamentals-log/.
In my devDependencies
"angular": "^1.5.0",
"angular-mocks": "^1.5.0",
I am using gulp to set up the tests.
gulp.task('test:jasmine', function (done) { // move to return async when execution metrics done
gulp.src('./Scripts/tests/modules/utility/services/ha-http.service.jasmine.test.js')
.pipe(jasmine({
verbose: true
}))
.on('error', gutil.log)
.on('end', function () {
console.log('jasmine end');
done();
});
});
So I know the versions of angular and mocks are matched up.
beforeEach(function () {
angular.mock.module('ha.module.utility');
angular.mock.inject(function ($httpBackend, haHttpService) {
http = $httpBackend;
service = haHttpService;
});
});
beforeEach(inject(function (_$log_) {
$log = _$log_;
}));
afterEach(function () {
http.flush();
http.verifyNoOutstandingExpectation();
http.verifyNoOutstandingRequest();
});
The test itself is just making sure I have $log working.
it('should call logs', function () {
$log.info('it worked');
expect($log.info.logs).toContain(['it worked']);
});
However I am returning
ReferenceError: inject is not defined
************* Update ***********
I did set up $log in the mock module
angular.mock.module('ha.module.utility', function ($provide) {
$provide.decorator('$log', function ($delegate) {
return $delegate;
});
});
angular.mock.inject(function ($httpBackend, haHttpService, $log) {
http = $httpBackend;
service = haHttpService;
console.log($log);
});
I am getting the output I want in the console.log($log) when I run my gulp test. However, $log still returns
ReferenceError: $log is not defined
in the spec.

ReferenceError: inject is not defined
means that inject global was not defined, literally. It is defined in angular-mocks.js on condition.
The problem is caused by testing rig and not the specs. angular-mocks.js may not be loaded, or it may be loaded before Jasmine.

Related

AngularJS: Controller is not Registered in Testing Environment

I'm in the process of upgrading a legacy app that uses angularjs to the latest LTS release. I seem to have the application working, but i'm struggling with
Error: [$controller:ctrlreg] The controller with the name 'LogoutController' is not registered.
errors in the test environment.
I have an angular module:
angular
.module('LoginModule', ['ui.bootstrap']);
a controller
(function () {
'use strict';
angular
.module("LoginModule")
.controller('LogoutController', LogoutController);
LogoutController.$inject = ['LogoutService'];
function LogoutController(LogoutService) {
this.logout = function () {
LogoutService.logout();
};
}
})();
and a spec
describe('MyApplication', function () {
'use strict';
var ctrl, mockLogoutService;
beforeEach(module('LoginModule'));
beforeEach(function () {
module(function ($provide) {
$provide.factory('LogoutService', function () {
return ({
logout: jasmine.createSpy('LogoutService.logout')
});
});
});
});
describe('LogoutController', function () {
beforeEach(inject(function ($controller, LogoutService) {
mockLogoutService = LogoutService;
ctrl = $controller('LogoutController', {
LogoutService: mockLogoutService
});
}));
it('instantiates', function () {
expect(ctrl).not.toBe(undefined);
});
});
});
When the spec runs, i get
Error: [$controller:ctrlreg] The controller with the name 'LogoutController' is not registered.
The files are in a directory structure like:
- root
-angular
-module
-login
-dialog
-theme
-test
-jasmine
-login
-dialog
-theme
and i configure karma to load files using:
files: [
'./node_modules/angular/angular.js',
'./node_modules/angular-mocks/angular-mocks.js',
'./node_modules/angular-sanitize/angular-sanitize.min.js',
'./node_modules/angular-resource/angular-resource.min.js',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap.js',
'./angular/application.js',
'./angular/module/**/*.js',
'./test/jasmine/**/*.js'
],
I ran across Angular controller is not registered error suggesting that the IIFE was problematic, so i tried implementing the accepted answer without joy -- which make sense, as the project has a couple dozen other controllers wrapped in IIFE that all test without needing changes.
So i'm stumped, and am left wondering if i've been starting at the code too long to see something right in front of my face. Looking for any insight into why this code produces the "controller not registered" error.

Is there a way to see if the angular mock modules are loaded?

I have the following code in my spec file
beforeEach(function () {
module('app');
inject(function ($injector) {
user = $injector.get('app.user');
});
});
user is undefined, and isn't being injected. So I want to make sure that the app module actually loaded.
If the module is not loaded, you get $injector:nomod error. If the module is loaded but the service cannot be found, you get $injector:unpr error. It is as easy as that. There is always a breadcrumb trail, no need to probe Angular to know if it fails silently or not.
Just make sure you're using the right module name. You can use beforeEach to load your module. Also, with $injector you can get an instance of your service or controller you're trying to test:
'use strict';
describe('MyControllerName', function () {
var MyControllerName;
beforeEach(module('myAppMomduleName'));
beforeEach(inject(function ($injector) {
MyControllerName = $injector.get('MyControllerName');
}));
it('should create an instance of the controller', function () {
expect(MyControllerName).toBeDefined();
});
});

Mock service injected into Angular module run block

In my module.run block it is calling a method on a service I have made. When running my tests I want it to reference a mock service instead of the real one which is making http requests. I am currently trying to test a controller, not the actual run block itself - how can I inject the mock service into the run function? I have tried using $provide.factory but it doesn't seem to do anything and is still loading the service as normal.
I am using Jasmine to write my tests.
app.js
angular.module("app")
.run(function(MyService) {
MyService.log("starting app");
});
test.js
describe("MyController", function() {
beforeEach(function() {
module(function ($provide) {
$provide.factory("MyService", { log: function(){} });
});
});
// I want module 'app' to execute its run function using injected value for MyService
beforeEach(module("app"));
beforeEach(inject(function($controller, $rootScope) {
MyController = $controller("MyController", { $scope: $rootScope.$new() });
}));
...........
});
In this case is important order.
You need load your app first
beforeEach(module("app"));
and then overwrite MyService definition.
beforeEach(
module({
"MyService": {
log: function(message) {
console.log("MyFakeService called: " + message);
}
}
})
);
Otherwise app service implementation is last registred and used.
working example is here - look to the console http://plnkr.co/edit/BYQpbY?p=preview

Unavailable Module Error: Overriding an AngularJS Factory with Protractor for E2E testing

I am trying to mock a factory within one of my angularjs modules. The full angularjs application is
angular.module('administration', ['administrationServices'])
The dependency:
var module = angular.module('administrationServices')
contains a factory service:
module.factory('Example', [function(){
return{
list:function(){
return ['This is real']
}
}
}])
This is the service I am attempting to override in my protractor e2e test. The actual test looks something like this:
describe('Example page', function(){
beforeEach(function() {
var mock = function(){
// get the module and provide the mock
var module = angular.module('administrationServices').config(['$provide', function($provide){
$provide.factory('Example',[function(){
return {
list: function(){
return ['This is a Mock Test']
}
}
}])
}])
}
// override the mock service
browser.addMockModule('administrationServices', mock)
})
it('should go to the page and see mock text', function() {
// code that goes to page and checks if the service works
// ...
})
})
The issue I'm having occurs when I $ protractor conf.js, I get the error:
Error while running module script administrationServices: [$injector:nomod] http://errors.angularjs.org/1.3.4/$injector/nomod?p0=administrationServices
This is where I'm confused. Every blog post about protractor's addMockModule uses similar syntax it seems. There are other factory services in administrationServices and those seem to get overwritten because the app can't open to the page due to those services (user and group services) not working.
Anyways, if somebody has seen this and can help direct me in the right direction, that would help; I am fairly new to mock services, protractor and e2e testing.
I think the problem is that your mock function does not return anything. It doesn't share the new module outside the function scope.
var mock = function(){
// get the module and provide the mock
return angular.module('administrationServices').config(['$provide', function($provide){
$provide.factory('Example',[function(){
return {
list: function(){
return ['This is a Mock Test'];
}
}
}])
}])
};
// override the mock service
browser.addMockModule('administrationServices', mock)
Just make it return the new module and it should be fine.

AngularJS + Jasmine test scripts failing fn is not function

I'm using Yeoman to create an angular project and have modules defined as:
angular.module('angularApp')<br />
.controller('LogOutCtrl', function ($scope) {//do stuff});
Test scripts via Yeoman are as follows:
describe('Controller: LogOutCtrl', function () {
// load the controller's module
beforeEach(module('angularApp', ['ui', 'appSettings']));
var LogOutCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller) {
scope = {};
LogOutCtrl = $controller('LogOutCtrl', {
$scope: scope
});
}));
it('should pass', function () {
expect(2+2).toBe(4); //aka some test
});
});
This is returning as an error via grunt/karma:
Error: Argument 'fn' is not a function, got string
I have looked at a few other ways of writing these as well:
How do I test an AngularJS service with Jasmine?
Any help would be appreciated, as I am new to Angular and Jasmine testing. I believe this is probably an issue with Yeoman's templates for test scripts.
Thanks!
This was an issue with the templates that Yeoman was using. They have been resolved after an update from 1.0 beta.

Resources