Code Apprentice
Code Apprentice

Reputation: 522

Error: getItem() method does not exist (Angular, mocking LocalStorage)

I grabbed a snippet of code to mock local storage, however, when I ran the test, it threw this error. As it says, it can't find the getItem method, but I explicitly declared the method outside the beforeEach block. I don't know what's throwing this error - would appreciate tips and suggestions!

Here are my files:

mainCtrl.spec.js

describe('Controller: MainCtrl', function () {
  var store = {};
  var ls = function() {
    return JSON.parse(store.storage);
  };
  var localStorage = {}; 

  var getItem = function(key) {
    return store[key];
  }

  var setItem = function(key, value) {
    store[key] = value;
  }

  beforeEach(function() {
        // setUp.
        module('mytodoApp');

        // LocalStorage mock.
        spyOn(localStorage, 'getItem').andCallFake(getItem); <-- throwing the error
        Object.defineProperty(sessionStorage, "setItem", { writable: true });
        spyOn(localStorage, 'setItem').andCallFake(setItem);
    });

  afterEach(function() {
    store = {};
  });

  var MainCtrl,
    scope;

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

  it('should have no items to start with', function() {
    // expect(scope.todos.length).toBe(0);
    expect(Object.keys(store).length).toBe(0);
  });
});

mainCtrl.js

angular.module('mytodoApp')
  .controller('MainCtrl', function ($scope, localStorageService) {
    //  breaks on repeat or blank input
    function addTodoFn() {
        $scope.todos.push($scope.todo); 
        $scope.todo = '';   
    }

    function removeTodoFn(index) {
        $scope.todos.splice(index, 1);
    }

    function watchFn() {
      localStorageService.set('todos', $scope.todos);
    }

    //////////

    var todosInStore = localStorageService.get('todos');
    $scope.todos = todosInStore || [];
    $scope.$watch('todos', watchFn, true);
    $scope.addTodo = addTodoFn;
    $scope.removeTodo = removeTodoFn;
  });

EDIT

var localStorage = { 
    getItem: function(key) {
      return store[key];
    },

    setItem: function(key, value) {
      store[key] = value;
    }
  };

  beforeEach(function() {
    // setUp.
    module('mytodoApp');

    // LocalStorage mock.
    spyOn(localStorage, 'getItem').andCallFake(getItem);
    Object.defineProperty(sessionStorage, 'setItem', { writable: true });
    spyOn(localStorage, 'setItem').andCallFake(setItem);
  });

I changed it as per @CosmicChild's suggestion to no avail.

New error message

ReferenceError: Can't find variable: getItem

Upvotes: 0

Views: 653

Answers (2)

CosmicChild
CosmicChild

Reputation: 181

You need to define an empty method inside the localStorage object that you are stubbing,

var localStorage = {
    getItem: function(key) {
    },
    setItem: function(key, value) {
    }
};

Upvotes: 1

Code Apprentice
Code Apprentice

Reputation: 522

As it turns out, it's just a simple syntax error. Taking another look at the Jasmine docs helped (maybe it's to do with the version of Jasmine you're using, but this is the wrong syntax in version 2.3).

beforeEach(function() {
    // setUp.
    module('mytodoApp');

    // LocalStorage mock.
    spyOn(localStorage, 'getItem').and.callFake(getItem); <-- .and.callFake
    Object.defineProperty(sessionStorage, 'setItem', { writable: true });
    spyOn(localStorage, 'setItem').and.callFake(setItem);
  });

Upvotes: 0

Related Questions