2014-09-10 70 views
0

我試圖單元測試一個處理簽名用戶的控制器。我得到一個錯誤,並認爲它可能與使用promise的代碼有關但在這一點上我不確定。這是控制器。包含promise的函數的單元測試沒有按預期工作

angular.module('app').controller('SignIn', SignIn); 

function SignIn ($scope, $state, auth) { 

    $scope.credentials = {}; 

    // signin 
    $scope.signIn = function() { 
     auth.signIn($scope.credentials) 
      .then(function() { 
       $state.go('user.welcome'); 
      }, function (res) { 
       $scope.signInError = res.statusText; 
      }); 
    }; 
} 

這裏是auth服務。

angular.module('app').factory('auth', auth); 

function auth (session, api) { 
    return { 
     signIn : function (credentials) { 
      return api.signIn(credentials) 
       .then(function (res) { 
        session.create(res.data.sessionId, res.data.userName); 
       }); 
     }, 
     signout: function() { 
      return session.destroy(); 
     }, 
     isAuthenticated: function() { 
      return !!session.userName; 
     } 
    }; 
} 

api只是返回$ http promises。

signIn : function (credentials) { 
    return $http.post(base + '/auth/credentials', credentials); 
} 

會話只是一個工廠,用於存儲當前會話信息並將其保存到瀏覽器的cookie中。

這裏是我的茉莉花測試

describe('SignIn', function() { 

// setup ------------------------------------------------------------------ 

    // init app module 
    beforeEach(module('app')); 

    // inject Session service 
    beforeEach(angular.mock.inject(function (_$rootScope_, _$controller_, _auth_) { 
     $rootScope    = _$rootScope_; 
     $scope     = $rootScope.$new(); 
     controller    = _$controller_("SignIn", {$scope: $scope}); 
     auth     = _auth_; 
    })); 

    // setup spies 
    beforeEach(function() { 
     spyOn(auth, 'signIn'); 
    }); 

// tests ------------------------------------------------------------------ 

    // signin in 
    it("should call auth.signIn with the user's credentials", function() { 
     $scope.signIn(); 
     expect(auth.signIn).toHaveBeenCalled(); 
    }); 

}); 

我只是想測試,當你調用$ scope.signIn auth.signIn稱爲()。應用程序本身工作,但我試圖運行此測試時出現此錯誤。

SignIn should call auth.signIn with the user's credentials FAILED 
TypeError: 'undefined' is not an object (evaluating 'auth.signIn($scope.credentials).then') 

雖然人們期望出現的錯誤是$ scope.signIn()發生時,我打電話;如果我在$ scope.signIn()之前登錄auth,被稱爲我得到這個。

LOG: Object{signIn: function() { ... }, signout: function() { ... }, isAuthenticated: function() { ... }} 

所以我假設DI工作正常。我研究過建立間諜的不同方式,但還沒有弄清楚實際上什麼是錯誤的。任何幫助,將不勝感激。

+0

隱而不宣」 t回答這個問題,但是在angular文件中有幾個問題。可能最好不要指望在你的errback ... – marneborn 2014-09-10 18:21:31

回答

0

那是因爲你在暗中監視authsignIn功能。當你窺探它時,它不會再是你在api中的實際功能。所以你需要使用.and.returnValue來發送間諜的承諾。

所以做: -

beforeEach(inject(function (_$rootScope_, _$controller_, _auth_, _$q_) { 
    $rootScope    = _$rootScope_; 
    $scope     = $rootScope.$new(); 
    controller    = _$controller_("SignIn", {$scope: $scope}); 
    auth     = _auth_; 
    fakePromise = _$q_.when(); //get a fake promise 
})); 

beforeEach(function() { 
    spyOn(auth, 'signIn').and.returnValue(fakePromise); //return fakepromise 
}); 

Plnkr

,如果你要返回來回回簽到一定的價值(或任何其他功能的承諾,只是做)

fakeAuthPromise = _$q_.when(somedata); 
+0

感謝這工作,並使錯誤是有道理的。我確實必須改變'.and.returnValue(); to和返回();這可能是茉莉花版本的差異。什麼是$ q.when()在做什麼?如果不傳遞更多的數據,這隻會返回一個通用的承諾? – Constellates 2014-09-10 18:32:14

+0

是$ q.when()返回一個promise對象,該對象具有then和其他承諾方法 – PSL 2014-09-10 18:40:33