Подтвердить что ты не робот

Функция тайм-аута AngularJS $не выполняется в моих спецификациях Jasmine

Я пытаюсь проверить свой контроллер AngularJS с помощью Jasmine, используя Karma. Но $timeout, который хорошо работает в реальной жизни, сбрасывает мои тесты.

Контроллер:

var Ctrl = function($scope, $timeout) {
  $scope.doStuff = function() {
    $timeout(function() {
      $scope.stuffDone = true;
    }, 250);
  };
};

Жасмин он блокирует (где $scope и контроллер правильно инициализированы):

it('should do stuff', function() {
  runs(function() {
    $scope.doStuff();
  });
  waitsFor(function() { 
    return $scope.stuffDone; 
  }, 'Stuff should be done', 750);
  runs(function() {
    expect($scope.stuffDone).toBeTruthy();
  });
});

Когда я запустил приложение в браузере, будет выполняться функция $timeout и $scope.stuffDone будет true. Но в моих тестах $timeout ничего не делает, функция никогда не выполняется, и Jasmine сообщает об ошибке после выключения 750 мс. Что здесь может быть неправильно?

4b9b3361

Ответ 1

В соответствии с документацией Angular JS для $timeout вы можете использовать $timeout.flush() для синхронного сброса очереди отложенных функций.

Попробуйте обновить свой тест:

it('should do stuff', function() {
  expect($scope.stuffDone).toBeFalsy();
  $scope.doStuff();
  expect($scope.stuffDone).toBeFalsy();
  $timeout.flush();
  expect($scope.stuffDone).toBeTruthy();
});

Вот plunker, показывающий как исходный тест, так и новый тест.

Ответ 2

Как отмечено в одном из комментариев, Jasmine setTimeout mock не используется, потому что вместо этого используется служба angular JS mock $timeout. Лично я предпочел бы использовать Jasmine, потому что его издевательский метод позволяет мне проверять длину таймаута. Вы можете эффективно обойти его простым провайдером в unit test:

module(function($provide) {
  $provide.constant('$timeout', setTimeout);
});

Примечание: если вы идете по этому маршруту, обязательно вызовите $scope.apply() после jasmine.Clock.tick.

Ответ 3

Поскольку $timeout является просто оберткой для window.setTimeout, вы можете использовать jasmines Clock.useMock(), который издевается над window.setTimeout

  beforeEach(function() {
    jasmine.Clock.useMock();
  });

  it('should do stuff', function() {
    $scope.doStuff();
    jasmine.Clock.tick(251);
    expect($scope.stuffDone).toBeTruthy();
  });