1

I have a service which fires a HTTP request. This request makes use of the $rootScope.config object (there is my base url stored), but for some reason when I use $httpBackend, $rootScope is not loaded correct.

Service:

myAppServices.factory('Auth', function($rootScope, $http, $cookieStore){   
  return {
    logout: function(success, error) {
      $http.get($rootScope.config.apiUrl + '/users/logout').then(function(response){
      }, function(response) {
      });
    }

Test:

describe('services', function() {
  var Auth;
  var $httpBackend;
  var $cookieStore;
  var $rootScope;

  beforeEach(function() {
    module('myApp.services');
  });

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    $cookieStore = $injector.get('$cookieStore');
    $rootScope = $injector.get('$rootScope');
    Helper = $injector.get('Helper');
    Auth = $injector.get('Auth');
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

describe('logout', function() {
  it('should make a request and invoke callback', function() {
    // I try to set $rootScope here, works in my other tests, but not in this test
    $rootScope = { config: { apiUrl: 'foo' } };

    var invoked = false;
    var success = function() {
      invoked = true;
    };
    var error = function() {};

    $httpBackend.expectPOST('/logout').respond();
    Auth.logout(success, error);
    $httpBackend.flush();
    $rootScope = { config: { apiUrl: 'foo' } };
    expect(invoked).toEqual(true);

It normally works when I set $rootScope in my test to some value, but not in this test.

Why is it that $rootScope does not have the config attribute in my service, when using $httpBackend?

1 Answer 1

5

The problem:

There are two different things with the same name that cause confusion:

  • There is the $rootScope (the actual $rootScope that is the ancestor of all Scopes and is injected through Angular's Dependency Injection).
  • And there is a local variable named $rootScope that you declare in your test-suite.

For the sake of clarity, I will refer to the latter as $rootScope{var}.


Here is what's going on:

  1. At some point $rootScope will be injected into your service's constructor (to be used later on when making the $http request).

  2. $rootScope{var} is initialized to the value returned by $injector.get('$rootScope');.
    At this point $rootScope and $rootScope{var} are the same object.

  3. This line: $rootScope = { config: { apiUrl: 'foo' } }; creates a new object and assigns it as the value of $rootScope{var}.
    At this point $rootScope and $rootScope{var} are not the same object any more.

  4. $rootScope{var} does have a config property, but your service is going to use $rootScope, which knows nothing about config.


The solution:

In order to add the config property to the actual $rootScope change your code like this:

$rootScope.config = { apiUrl: 'foo' };
Sign up to request clarification or add additional context in comments.

1 Comment

Goodness, common JS mistake, tnx a lot for the explanation!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.