Угловое модульное тестирование: вызов метода, определенного в другом контроллере, выдает «неопределенное» — это не ошибка

Я пытаюсь протестировать файл AngularJS, но он не может вызвать метод, определенный в другом контроллере.

В файле MyPage:

angular.module('MyApplication').controller('MyPageCtrl', function ($scope, $rootScope) {
  if($scope.pageChecker) {
    $scope.doSomething();
  }
}

Метод pageChecker() определен в App.js в контроллере MyApplication и возвращает значение true или false.

Для полноты:

$scope.pageChecker = function() {
  if(cookieCheck) {
    return true;
  }
  else {
    return false;
  }
};

Жасминовый файл:

describe("Page check", function(){
  beforeEach(angular.mock.module('MyApplication'));

  beforeEach(angular.mock.inject(function ($rootScope, $controller) {
    var $scope = $rootScope.$new();
    $controller('MyPageCtrl', { $scope: $scope});
  }));

  it("should call $scope.doSomething", function(){
    spyOn($scope, "doSomething");
    $scope.doSomething();
    expect($scope.doSomething).toHaveBeenCalled();
  });
});

Я получаю «TypeError:« undefined »не является функцией (оценка« $scope.pageChecker () »)

Я хочу переопределить метод pageChecker, чтобы он всегда возвращал true. Как мне это сделать?

РЕДАКТИРОВАТЬ: Благодаря Dskh, у меня есть ответ с другой настройкой от меня:

describe("Page check", function(){

  var $scope; //declare here, else it is a local variable inside the beforeEach

  beforeEach(angular.mock.module('MyApplication'));

  beforeEach(angular.mock.inject(function ($rootScope, $controller) {
    $scope = $rootScope.$new();
    // define the overriding methods here
    $scope.pageChecker = function(){
      return true;
    };
    // end overriding methods here
    $controller('MyPageCtrl', { $scope: $scope});
  }));

  it("should call $scope.doSomething", function(){
    spyOn($scope, "doSomething");
    $scope.doSomething();
    expect($scope.doSomething).toHaveBeenCalled();
  });
});

person Jezcentral    schedule 02.01.2014    source источник
comment
Я думаю, что в вопросе опечатка, я не вижу вызова $scope.pageChecker() как вызова функции. Похоже, ваш контроллер вызывает метод $scope.pageChecker как часть экземпляра контроллера, и когда вы предоставляете объект области при создании контроллера в тесте, у него действительно нет метода pageChecker   -  person Eitan Peer    schedule 02.01.2014
comment
Хороший улов, Эйтан, но проблема не в этом. Это была версия моего кода, в которой имена были изменены для защиты невиновных, поскольку мой работодатель не хотел бы, чтобы я публиковал реальный код. :)   -  person Jezcentral    schedule 02.01.2014


Ответы (1)


Вы сами создаете $scope при выполнении $rootScope.$new(), а затем внедряете его в контроллер, который создаете при использовании метода $controller().

Поэтому, если вы хотите, чтобы этот метод всегда возвращал true, вам просто нужно создать метод самостоятельно:

beforeEach(angular.mock.inject(function ($rootScope, $controller) {
    var $scope = $rootScope.$new();

    $scope.doSomething = function(){
        return true;
    };

    $controller('MyPageCtrl', { $scope: $scope});
  }));

Еще одно объяснение: когда ваше приложение работает по-настоящему, $scope автоматически вводится в ваш контроллер angular. В своем тесте вы просто тестируете свой контроллер изолированно, поэтому вам нужно создать объект области самостоятельно и имитировать любое поведение, которое вы хотите от него. Использование $rootScope().$new() даст вам угловые методы, такие как $watch или $on, но вам нужно воссоздать свои собственные методы самостоятельно.

person Dan    schedule 02.01.2014
comment
Спасибо Дсх. Это сработало, как только я также узнал, что мне нужно установить $scope как глобальную переменную. Это мешало мне правильно определить $scope, так как я определял его как локальную переменную. О! - person Jezcentral; 02.01.2014