I have a simple controller with init function:
init() {
this.PositionService.getPagePosition(this.$state.params.name).then(( res ) => {
this.position = res.data.position;
})
}
And my positions service:
getPagePosition( name ) {
return this.$http.get(this.appConfig.api.positions + '/' + name);
}
My test:
describe('position list page', function() {
var scope,
$httpBackend,
controller;
beforeEach(module('module'));
beforeEach(inject(function( $controller, $rootScope, _$httpBackend_, _PositionService_ ) {
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
controller = $controller('PositionsController', {
$scope : scope,
PositionService : _PositionService_,
});
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('PositionsController', function() {
it('should get the position', function() {
$httpBackend.whenGET(/http:\/\/localhost:3000\/positions\/[a-z]+/).respond(200, {
data: {
id: 2
}
});
controller.init();
$httpBackend.flush();
expect(controller.position.id).to.equal(1);
});
});
});
My problem is that i get this error:
Error: Unexpected request: GET http://localhost:3000/api/positions/undefined
No more request expected
Why the paramater is undefiend and why i get this error?
With Jasmine and ES5 the test will look like:
angular.module('module', [])
.controller('PositionsController', function(PositionService, $state) {
this.init = function() {
PositionService.getPagePosition($state.params.name)
.then(function(res) {
this.position = res.data.position;
}.bind(this))
}
}).service('PositionService', function($http, appConfig) {
this.getPagePosition = function(name) {
return $http.get(appConfig.api.positions + '/' + name);
}
});
describe('Position list page', function() {
var scope,
$httpBackend,
controller;
beforeEach(module('module'));
beforeEach(function() {
angular.module('module').value('appConfig', {
api: {
positions: 'http://localhost:3000/positions'
}
})
})
beforeEach(inject(function($controller, $rootScope, _$httpBackend_, _PositionService_) {
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
controller = $controller('PositionsController', {
$scope: scope,
PositionService: _PositionService_,
$state: {
params: {
name: 'someParamValue'
}
}
});
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('PositionsController:', function() {
it('Gets the position - init()', function() {
var stubId = 2
$httpBackend.whenGET(/http:\/\/localhost:3000\/positions\/[a-z]+/).respond(200, {
position: {
id: stubId
}
});
controller.init();
expect(controller.position).not.toBeDefined();
$httpBackend.flush();
expect(controller.position).toBeDefined();
expect(controller.position.id).toEqual(stubId);
});
});
});
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>
Related
I'm using the ui-bootstrap modal window and I'm trying to test a method that fires that modal window. My controller:
app.controller('AddProductController', ['$scope', 'ProductsService', '$uibModal', function ($scope, ProductsService, $uibModal) {
$scope.product = {};
$scope.searchCategories = function () {
ProductsService.getRootCategories().then(function (data) {
$scope.categories = data.data;
});
$scope.modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'categoryContent.html',
controller: 'AddProductController',
scope: $scope
});
$scope.modalInstance.result.then(function (category) {
$scope.searchCategory = null;
$scope.product.category = category;
}, function () {
});
};
$scope.ok = function(){
$scope.modalInstance.close($scope.product.category);
};
$scope.cancel = function(){
$scope.modalInstance.dismiss();
}]);
And my test:
describe("Products Controller", function () {
beforeEach(function () {
module('productsController');
});
beforeEach(function () {
var ProductsService, createController, scope, rootScope,
module(function ($provide) {
$provide.value('ProductsService', {
getRootCategories: function () {
return {
then: function (callback) {
return callback({data: {name: 'category1'}});
}
};
},
});
$provide.value('$uibModal', {
open : function(){
return {
then: function (callback) {
return callback({data: {name: 'category1'}});
}
};
}
});
return null;
});
});
describe('AddProductController', function () {
beforeEach(function () {
inject(function ($controller, _$rootScope_, _ProductsService_) {
rootScope = _$rootScope_;
scope = _$rootScope_.$new();
ProductsService = _ProductsService_;
createController = function () {
return $controller("AddProductController", {
$scope: scope,
});
};
});
});
it('calling searchCategories should make $scope.categories to be defined', function () {
createController();
expect(scope.categories).not.toBeDefined();
scope.searchCategories();
expect(scope.categories).toBeDefined();
});
});
});
All my tests pass,except this one, where I get TypeError: $scope.modalInstance.result is undefined.
Any clues?
It seems you're not defining result in your mock modal. Try something like this:
$provide.value('$uibModal', {
open: function () {
return {
result : {
then: function (callback) {
return callback({ data: { name: 'category1' } });
}
}
};
}
});
I am having trouble in my test for an ionic modal controller. The problem (or at least the problem I'm focusing on) is mocking up the $ionicModal.fromTemplateUrl function. According to ionic documentation, it's supposed to return a promise that resolves into an instance of the modal.
Here is my factory:
(function() {
'use strict';
angular.module('penta.app.main').factory('addEquipment', AddEquipment);
function AddEquipment($rootScope, $ionicModal) {
return {
openModal: function() {
var scope = $rootScope.$new(true);
scope.controller = new AddEquipmentController(scope, $ionicModal);
}
};
function AddEquipmentController(scope, $ionicModal) {
var controller = this;
$ionicModal.fromTemplateUrl('app/tracking/activityLog/addItems/equipment/addEquipment.html', {
scope: scope,
animation: 'slide-in-up'
}).then(function(modal) {
controller.modal = modal;
controller.openModal();
});
controller.openModal = function() {
controller.modal.show();
};
controller.closeModal = function() {
controller.modal.hide();
};
return controller;
}
}
})();
And here is my test:
(function() {
'use strict';
describe('AddEquipment', function() {
var controllerConstructor;
var addEquipment;
var mock;
var mockIonicModal;
var mockModal;
var scope;
var dfd;
beforeEach(module('penta.app.main'));
beforeEach(module('unitTest'));
beforeEach(module('app/tracking/activityLog/addItems/equipment/addEquipment.html'));
beforeEach(function() {
mockModal = sinon.stub({
show: function() {
},
hide: function() {
}
});
mockIonicModal = sinon.stub({
fromTemplateUrl: function() {
},
then: function() {
}
});
mockIonicModal.fromTemplateUrl.returns(mockModal);
});
beforeEach(function() {
module(function($provide) {
$provide.value('$ionicModal', mockIonicModal);
});
});
beforeEach(inject(function($rootScope, $controller, $q, ptiMock) {
controllerConstructor = $controller;
dfd = $q.defer();
scope = $rootScope.$new();
mock = ptiMock;
mockModal.$promise = dfd.promise;
}));
beforeEach(inject(function(_addEquipment_) {
addEquipment = _addEquipment_;
}));
it('exists', function() {
expect(addEquipment).to.exist;
});
describe('open', function() {
it.only('opens the modal', function() {
addEquipment.openModal();
dfd.resolve(mockModal);
scope.$digest();
expect(mockIonicModal.show.calledOnce).to.be.true;
});
});
function getController() {
return mockIonicModal.fromTemplateUrl.lastCall.args[0].scope.controller;
}
});
})();
I'm also unsure if my getController function will properly return the controller. This is my first time working with $ionicModal, so any pointers are appreciated. Thanks.
FIXED:
I didn't have the dfd set up properly. Also I had the show set as a function of mockIonicPopup when it is a function of mockModal.
(function() {
'use strict';
describe('AddEquipment', function() {
var controllerConstructor;
var addEquipment;
var mock;
var mockIonicModal;
var mockModal;
var scope;
var dfd;
beforeEach(module('penta.app.main'));
beforeEach(module('unitTest'));
beforeEach(module('app/tracking/activityLog/addItems/equipment/addEquipment.html'));
beforeEach(function() {
mockModal = sinon.stub({
show: function() {
},
hide: function() {
}
});
mockIonicModal = sinon.stub({
fromTemplateUrl: function() {
},
then: function() {
}
});
});
beforeEach(function() {
module(function($provide) {
$provide.value('$ionicModal', mockIonicModal);
});
});
beforeEach(inject(function($rootScope, $controller, $q, ptiMock) {
controllerConstructor = $controller;
dfd = $q.defer();
scope = $rootScope.$new();
mock = ptiMock;
mockIonicModal.fromTemplateUrl.returns(dfd.promise);
}));
beforeEach(inject(function(_addEquipment_) {
addEquipment = _addEquipment_;
}));
it('exists', function() {
expect(addEquipment).to.exist;
});
describe('openModal', function() {
it.only('opens the modal', function() {
addEquipment.openModal();
dfd.resolve(mockModal);
scope.$digest();
expect(mockModal.show.calledOnce).to.be.true;
});
});
function getController() {
return mockIonicModal.fromTemplateUrl.lastCall.args[0].scope.controller;
}
});
})();
I am having a bit of trouble testing a HTTP POST in AngularJs with Jasmine.
I have a controller that looks like so:-
appControllers.controller("TaskAddController", function ($scope, $http) {
$scope.task = {};
$scope.messages = {};
$scope.actions = {
save : function() {
$http.post("/ajax/tasks/save", $scope.task)
.then(function() {
$scope.messages.success = true;
$scope.task = {};
});
}
};
});
I am testing it like so:-
describe("TaskAddController", function() {
var createController, scope, $httpBackend;
beforeEach(function () {
module('appControllers');
scope = {};
inject(function ($injector) {
$httpBackend = $injector.get("$httpBackend");
});
inject(function ($controller) {
createController = function () {
return $controller("TaskAddController", { $scope: scope });
};
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("when actions.save is called then should call service", function () {
var task = {
title: "Title",
description: "Description"
};
$httpBackend.expectPOST("/ajax/tasks/save", task);
createController();
scope.task = task;
scope.actions.save();
$httpBackend.flush();
});
});
This causes me to get the following error Error: No pending request to flush !
What am I doing wrong?
Thanks.
What version of AngularJS are you using?
When I run the code I get: Error: No response defined !
When I add a response the test passes:
$httpBackend.expectPOST("/ajax/tasks/save", task).respond({});
What is the difference between angual.module('app') and module('app')?
Here is the simple service and unit test in question:
Service
(function () {
"use strict"
var app = angular.module('app', []);
app.service('CustomerService', ['$http', function ($http) {
return {
getById: function (customerId) {
return $http.get('/Customer/' + customerId);
}
}
}]);
}());
Test
describe('Customer Service', function () {
var $rootScope,
$httpBackend,
service,
customerId = 1;
beforeEach(function () {
angular.module('app', ['ngMock']);
inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('/Customer/' + customerId).respond({ id: customerId, firstName: 'Joe', lastName: 'Blow' });
service = $injector.get('CustomerService');
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingRequest();
});
it('should get customer by id', function () {
var customer;
service.getById(1).then(function (response) {
customer = response.data;
});
$httpBackend.flush();
expect(customer.firstName).toBe('Sam');
});
});
module in the unit test framework refers to the mock angular.mock.module method (which is attached to window as a convenience). angular.module is the method that angular.mock.module mocks.
Trying to get some units tests in AngularJS (using jasmine & karma) working and struggling to comprehend dependency injection... current error message in karma reads 'Error: Argument 'fn' is not a function, got string'
app.js
angular.module('App', [ 'App.Services', 'App.Controllers', 'App.Directives']);
controller.js
angular.module('App.Controllers', []).
controller('MarketplaceCtrl', function ($scope, apiCall) {
apiCall.query({
type: 'engagement',
engagement_status__in: '0,1'
}, function(data) {
var engagements = {};
$.each(data.objects, function (i, engagement) {
engagements[engagement.lawyer_id] = engagement
});
$scope.engagements = engagements;
});
});
services.js
angular.module('App.Services', ['ngResource']).
factory('apiCall', function ($resource) {
return $resource('/api/v1/:type',
{type: '#type'},
{
query: {
method: 'GET',
isArray: false
}
}
);
});
controllerSpec.js
describe('controllers', function () {
beforeEach(
module('App', ['App.Controllers', 'App.Directives', 'App.Services'])
);
describe('MarketplaceCtrl', function () {
var scope, ctrl, $httpBackend;
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/v1/engagement?engagement_status__in=0,1').
respond([]);
scope = $rootScope.$new();
/* Why is MarketplaceCtrl not working? :( */
ctrl = $controller('MarketplaceCtrl', {$scope: scope});
}));
it('should have a MarketplaceCtrl controller', (function () {
expect(ctrl).not.to.equal(null);
}));
});
});
Ended up using this example https://github.com/tebriel/angular-seed/commit/b653ce8e642ebd3e2978d5404db81897edc88bcb#commitcomment-3416223
Basically:
describe('controllers', function(){
beforeEach(module('myApp.controllers'));
it('should ....', inject(function($controller) {
//spec body
var myCtrl1 = $controller('MyCtrl1');
expect(myCtrl1).toBeDefined();
}));
it('should ....', inject(function($controller) {
//spec body
var myCtrl2 = $controller('MyCtrl2');
expect(myCtrl2).toBeDefined();
}));
});