2016-06-07 58 views
2

所以我遇到了一個情況,就是我們不得不擊中不在我們控制下的「寧靜」服務,爲了從GET服務中獲得json的服務,我們必須通過Content-Type =「application/json」。唯一的問題是Angular從GET請求標題中去除Content-Type。我發現了一個博客帖子上使用$ httpBackend一個裝飾,使我們能夠攔截呼叫被髮送之前,並添加回內容類型建議:

angular 
.module('MyApp') 
.decorator('$httpBackend', [ 
    '$delegate', function($delegate) { 
     return function() { 
      var contentType, headers; 
      headers = arguments[4]; 
      contentType = headers != null ? headers['X-Force-Content-Type'] : null; 
      if (contentType != null && headers['Content-Type'] == null) 
      headers['Content-Type'] = contentType; 

      return $delegate.apply(null, arguments); 
     }; 
    }]); 

是這樣,那精美的作品!現在我們的問題是它打破了我們使用模擬$ httpBackend服務的所有單元測試。我們得到的唯一錯誤是「未定義」。

Ex。單元測試方法:

it('should return service.model.error if service returns an exception code from EndProject', 
inject(function($httpBackend) { 
     var mockResponse = sinon.stub({ 'exception': 'Unable to retrieve service data' }); 
     $httpBackend.whenPUT(this.endProjectUrl).respond(mockResponse); 
     var data; 
     this.service.EndProject().then(function(fetchedData) { 
      data = fetchedData; 
     }); 

     $httpBackend.flush(); 
     expect(data.error.state).toBe(true); 
     expect(data.error.message).toEqual('Unable to retrieve service data'); 
})); 

PhantomJS 2.1.1(Mac OS X的0.0.0)projectService EndProject應該返回service.model.error如果服務返回從EndProject異常代碼FAILED 未定義 /用戶/ mlm1205 /Documents/THDSource/bolt-projects/html_app/src/app/components/services/project/projectService.spec.js:213:41 invoke @/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular/angular.js:4560:22 [email protected]/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular-mocks/angular-mocks.js:2518:26

回答

0

雖然我將estus的答案標記爲解決方案,但完全基於我的問題......最終,這不是我們的最終結果。在沒有通過樹看到森林的情況下,最簡單的解決方案是在$ http調用的配置中添加一個空數據元素。之前我曾經嘗試過,它不起作用(或者看起來似乎如此),但是在再次播放它之後,它確實起作用了,我們可以從應用程序中刪除裝飾器。

return $http.get(getItemInformationUrl + params, { dataType: 'json', data: '', headers: {'Content-Type': 'application/json'} }).then(getItemInformationCompleted).catch(getItemInformationFailed); 
1

列出的裝飾器包含簡單的猴子修補方案,其中修補的函數不是構造函數,也沒有靜態屬性和方法。

這對於$httpBackend in ng module是正確的,它只是一個沒有額外特性的工廠函數。

這不適用於ngMockngMockE2E模塊,它們會覆蓋$httpBackend並且具有靜態方法at least some of them are documented

這意味着,總體上是安全的配方(不包括非枚舉和繼承的屬性)的猴子修補工廠函數無論是

app.decorator('$httpBackend', ['$delegate', function ($delegate) { 
    var $httpBackend = function() { 
     ... 
     return $delegate.apply(null, arguments); 
    }; 
    angular.extend($httpBackend, $delegate); 
    return $httpBackend; 
}]); 

,這是一個好習慣的模塊化應用程序的水平,單位可以孤立測試,沒有過多的運動部件(這個問題是一個表達性的例子,爲什麼這很重要)。方便的是具有app(自舉在生產),app.e2e(在E2E測試自舉),app.common(公分母),app.unitA(加載在app.common,並且可以在單元測試分別裝載)等

大多數應用的範圍內的代碼(configrun塊,路由)可能會移動到單獨的模塊,並且只能加載到直接依賴它們的模塊中。除非這是測試decorator單元本身的規格,否則裝飾模塊不應加載。

調試規格錯誤時,還請注意Chrome may offer superior experience比PhantomJS。

+0

我試過了,但是這個調用仍然在剝離Content-Type。我有一個攔截器,它注入了我們的負載均衡器所需的另一個頭,並且已經嘗試過這種Content-Type,但它不起作用。我通過攔截器代碼進行調試,並確認它確實添加了標題,但是當您查看「網絡」選項卡(Chrome開發工具)中的實際調用時,Content-Type標頭消失了。 – Shaggy13spe

+0

我想我以前曾經誤解過你的情況。儘管事實上單元測試沒有提出真正的請求,但您已經有了適用於您的現有生產裝飾器,但在單元測試中失敗。我已經更新了答案。看到關於PhantomJS的評論,我很確定錯誤信息因此被破壞,並且應該說'undefined不是一個函數',因爲'$ httpBackend.whenPUT(...)'。 – estus

+0

是的,抱歉,如果我沒有更清楚。我會盡量按照你的建議玩一下。我真的想要推回創建該服務的團隊來改變它,因爲在GET請求上需要該頭部是很荒謬的。 – Shaggy13spe