web-dev-qa-db-ja.com

UIルーターが$ httpbackendユニットテスト、angular jsに干渉する

これは、送信機能を備えたコントローラーです。

$scope.submit = function(){   

 $http.post('/api/project', $scope.project)
      .success(function(data, status){
        $modalInstance.dismiss(true);
      })
      .error(function(data){
        console.log(data);
      })
  }
}

これは私のテストです

it('should make a post to /api/project on submit and close the modal on success', function() {
    scope.submit();

    $httpBackend.expectPOST('/api/project').respond(200, 'test');

    $httpBackend.flush();

    expect(modalInstance.dismiss).toHaveBeenCalledWith(true);
  });

私が得るエラーは次のとおりです:

Error: Unexpected request: GET views/appBar.html

views/appBar.htmlは私のtemplateUrlです:

 .state('project', {
    url: '/',
    templateUrl:'views/appBar.html',
    controller: 'ProjectsCtrl'
  })

だから何とかui-routerは私の$ httpBackendが私のsubmit関数の代わりにこれを指すようにしています。 $ httpBackendを使用するすべてのテストで同じ問題があります。

これに対する解決策はありますか?

44
Joe

この要点を取り上げてください https://Gist.github.com/wilsonwc/8358542

angular.module('stateMock',[]);
angular.module('stateMock').service("$state", function($q){
    this.expectedTransitions = [];
    this.transitionTo = function(stateName){
        if(this.expectedTransitions.length > 0){
            var expectedState = this.expectedTransitions.shift();
            if(expectedState !== stateName){
                throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName );
            }
        }else{
            throw Error("No more transitions were expected! Tried to transition to "+ stateName );
        }
        console.log("Mock transition to: " + stateName);
        var deferred = $q.defer();
        var promise = deferred.promise;
        deferred.resolve();
        return promise;
    }
    this.go = this.transitionTo;
    this.expectTransitionTo = function(stateName){
        this.expectedTransitions.Push(stateName);
    }

    this.ensureAllTransitionsHappened = function(){
        if(this.expectedTransitions.length > 0){
            throw Error("Not all transitions happened!");
        }
    }
});

Test/mockフォルダーのstateMockというファイルに追加し、まだ取得していない場合は、そのファイルをカルマ構成に含めます。

テスト前のセットアップは次のようになります。

beforeEach(module('stateMock'));

// Initialize the controller and a mock scope
beforeEach(inject(function ($state //other vars as needed) {
    state = $state;
    //initialize other stuff
}

次に、テストで追加する必要があります

state.expectTransitionTo('project');
48
rosswil

nit Testing UI Router に関するこのGithubの問題は、何が起こっているかをより完全に説明しています。

問題は、$httpBackend.flush()がブロードキャストをトリガーし、それがstateProviderのその他の場合をトリガーすることです。

上記のGithubスレッドの@darinclarkで言及されているように、簡単な解決策は次のセットアップを行うことです。これは、状態遷移をテストする必要がない場合に有効です。それ以外の場合は、- @ rosswil's answer に目を向けてください。これは Githubの@Vratislav answer に触発されたものです。

beforeEach(module(function ($urlRouterProvider) {
    $urlRouterProvider.otherwise(function(){return false;});
}));

[〜#〜]編集済み[〜#〜]

これをコメントで報告してくれたChris Tに感謝します。v0.2.14以降ですか?これを行う最良の方法は、使用することです

beforeEach(module(function($urlRouterProvider) {
  $urlRouterProvider.deferIntercept();
}));
39

正しいソリューションにあるようにGistファイルを追加したくない場合は、$ httpBackendに「when」条件を追加して、次のようなビューのGETを無視できます。

$httpBackend.when("GET", function (url) {
    // This condition works for my needs, but maybe you need to improve it
    return url.indexOf(".tpl.html") !== -1;
}).passThrough();
3

あなたがコメントしたのと同じエラーがあります、コールサービスの後、彼らはそれ以外の場合はui-routeのURLについて尋ねます。

呼び出しの問題を解決するために、テストでのその他のui-routeはinject $ state in beforeach statmentです。私のテストでは、$ stateを使用する意味がありません。

2
Alex Carod

Ui.routerに依存しない独自のモジュールにサービスを移動します。メインアプリがこのモジュールに依存するようにします。テストするときは、メインアプリをテストしないで、サービスが含まれているモジュールをテストします。このモジュールはui.routerについて何も知らないため、状態プロバイダーは状態/ルートを変更しようとしません。これは私のために働いた。

1
Maccurt