I am writing a jasmine test for my DetailCtrl. I have 10 json file each with file names like this
1.json
2.json
3.json
in my data folder
Here is my Detail Ctrl
backpagecontrollers.controller('DetailCtrl', function($scope, $stateParams, $http) {
$http.get('data/' + $stateParams.listingId + '.json').success(function(data) {
$scope.extrainfo = data;
});
});
The detail controller is fetching each 1.json, 2.json, 3.json file from my data folder.
Here is a part of my route
.state('listingdetail', {
url: "/listings/:listingId",
templateUrl: "partials/detail.html",
controller: 'DetailCtrl'
})
Lets head back to the test, I injected both the $stateParams
and the $state
into the test.
I want to test that for each json file above the images exist inside my json file.
I am setting the httpbackend to get the local host url plus the listingId from the $stateparams
which I configured as part of the routes but the listingId
is coming back as undefined. Am I suppose to inject something else into my test?
describe('Detail Ctrl', function() {
var scope, ctrl, httpBackend, stateparams, listingId;
beforeEach(angular.mock.module("backpageApp"));
beforeEach(angular.mock.inject(function($controller, $rootScope, _$httpBackend_, $stateParams, $state) {
httpBackend = _$httpBackend_;
stateparams = $stateParams;
listingId = stateparams.listingId;
httpBackend.expectGET('http://localhost:8000/#/listings/' + listingId).respond([{id: 1 }, {id: 2}, {id:3}, {id:4}, {id:5}, {id:6}, {id:7}, {id:8}, {id:9}, {id:10}]);
scope = $rootScope.$new();
ctrl = $controller("DetailCtrl", {$scope:scope});
}));
it('the images for each listing should exist', function() {
httpBackend.flush();
expect(scope.images).toBe(true)
});
});
I am getting this error
Error: Unexpected request: GET data/undefined.json
Expected GET http://localhost:8000/#/listings/undefined
What Is the $stateParams Service in Angular? $stateParams is a service that captures URL-based parameters, and we can use these parameters to display information according to the state. Let’s create an example with two states, understand how states work, and use $stateparams to store parameters.
Jasmine is the framework we are going to use to create our tests. It has a bunch of functionalities to allow us the write different kinds of tests. karma. Karma is a task runner for our tests. It uses a configuration file in order to set the startup file, the reporters, the testing framework, the browser among other things.
This includes the option to test your code on various browsers and devices such as phones, tablets, and even a PS3 like the YouTube team. Karma also provides you options to replace Jasmine with other testing frameworks such as Mocha and QUnit or integrate with various continuous integration services like Jenkins, TravisCI, or CircleCI.
Similar to Karma, it’s also the recommended testing framework within the Angular documentation as it’s setup for you with the Angular CLI. Jasmine is also dependency free and doesn’t require a DOM. As far as features go, I love that Jasmine has almost everything I need for testing built into it.
I think you might be misunderstanding how the router is working with the controller. When you're unit testing a controller, you're not executing a route or entering a ui-router state. Those states and routes are what trigger controllers to be executed when the application is running normally. But in a unit test, you're executing the controller explicitly using $controller. So you're skipping the routing part altogether. Which means you need to mock the object that the ui-router would normally create for you, $stateparams.
describe('Detail Ctrl', function() {
var scope, ctrl, httpBackend, stateparams, listingId;
beforeEach(angular.mock.module("backpageApp"));
//don't need to inject state or stateparams here
beforeEach(angular.mock.inject(function($controller, $rootScope, _$httpBackend_) {
httpBackend = _$httpBackend_;
stateparams = { listingId: 1 }; //mock your stateparams object with your id
//you should be expecting the get request url from the controller, not the route
httpBackend.expectGET('data/' + stateparams.listingId + '.json').respond([{id: 1 }, {id: 2}, {id:3}, {id:4}, {id:5}, {id:6}, {id:7}, {id:8}, {id:9}, {id:10}]);
scope = $rootScope.$new();
//pass your mock stateparams object to the controller
ctrl = $controller("DetailCtrl", {$scope:scope, $stateParams:stateparams});
}));
it('the images for each listing should exist', function() {
httpBackend.flush();
//I don't see images set in your controller, but you
//could check scope.extrainfo here
expect(scope.images).toBe(true)
});
});
Adding the stateMock.js and then including the module
beforeEach(function() {
module('stateMock');
module('mean');
module('mean.system');
module('mean.companies');
});
code here for stackMock.js: github code for stateMock
Reference: UI-router interfers with $httpbackend unit test, angular js.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With