2014-06-16 38 views
1

我試圖測試我的$watch偵聽器,但是它並未在測試中觸發。

這裏的測試:

it('should fire $watch when selectedBrands change', function() { 
    spyOn($scope, 'updateFilters') 

    $scope.selectedBrands = ['1']; 

    expect($scope.updateFilters).toHaveBeenCalled(); 
}) 

而且控制器:

$scope.selectedBrands = []; 

$scope.$watch("selectedBrands", function() { 
    $scope.updateFilters(); 
}, true); 

最後,錯誤:

Chrome 35.0.1916 (Mac OS X 10.10.0) ItemsController should fire $watch when selectedBrands change FAILED 
    Expected spy updateFilters to have been called. 
    Error: Expected spy updateFilters to have been called. 
     at null.<anonymous> (/Applications/MAMP/htdocs/cloqet_client/testing/tests/ItemModule/ItemsController_spec.js:62:38) 

我嘗試使用$scope.$digest()但使測試通過,即使沒有改變$scope.selectedBrands。爲什麼$watch不被解僱?

+0

在下面的答案中發現了一些有趣的東西? – gkalpak

回答

0

你需要一個消化的過程被炒魷魚,這時候做觀察家檢查

it('should fire $watch when selectedBrands change', function() { 
    spyOn($scope, 'updateFilters') 

    $scope.selectedBrands = ['1']; 
    $scope.$digest() 

    expect($scope.updateFilters).toHaveBeenCalled(); 
}) 
3

它的正確使用$scope.$digest()觸發摘要。

it('should fire $watch when selectedBrands change', function() { 
    spyOn($scope, 'updateFilters') 

    $scope.selectedBrands = ['1']; 

    $scope.$digest(); 

    expect($scope.updateFilters).toHaveBeenCalled(); 
}); 

but that makes the test pass even without changing $scope.selectedBrands

原因是$看總是火災在第一時間與undefined即使你不改變的值。當前測試反映了您當前代碼的正確行爲。這意味着你的代碼有一個需要修復的錯誤

要解決這個問題,試圖修復代碼:

$scope.$watch("selectedBrands", function(value) { 
    if (value){ //check for undefined fired the first time. 
     $scope.updateFilters(); 
    } 
}, true); 

DEMO

1

測試的角度上下文之外運行,所以不存在自動$消化週期發生。
$watch()未被觸發,因爲您需要首先手動調用$摘要循環。

您還應該記住,每個$ watch回調函數都會執行一次初始化值。
這就是爲什麼你的$scope.updateFilter()被稱爲即使不改變selectedBrands
引用the docs
「經過觀察者與範圍登記時,listener FN是異步(經由​​)調用初始化觀察者」。

測試正確的方法是手工調用$消化週期(這樣的$手錶initiaized),然後更改selectedBrands,最後調用secod $消化週期「消化」這種變化。

E.g.:

it('should fire $watch when selectedBrands change', function() { 
    $scope.$digest(); 

    spyOn($scope, 'updateFilters'); 
    $scope.selectedBrands = ['1']; 
    $scope.$digest(); 

    expect($scope.updateFilters).toHaveBeenCalled(); 
}); 

還參見本short demo

相關問題