web-dev-qa-db-ja.com

ダイジェストを強制する$ scopeがないときに、AngularJS、Jasmine 2.0で約束を解決する方法は?

約束 $scope.$digest()を強制しない限り、Angular/Jasmineテストで解決しないでください 。これは馬鹿げたIMOですが、問題ありません(該当する場合)(コントローラー)。

私が今いる状況は、アプリケーション内のスコープをあまり気にしないサービスがあり、サーバーからデータを返すだけですが、約束は解決していないようです。

app.service('myService', function($q) {
  return {
    getSomething: function() {
      var deferred = $q.defer();
      deferred.resolve('test');
      return deferred.promise;
    }
  }
});

describe('Method: getSomething', function() {
  // In this case the expect()s are never executed
  it('should get something', function(done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
      expect(1).toEqual(2);
    });

    done();
  });

  // This throws an error because done() is never called.
  // Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
  it('should get something', function(done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
      expect(1).toEqual(2);
      done();
    });
  });
});

この機能をテストする正しい方法は何ですか?

編集:参照用のソリューション。サービスが使用していない場合でも、$ rootScopeの挿入とダイジェストを強制されているようです。

  it('should get something', function($rootScope, done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
    });

    $rootScope.$digest();
    done();
  }); 
47
Terry

テストに$rootScopeを挿入し、それに対して$digestをトリガーする必要があります。

41

常に$ rootScopeがあり、それを使用します

inject(function($rootScope){
myRootScope=$rootScope;
})
....

myRootScope.$digest();
12
mpm

angularドキュメントから。

https://docs.angularjs.org/api/ng/service/ $ q

it('should simulate promise', inject(function($q, $rootScope) {
  var deferred = $q.defer();
  var promise = deferred.promise;
  var resolvedValue;

  promise.then(function(value) { resolvedValue = value; });
  expect(resolvedValue).toBeUndefined();

  // Simulate resolving of promise
  deferred.resolve(123);
  // Note that the 'then' function does not get called synchronously.
  // This is because we want the promise API to always be async, whether or not
  // it got called synchronously or asynchronously.
  expect(resolvedValue).toBeUndefined();

  // Propagate promise resolution to 'then' functions using $apply().
  $rootScope.$apply();
  expect(resolvedValue).toEqual(123);
}));
3
Rentering.com

だから私は午後ずっとこれに苦労しています。この投稿を読んだ後、私も答えに何か外れていると感じました。上記の回答では、$rootScope.$digestを使用する場所と理由について明確な説明がありません。だから、ここに私が思いついたものがあります。

なぜ最初に?角度のないイベントまたはコールバックから応答するときは常に$rootScope.$digestを使用する必要があります。これには、純粋なDOMイベント、jQueryイベント、および角度の一部である$q以外のサードパーティのPromiseライブラリが含まれます。

第二にどこに?テストではなく、コードで。テストに$rootScopeを挿入する必要はありません。実際のangularサービスでのみ必要です。上記のすべてが答えが何であるかを明確にできない場合、それらは、テストから呼び出されたものとして$rootScope.$digestを示します。

これが、同じ問題である次の人に役立つことを願っています。

更新


昨日、この投稿が投票されたときに削除しました。今日、私はこの問題に答えを使用しようとし続けました。したがって、評判ポイントを犠牲にして回答を待機します。そのため、削除を取り消しています。

これは、非角度のイベントハンドラーで必要なものであり、$ qを使用してJasmineでテストしようとしています。

something.on('ready', function(err) {
    $rootScope.$apply(function(){deferred.resolve()});              
});

場合によっては$ timeoutでラップする必要があることに注意してください。

something.on('ready', function(err) {
    $timeout(function(){
      $rootScope.$apply(function(){deferred.resolve()});    
    });     
});

もう1つ注意してください。元の問題の例では、doneを間違ったタイミングで呼び出しています。解決後、promiseのdoneメソッド(またはthenまたはcatch)内でfinallyを呼び出す必要があります。 promiseが解決する前に呼び出しているため、it句が終了します。

3