Jasmine angularjs - spying on angular -local storage methods called during controller initialization

A similar question: Jasmine angularjs - spy on a method that is called when the controller is initialized

In my controller, I use the angular -local-storage package to provide local storage through injection.

in my unit tests, I want to make sure that the data is retrieved from the service, so I spy on the "get" and "add" methods and make fun of them (.andCallFake).

this works great with all methods that are called through $ scope. $ watch - while I force $ digest. but for the method that is called when the controller is initialized, it does not work. Can someone tell me why this is not working?

Application> Main.js

angular.module('angularTodoApp')
  .controller('MainCtrl',['$scope','localStorageService',function ($scope, localStorageService) {

    var todosInStore =  localStorageService.get('todos');
    $scope.todos = todosInStore && todosInStore.split('\n') || [];
    //$scope.todos = ['Item 1', 'Item 2', 'Item 3'];

    $scope.$watch('todos', function(){
      localStorageService.add('todos', $scope.todos.join('\n'));
    },true);

    $scope.addTodo  = function() {
      $scope.todos.push($scope.todo);
      $scope.todo = '';
    };

    $scope.removeTodo = function(index) {
      $scope.todos.splice(index,1);
    };
  }]);

test> Main.js

describe('Controller: MainCtrl', function () {

  // load the controller module
  beforeEach(module('angularTodoApp'));

  var MainCtrl,
    scope,
    localStorageService,
    store = [];

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
    scope = $rootScope.$new();
    localStorageService = _localStorageService_;
    MainCtrl = $controller('MainCtrl', {
      $scope: scope,
      localStorageService: _localStorageService_
    });

    //mock localStorageService get/add
    spyOn(localStorageService,'get').andCallFake(function(key){
      return store[key];
    });
    spyOn(localStorageService,'add').andCallFake(function(key, val){
      store[key] = val;
    });
  }));

  it('should retrieve "todos" from the store and assign to scope', function () {
    expect(localStorageService.get).toHaveBeenCalledWith('todos');
    expect(scope.todos.length).toBe(0);
  });

  it('should add items to the list and update the store for key = "todos"', function () {
    scope.todo = 'Test 1';
    scope.addTodo();
    scope.$digest();
    expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
    expect(scope.todos.length).toBe(1);
  });

all tests pass, except those specified in the constructor:

expect(localStorageService.get).toHaveBeenCalledWith('todos');
+4
source share
3 answers

The reason is that the controller is initialized at the point that you are calling $controller, which in your example before you create spies through spyOn. The solution for your example is to transfer the call to $controllerafter calls to spyOn.

For longer test suites, in order to preserve DRY stuff, you may need to send a call $controllerto a separate function that you can call after you have mocked any required services.

+5
source

, , mocks , :

describe('Controller: MainCtrl', function () {

  // load the controller module
  beforeEach(module('angularTodoApp'));

  var MainCtrl,
    scope,
    localStorageService,
    store;

  // Initialize the controller and mocks
  beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
    store = []; //clear the store before each test
    scope = $rootScope.$new();
    localStorageService = _localStorageService_;

    //mock localStorageService get/add
    spyOn(localStorageService,'get').andCallFake(function(key){
      return store[key];
    });
    spyOn(localStorageService,'add').andCallFake(function(key, val){
      store[key] = val;
    });

    //Instantiate controller to test
    MainCtrl = $controller('MainCtrl', {
      $scope: scope,
      localStorageService: localStorageService
    });
  }));

  it('should retrieve "todos" from the store and assign to scope', function () {
    expect(localStorageService.get).toHaveBeenCalledWith('todos');
    expect(scope.todos.length).toBe(0);
  });

  it('should add items to the list and update the store for key = "todos"', function () {
    scope.todo = 'Test 1';
    scope.addTodo();
    scope.$digest();
    expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
    expect(scope.todos.length).toBe(1);
  });

  it('should remove items to the list and update the store', function() {
    scope.todo = 'Test 1';
    scope.addTodo();
    scope.$digest();
    //reset call count
    localStorageService.add.reset();

    scope.removeTodo(0);
    scope.$digest();
    expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
    expect(scope.todos.length).toBe(0);
  });
});
+3

LocalStorageModule beforeEach() test.js.

beforeEach(module('angularTodoApp', 'LocalStorageModule'));

, karma.conf.js

module.exports = function(config) {
    // ...
    files: [
        '/path/to/angular.min.js',
        '/path/to/angular-mocks.js',
        '/path/to/angular-local-storage.js',
        'Main/test.js',
        'Main/app.js'
    ],
    //...

, .

, spyOn(...).andCallFake(...), Jasmine 2.4 spyOn(...).and.callFake(...)

, , Jasmine 2.4 ( ).

+1

Source: https://habr.com/ru/post/1536355/


All Articles