2016-07-29 3 views
3

私は$q.when()でラップしたES6の約束を返す関数で作られたJSONP GETリクエストへの応答を模擬しようとしています。しかし、単体テストでは、リクエストは$ httpBackendによってキャッチされず、実際のURLに移動します。したがって、flush()が呼び出されると、Error: No pending request to flush !というエラーが表示されます。 JSONPのリクエストは、jQueryの$.getJSON()でES6の約束の中で行われたので、ハードコードされたURLの代わりに正規表現を提供することで、すべての発信リクエストをキャッチすることにしました。

私はこれまで何度もこのことを理解しようとしてきましたが、まだ何が起こっているのかまだ分かりません。あたかもES6の約束のHTTPリクエストが "Angularの外"で行われているように、$ httpBackendはそれを知りません/それを捕まえることはできませんが、そうではないかもしれませんget-goからの$ 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"); 
    }); 
}); 

... 

説明します:

グラハムさんのコメントにの
+1

httpBackendあなたが作るために$ HTTPサービスを使用していない場合は、ユニットテストのために、角度によって$ HTTPサービスに注入されたモック実装ですリクエストでは、httpBackendを使用してキャッチすることはできません –

答えて

0

おかげで、私は...原因私は、誰かが同じような状況になってしまう場合には、ここでまとめますいくつかのことを理解するの私の不足のために異なるウサギの穴のさらに下に持って来られた

  1. JSONPの仕組みを完全に理解できませんでした。 XmlHttpRequestにはまったく依存しません(here参照)。 JSONPを介してこれらのリクエストに対する応答を嘲笑しようとするのではなく、私が使用していたコードの "debug"フラグを切り替えて、XHRオブジェクトを介して呼び出しを行っていました。この外部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! 
    }); 
    
関連する問題