12

I am currently working on a tutorial that integrates angular JS into a Rails app.

Tests are setup as follows:

describe( 'Club functionality', function() {
  // mock Application to allow us to inject our own dependencies
  beforeEach(angular.mock.module('league'));

  // create the custom mocks on the root scope
  beforeEach(angular.mock.inject(function($rootScope, _$httpBackend_, $state){
    //create an empty scope
    scope = $rootScope.$new();

    // we're just declaring the httpBackend here, we're not setting up expectations or when's - they change on each test
    scope.httpBackend = _$httpBackend_;
    scope.$state = $state;
  }));

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

After finishing that section of the tutorial and browsing some of the Angular docs it is still not clear to me why the underscores are used when including the $httpBackend dependency. Why is this mocked out like so? scope.httpBackend = _$httpBackend_;

Davey
  • 1,093
  • 1
  • 13
  • 25
  • possible duplicate of [What does the underscores in \_servicename\_ mean in AngularJS tests?](http://stackoverflow.com/questions/15318096/what-does-the-underscores-in-servicename-mean-in-angularjs-tests) – Davin Tryon Feb 03 '14 at 22:10

2 Answers2

14

This one is more simple than it looks.

For convenience, we want to reference our services / scopes across our test suite as we are used to in our applications. So we need to save their reference at the outer function scope.

First we need to inject them so we try to do so without underscores like so:

var $httpBackend;

beforeEach(angular.mock.inject(function( $httpBackend ){

The problem is that the inner function scope variable $httpBackend shadows the outer function scope variable $httpBackend, so we cannot go up the scope chain to set our reference outside.

To fix it, we must have different names for the inner and the outer scope variables. The underscores are just a little help from the $injector to do it without pain.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
Ilan Frumer
  • 32,059
  • 8
  • 70
  • 84
9

DISCLAIMER: I did not write this answer. It was copied from here.

So the key to the "secret" is here: https://github.com/angular/angular.js/blob/master/src/auto/injector.js#L57

Basically $injector will strip leading / trailing underscores when inspecting function's arguments (to retrieve dependencies). This is useful trick since we can do $rootScope = _$rootScope_; and then, later in the tests use $rootScope. It kind of looks nicer since test code uses the same variables as a controller would use. At somehow having leading $ helps to remember that those are injected variables.

Of course we could do: rootScope = $rootScope; but it wouldn't be so obvious that rootScope was injected.

muenchdo
  • 2,161
  • 1
  • 17
  • 30