2014-10-24 6 views
0

Первая итерация этого вопроса: Unit testing Angular directive with $httpблок тестирования асинхронно Угловая директива

Я создал директиву, которая, будучи связанным с входом, реагирующий на размытие/KeyUp события путем вызова службы до изменения DOM. Эта услуга основана на $ http и поэтому является асинхронной. Я написал функциональный модульный тест для службы, но на всю жизнь я не могу написать рабочий тест для этой директивы.

describe('SignupForm directives', function() { 
    var form,  // el to which directive is applied 
    scope, 
    userService, 
    el; 

beforeEach(function() { 
    module('signupform.directives'); 
}); 

beforeEach(function() { 
    inject(function ($injector, $rootScope, $compile, $q, $timeout) { 
     scope = $rootScope.$new(); 
     el = $compile('<input id="username" type="text" name="username" ng-model="user.username" sg-valid-username />')(scope); 

     userService = $injector.get('userService'); 
     scope.user = { username: 'test_username' }; 
     spyOn(userService, 'checkIfUserExists'); 
    }); 
}); 

    it('Directive fires on blur', function() { 
    scope.$digest(); 

    // build blur event and fire it 
    var blurEvent = $.Event('blur'); 
    angular.element(el).triggerHandler(blurEvent); 

    expect(userService.checkIfUserExists).toHaveBeenCalled(); 
    }); 
}); 

Я доказал с помощью отладчика, что сервис-userService.checkIfUserExists-получает называется. Это просто ожидание() происходит до этого и не проходит тест.

У меня нет понятия, как писать это асинхронно. Концепция Jasmine 2.0's done() ошеломляет, и пользовательскому сервису в противном случае не требуется обратный вызов.

Как я могу подойти к этому?

+0

Добавить 'scope. $ Digest()' после 'angular.element (el) .triggerHandler (blurEvent);' – merlin

+0

@merlin: я переместил область. $ Digest() после этой строки и перед expect(), затем reran karma. Ошибка все тот же: ожидается, что ожидаемый запрос проверки spyIfUserExists был вызван. – spamguy

ответ

1

Используйте $timeout вместо setTimeout в своем driective, чтобы вы могли вручную очистить ожидающий таймаут в модульных тестах.

.directive('sgValidUsername', ['$timeout', 'userService', function ($timeout, userService) { 
    return { 
     restrict: 'A', 

     link: function(scope, element) { 
      var promise; 
      element.on('blur keyup', function(e) { 
       $timeout.cancel(promise); 
       promise = $timeout(function() { 
       userService.checkIfUserExists(); 
       }, 1000); 
      }); 
     } 
    } 
}]) 

В тестовом модуле, вызовите $timeout.flush() после el.triggerHandler('blur') вручную вызвать тайм-аута обратного вызова (который вызывает ваш checkIfUserExists).

it('Directive fires on blur', function() { 
    el.triggerHandler('blur'); 
    $timeout.flush();//Flush pending timeouts 
    expect(userService.checkIfUserExists).toHaveBeenCalled(); 
}); 

Смотрите эту plnkr для полного рабочего примера.

+0

Блестящий! Я даже не слышал о тайм-ауте. Благодарю. – spamguy

Смежные вопросы