2015-12-11 71 views
2

我用ng-describekarma一起運行下面的茉莉花測試。Promise在angularjs茉莉花測試中解決得太晚了

(我使用es6-promise填充工具爲PhantomJS)

var myModule = angular.module('MyModule', []); 
myModule.service('MyService', [function() { 
    return { 
    getItems: function() { 
     // this will be spied and mocked 
    } 
    }; 
}]); 

myModule.controller('MyController', ['$scope', 'MyService', 
    function($scope, MyService) { 
    $scope.items = []; 

    $scope.refreshItems = function() { 
     MyService.getItems().then(
     function ok(items) { 
      $scope.items = items; 
      console.log('OK, items.length = ' + items.length); 
     }, 
     function fail(reason) { 
      console.error('FAIL') 
     }).catch(console.error.bind(console)); 
    }; 
    } 
]); 

ngDescribe({ 
    name: "MyController test", 
    modules: ['MyModule'], 
    inject: ['MyService', '$rootScope', '$q'], 
    controllers: 'MyController', 
    tests: function(deps) { 

    function getPromise(val) { 
     return new Promise(function(resolve, reject) { 
     resolve(val); 
     }); 
    } 

    it('updates $scope.items', function() { 
     spyOn(deps.MyService, 'getItems').and.returnValue(getPromise([4, 5, 6])); 
     deps.MyController.refreshItems(); 
     deps.$rootScope.$digest(); 

     expect(deps.MyService.getItems).toHaveBeenCalled(); 
     expect(deps.MyController.items.length).toBe(3); 
     console.log("END OF TEST"); 
    }); 
    } 
}); 

測試將失敗,因爲承諾解決爲時已晚:

LOG: 'END OF TEST' 
PhantomJS 1.9.8 (Windows 7 0.0.0) MyController test updates $scope.items FAILED 
     Expected 0 to be 3. 
      at d:/git/myproject/test/controllers/ItmngtControllerTest.js:49 
LOG: 'OK, items.length = 3' 
PhantomJS 1.9.8 (Windows 7 0.0.0): Executed 37 of 37 (1 FAILED) (0.085 secs/0.26 secs) 

後太長時間的調查,我想它,如果我使用$q而不是Promise,它會正常工作。

function getPromise(val) { 
     var deferred = deps.$q.defer(); 
     deferred.resolve(val); 
     return deferred.promise; 
    } 

我不知道但是,爲什麼是這樣的話,我可以改變的東西在我的測試中使用Promise而不是$q讓測試通過了嗎?

我已經讀過各種關於$rootScope.$apply()的地方,但是無論我把它放在哪裏,它都不適合我。

+2

我不知道什麼觸發了Shimmed ES6承諾的決心,但我懷疑它是範圍摘要,因爲它是角度承諾。 'and.returnValue($ q.when([4,5,6]))''有什麼問題? –

+0

是的,我意識到摘要只能解決角度許諾,我最初認爲它能夠神奇地解決所有的承諾。廣告'$ q.when',是的,我也可以使用它,我忽略了它。我的問題是,出於好奇,是否有可能強制角度來解決本地/墊片式Promise呢? –

+0

那裏有原生的承諾呢?他們是僅用於規格還是應用程序本身? – estus

回答

1

角度$q測試是同步的,這是一個巨大的優勢。一旦調用範圍$digest(),可以預期所有$q承諾鏈處理程序也被調用。

另一方面,一般的承諾(包括ES6實現)在設計上是異步的。一旦這個承諾解決了,它的處理程序將在下一個勾號中被調用。那麼愉快角測試是不是同步的了:

it('updates $scope.items', function (done) { 
    ... 
    setTimeout(() => { 
    expect(deps.MyService.getItems).toHaveBeenCalled(); 
    expect(deps.MyController.items.length).toBe(3); 
    console.log("END OF TEST"); 
    done(); 
    }); 
}); 

Promise可以模擬來測試的目的是同步的,mock-promises可能在這種情況下使用。

而且有jasmine-co其目的是使異步測試在茉莉花容易多了(它實際上)與ES6發電機和co,我不知道它有多好與ng-describe執行。