2016-07-29 63 views
3

我試圖嘲笑對一個JSONP GET請求的迴應,這是一個函數,該函數返回一個ES6承諾,我已包裝在$q.when()。代碼本身工作得很好,但是,在單元測試中,請求沒有被$ httpBackend捕獲,而是直接到達實際的URL。因此,當調用flush()時,我得到一個錯誤,說明Error: No pending request to flush !。 JSONP請求是通過jQuery的$.getJSON()在ES6承諾中完成的,所以我選擇通過提供一個正則表達式來代替一個硬編碼的URL來嘗試捕獲所有傳出的請求。

我一直在努力研究這個問題,現在仍然還沒有明白是什麼導致了電話通過。我感覺好像ES6承諾中的HTTP請求正在「Angular之外」被做出來,所以$ httpBackend不知道它/不能夠捕獲它,儘管如果正在進行該調用可能不是這種情況在一個$ q承諾從一開始。任何人都可以告訴我爲什麼這個電話正在通過,爲什麼簡單的超時會工作得很好?我試過$scope.$apply,$scope.$digest$httpBackend.flush()的所有組合,但無濟於事。

也許有些代碼將更好地解釋它...

控制器

function homeController() { 
    ... 
    var self = this; 
    self.getData = function getData() { 
     $q.when(user.getUserInformation()).then(function() { 
      self.username = user.username; 
     }); 
    }; 
} 

單元測試

... 

beforeEach(module('home')); 

describe('Controller', function() { 
    var $httpBackend, scope, ctrl; 

    beforeEach(inject(function(_$httpBackend_, $rootScope, $componentController) { 
     $httpBackend = _$httpBackend_; 
     scope = $rootScope.$new(); // used to try and call $digest or $apply 
     // have also tried whenGET, when('GET', ..), etc... 
     $httpBackend.whenJSONP(/.*/) 
        .respond([ 
         { 
          "user_information": { 
           "username": "TestUser", 
          } 
         } 
        ]); 
     ctrl = $componentController("home"); 
    })); 

    it("should add the username to the controller", function() { 
     ctrl.getData(); // make HTTP request 
     $httpBackend.flush(); // Error: No pending request to flush ! 
     expect(ctrl.username).toBe("TestUser"); 
    }); 
}); 

... 

出於某種原因,這個工程,但是:

it("should add the username to the controller", function() { 
     ctrl.getData(); // make HTTP request 
     setTimeout(() => { 
      // don't even need to call flush, $digest, or $apply...? 
      expect(ctrl.username).toBe("TestUser"); 
     }); 
    }); 
+1

httpBackend是一個模擬實現它,如果你不使用$ http服務,以便爲單元測試的角度注入$ http服務,一個請求,你將無法使用httpBackend來捕獲它 –

回答

0

由於格雷厄姆的評論,我再放倒不同兔子洞,由於我缺乏理解幾件事情,我將在這裏總結一下,以防有人在相同的情況下結束了......

  1. 我並沒有完全理解JSONP是如何工作的。它完全不依賴於XmlHttpRequest(請參閱here)。與其試圖通過JSONP來嘲弄對這些請求的嘲諷,我只是簡單地將我調用的代碼中的「調試」標誌切換爲禁用的JSONP,然後通過XHR對象調用這些調用(如果真實響應是這樣的話,將會失敗same origin policy需要從這個外部API)。
  2. 我不是試圖使用jasmine-ajax,而是簡單地在jQuery的getJSON上設置一個間諜並返回一個模擬響應。這最終將嘲諷的響應發送給ES6的承諾,但由於某種原因,包裝ES6承諾導致的$ q承諾對象的功能沒有被調用(也沒有任何其他錯誤處理功能,即使finally)。我也嘗試在幾乎任何地方打電話$scope.$apply()它會幫助,但無濟於事。

    基本實現(在單元測試):

    ... 
    spyOn($, 'getJSON').and.callFake(function (url, success) { 
        success({"username": "TestUser"}); // send mock data 
    }); 
    ctrl.getData(); // make GET request 
    ... 
    

    問題(在控制器的源):

    // user.getUserInformation() returns an ES6 promise 
    $q.when(user.getUserInformation()).then(function() { 
        // this was never being called/reached! (in the unit tests) 
    }); 
    
  3. 最終我用#2的執行發送數據和剛剛將單元測試中的斷言封裝在沒有指定時間長度的超時內。我意識到這不是最佳的,希望不是應該如何去做,但是在嘗試了好幾個小時之後,我已經達到了極限並放棄了。如果任何人有任何想法如何改善這一點,或爲什麼then沒有被調用,我會誠實地喜歡聽到它。

    單元測試:

    ... 
    ctrl.getData(); // make GET request 
    setTimeout(() => { 
        expect(ctrl.username).toBe("TestUser"); // works! 
    });