I am trying to get/set "testModel.number" in my unit test but I can't seem to get it. When I run the test I get this error message:
Error: [$injector:unpr] Unknown provider: testModelProvider <- testModel
Here is the controller:
angular.module("TestApp", [])
.controller("IndexController", function ($scope, testModel) {
$scope.name = "test";
testModel = {
number: 0
}
if (testModel.number === 1) {
$scope.name = "test1";
} else {
$scope.name = "test2";
}
});
Here is the unit test:
describe('IndexController', function () {
var scope, createController;
beforeEach(module("TestApp"));
beforeEach(inject(function ($rootScope, $controller, testModel) {
scope = $rootScope.$new();
createController = function () {
return $controller('IndexController', {
'$scope': scope,
'testModel': testModel
})
}
}));
it('example test', function () {
var controller = createController();
testModel.number = 1;
expect(scope.name).toBe('test1');
});
});
I'm fairly new to unit testing so any suggestions would be great! Thanks in advance!
I think you need to pass the testModel object to the method creating the controller. Jasmine does not know how to inject custom providers.
describe('IndexController', function () {
var scope, createController;
beforeEach(module("TestApp"));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
createController = function (testModel) {
return $controller('IndexController', {
'$scope': scope,
'testModel': testModel
})
}
}));
it('example test', function () {
var testModel = { number: 1 };
var controller = createController(testModel);
expect(scope.name).toBe('test1');
});
});
If you will have multiple tests that will need the testModel object, you can also define it at a global level as follows:
describe('IndexController', function () {
var scope, createController;
var testModel = { number: 1 };
beforeEach(module("TestApp"));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
createController = function () {
return $controller('IndexController', {
'$scope': scope,
'testModel': testModel
})
}
}));
it('example test', function () {
var controller = createController();
expect(scope.name).toBe('test1');
});
});
Related
I'm trying to verify that a factory function is called from within a modal function, if passed a valid file object. The factory is injected into the modal controller and when the test is run the factory is undefined. What is the proper way to test that a factory function is called from within a modal?
modal controller
angular.module('vicModule')
.controller('vicModalController', vicModalController);
vicModalController.$inject = [
'$uibModalInstance',
'$uibModal',
'utilFunctionsFactory'
]
function vicModalController($uibModalInstance, $uibModal, utilFunctionsFactory) {
mvm.uploadVICs = uploadVICs;
function uploadVICs(file, error) {
if (file == null) {
data.errorMessage = 'file is not found or not supported';
return;
}
if(error.length > 0) {
$uibModalInstance.close();
data.errorMessage = 'reading file error';
return;
} else {
var fileData = utilFunctionsFactory.validateCSV(file, error);
}
}
}
modal controller test
describe('vicModalController', function() {
var $controller, vicModalController, vicFactory, utilFunctionsFactory, $q, $scope, $httpBackend, deferred, $uibModalInstance;
beforeEach(module('fotaAdminPortal'));
beforeEach(module('vicModule'));
beforeEach(inject(function(_$controller_, _vicFactory_, _utilFunctionsFactory_, _$q_, _$rootScope_, _$httpBackend_) {
$controller = _$controller_;
vicFactory = _vicFactory_;
utilFunctionsFactory: _utilFunctionsFactory_;
$q = _$q_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$uibModalInstance = { // Create a mock object using spies
close: jasmine.createSpy('modalInstance.close'),
dismiss: jasmine.createSpy('modalInstance.dismiss'),
result: {
then: jasmine.createSpy('modalInstance.result.then')
}
};
vicModalController = $controller('vicModalController', {
vicFactory: vicFactory,
utilFunctionsFactory: utilFunctionsFactory,
$uibModalInstance: $uibModalInstance
});
}));
it('should be defined', function() {
expect(vicModalController).toBeDefined();
});
describe('uploadVICS()', function() {
beforeEach(inject(function(_utilFunctionsFactory_) {
utilFunctionsFactory = _utilFunctionsFactory_;
spyOn(utilFunctionsFactory, 'validateCSV').and.callFake(function() {
return {};
});
}));
it('should call validateCSV() with valid file', function() {
vicModalController.uploadVICs({}, []);
expect(utilFunctionsFactory.validateCSV()).toHaveBeenCalledWith({}, []);
});
});
});
edit
I had the assignment wrong in the beforeEach:
utilFunctionsFactory: utilFunctionsFactory; //incorrect colon
utilFunctionsFactory = utilFunctionsFactory; // should be assigned
A couple of issues I see:
You are doing:
utilFunctionsFactory: _utilFunctionsFactory_;
instead of:
utilFunctionsFactory = _utilFunctionsFactory_;
Also you are asserting that the result of validateCSV is called:
expect(utilFunctionsFactory.validateCSV()).toHaveBeenCalledWith({}, []);
Instead of validateCSV itself:
expect(utilFunctionsFactory.validateCSV).toHaveBeenCalledWith({}, []);
I called one $mdDialog inside a function. I want to unit-test $mdDialog ok and cancel cases.
The below is my controller code (app.controller.js).
(function () {
'use strict';
app.controller('AppCtrl', AppCtrl);
AppCtrl.$inject = ['$scope', '$mdDialog'];
function AppCtrl($scope, $mdDialog) {
$scope.saveEntry = function (ev) {
var confirm = $mdDialog.prompt()
.title('Save Entry')
.textContent('If you want, you can add a description to explain what you changed.')
.placeholder('Version Description')
.ariaLabel('Version Description')
.initialValue('')
.targetEvent(ev)
.ok('Save')
.cancel('Cancel');
$mdDialog.show(confirm).then(function (result) {
$scope.status = true;
}, function () {
$scope.status = false;
});
};
}
})();
The following is the spec code (app.controller.spec.js) :
describe('Unit test AppController: mdDialog', function () {
var $controller, $mdDialog;
beforeEach(function () {
module('App');
inject(function (_$controller_, _$mdDialog_) {
$controller = _$controller_;
$mdDialog = _$mdDialog_;
});
});
it(': Opened', function () {
var $scope = {};
var controller = $controller('AppCtrl', { $scope: $scope });
var $mdDialogOpened = false;
$mdDialog.show = jasmine.createSpy().and.callFake(function () {
$mdDialogOpened = true;
});
$scope.saveEntry();
$scope.$digest();
expect($mdDialog.show).toHaveBeenCalled;
expect($mdDialogOpened).toBe.true;
});
});
when I running the above code I'm getting the following error:
TypeError: Cannot read property 'then' of undefined
I referred this GitHub issue https://github.com/angular/material/issues/1482. But I'm not getting solution for my problem
Thanks in advance
The problem is that you are injecting one version of $mdDialog, and trying to test on another one.
You could try something like this:
describe('Unit test AppController: mdDialog', function () {
var ctrl, mdDialog, scope;
beforeEach(function () {
module('App');
inject(function ($rootScope, $controller, $mdDialog) {
scope = $rootScope.$new();
mdDialog = $mdDialog; //keep the reference, for later testing.
spyOn(mdDialog, 'show');
mdDialog.show.and.callFake(function () {
return {
then: function (callBack) {
callBack(true); //return the value to be assigned.
}
}
});
ctrl = $controller('AppCtrl',{$scope:scope, $mdDialog:mdDialog}); //Inject the dependency
});
});
it(': Opened', function () {
scope.saveEntry(); //exercise the method.
scope.$digest();
expect(mdDialog.show).toHaveBeenCalled();
expect(scope.status).toBe(true);
});
});
Something very similar should work.
hope this help.
new to angular and unit testing, I have a function in my controller as following:
function TermList($scope, $http, $q, $timeout, $modal, uiGridConstants, uiGridGroupingConstants, storedValue, sendEmail, getUser) {
$scope.greeting = "hello";
$scope.sum = function sum() {
$scope.z = $scope.x + $scope.y;
};
$scope.password = '';
$scope.grade = function () {
var size = $scope.password.length;
if (size > 8) {
$scope.strength = 'strong';
} else if (size > 3) {
$scope.strength = 'medium';
} else {
$scope.strength = 'weak';
}
};
}
and I need to write unit for my scope functions, I have following test case written:
describe('routerApp', function () {
var scope,
controller;
beforeEach(function () {
module('routerApp');
});
describe('TermList', function () {
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('TermList', {
'$scope': scope
});
}));
it('sets the name', function () {
expect(scope.greeting).toEqual('hello');
});
});
});
and I get the following error when I run my unit test:
TypeError: Cannot read property 'greeting' of undefined
Your inject parameters look suspect; I'm not entirely convinced that they'd inject anything.
If you want to preserve the name of the parameter, then you can prefix and suffix each parameter with underscores instead.
beforeEach(inject(function (_$rootScope_, _$controller_) {
scope = _$rootScope_.$new();
controller = _$controller_('TermList', {
'$scope': scope
});
}));
I'm trying to test if a $scope method has been called
my controller :
(function () {
var app = angular.module('productsController',[]);
app.controller('AddProductController', ['$scope',function ($scope) {
$scope.test = function(){
return true;
};
$scope.test();
}]);
})();
and my test :
describe("Products Controller", function () {
beforeEach(function () {
module('productsController');
});
beforeEach(function () {
var createController, scope, rootScope;
});
describe('AddProductController', function () {
beforeEach(function () {
inject(function ($controller, _$rootScope_) {
rootScope = _$rootScope_;
scope = _$rootScope_.$new();
createController = function () {
return $controller("AddProductController", {
$scope: scope,
});
};
});
});
it('should call test', function(){
spyOn(scope, 'test');
createController();
scope.$apply()
expect(scope.test).toHaveBeenCalled();
})
});
});
but I got this error:
Error: test() method does not exist
$scope.test exists any when I run the app in a browser the method is been called, but if falis whne testing, any clues?
May be there is some problem in the ordering, Could you try and check if the below works?
describe('AddProductController', function() {
var createController, scope, rootScope;
beforeEach(function() {
inject(function($controller, _$rootScope_) {
rootScope = _$rootScope_;
scope = _$rootScope_.$new();
createController = function() {
return $controller("AddProductController", {
$scope: scope,
});
};
});
});
it('should call test', function() {
createController(); // To create function test in the scope
spyOn(scope, 'test');
createController(); // To execute test after spy is added.
expect(scope.test).toHaveBeenCalled();
})
});
I have the following controller:
(function () {
"use strict";
angular.module('usp.configuration').controller('ConfigurationController', ConfigurationController);
ConfigurationController.$inject = ['$scope', '$rootScope', '$routeParams', 'configurationService'];
function ConfigurationController($scope, $rootScope, $routeParams, configurationService) {
//Get Master Gas List
configurationService.getMasterGasList().then(function (response) {
$scope.masterGasList = response.data.data;
});
$scope.convertToInt = function (str) {
if (!isNumberEmpty(str) && !isNaN(str)) {
return parseInt(str, 10);
}
return "";
}
$scope.convertToString = function (num) {
if (!isNumberEmpty(num) && !isNaN(num)) {
return num + "";
}
return "";
}
}
}());
And below is the test case for the controller:
describe("test suite for Configuration test controller", function() {
var scope = null;
var configurationService;
beforeEach(module("usp.configuration"));
beforeEach(inject(function($rootScope, $controller, _configurationService_) {
// Services
// _'s are automatically unwrapped
configurationService = _configurationService_;
// Controller Setup
scope = $rootScope.$new();
$controller("ConfigurationController", {
$scope: scope,
configurationService : configurationService
});
}));
it("should convert to int", function() {
expect(scope.convertToInt("2")).toEqual(2);
});
it("should return empty string", function() {
expect(scope.convertToInt("asd")).toEqual("");
});
});
I don't want to call that service while I am running the test case.
I am new to unit testing, I don't know how can I do this.
Please help me to do this?
You need to mock the dependencies with $provide
beforeEach(function () {
configurationServiceMock = {
getSomething: function () {
return 'mockReturnValue';
}
};
module(function ($provide) {
$provide.value('configurationService', configurationServiceMock);
});
});
see: Injecting a mock into an AngularJS service
Solution for your needs:
var configurationServiceMock = {
getMasterGasList: function () {
return {
then: function(callback) {}
};
}
};
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('ConfigurationController', {
'$scope': scope,
'configurationService': configurationServiceMock
});
}));