Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injected $stateParams and $state into jasmine angular js test getting undefined

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
like image 600
Jngai1297 Avatar asked Jan 23 '14 19:01

Jngai1297


People also ask

What is the $stateparams service in angular?

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.

What is Jasmine testing framework?

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.

What is the best alternative to Jasmine for testing?

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.

Which testing framework should I use for angular testing?

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.


2 Answers

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)
  });
});
like image 53
JeffB Avatar answered Nov 03 '22 00:11

JeffB


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.

like image 27
Enkode Avatar answered Nov 03 '22 00:11

Enkode