2015-09-22 4 views
9

Wir versuchen derzeit, unsere eckigen Dienste zu testen, die Versprechen verwenden, um Werte an die Controller zurückgeben. Das Problem ist, dass die Funktionen, die wir an die .then hängen, nicht in Jasmine aufgerufen werden.

Wir haben festgestellt, dass das Hinzufügen von $ rootScope.digest() zur Funktion nach der Rückgabe des Versprechens synchrone Versprechungen erlaubt, aber es funktioniert immer noch nicht für Asynchrone Versprechen.

Der Code so weit ist

beforeEach(inject(function (Service, $rootScope) 
    { 
     service = Service; 
     root = $rootScope; 
    })); 

    it('gets all the available products', function (done) 
    { 
     service.getData().then(function (data) 
     { 
      expect(data).not.toBeNull(); 
      expect(data.length).toBeGreaterThan(0); 
      done(); 
     }); 
     root.$digest(); 
    }); 

In diesem Fall ist das Versprechen fein aufgerufen wird, aber wenn es asynchron ist es nicht in Anspruch genommen werden, weil das Versprechen für „Verdauung“ durch die Zeit, die Wurzel nicht bereit ist. $ digest() wird aufgerufen.

Gibt es eine Möglichkeit zu sagen, wann ein Versprechen nach der Auflösung ist, damit ich Digest aufrufen kann? Oder vielleicht etwas, das das automatisch machen würde? Dank;)

Teil des Service, den wir (Fehlerbehandlung entfernt) testen müssen:

var app = angular.module('service', []); 

/** 
* Service for accessing data relating to the updates/downloads 
* */ 
app.factory('Service', function ($q) 
{ 
    ... init 

    function getData() 
    { 
     var deffered = $q.defer(); 

     var processors = [displayNameProc]; 

     downloads.getData(function (err, data) 
     { 
      chain.process(processors, data, function (err, processedData) 
      { 
       deffered.resolve(processedData); 
      }); 
     }); 

     return deffered.promise; 
    } 
    ... 

In dem Fall, dass es ein Problem ist, wenn service.getData ist async das Versprechen gelöst wird, aber die Funktion gebunden Dieses Versprechen aus dem Testcode wird nicht aufgerufen, da der Root. $ Digest bereits aufgerufen wurde. Hoffe, dass diese weitere Informationen

Umgehung

var interval; 
beforeEach(inject(function ($rootScope) 
{ 
    if(!interval) 
    { 
     interval = function() 
     { 
      $rootScope.$digest(); 
     }; 
     window.setInterval(interval, /*timing*/); 
    } 
})); 

Ich landete mit der Problemumgehung oben rief den Digest wiederholt so jede Schicht Versprechen würde die Chance bekommen, zu laufen ... es ist nicht ideal oder ziemlich gibt aber es funktioniert für den Test ...

+0

Sind Sie Ihren Dienst spöttisch und damit die zurückgegebene Versprechen? – CainBot

+0

Nein Ich habe versucht, den tatsächlichen Dienst zu testen. – BrendanM

+0

Wenn Sie den eigentlichen Dienst testen und intern den $ http-Dienst verwenden, glaube ich, dass ein Digest von angularjs gestartet wird, wenn der Remote-Aufruf erfolgreich ist oder fehlschlägt. – CainBot

Antwort

0

sollten Sie bewegen behauptet außerhalb der dann glaube ich:

beforeEach(inject(function (Service, $rootScope) 
{ 
    service = Service; 
    root = $rootScope; 
})); 

it('gets all the available products', function (done) 
{ 
    var result; 
    service.getData().then(function (data) 
    { 
     result = data; 
     done(); 
    }); 

    root.$digest(); 

    expect(result).not.toBeNull(); 
    expect(result .length).toBeGreaterThan(0); 
}); 

Update

Forked die plunkr aus dem Kommentar unten, um zu zeigen, wie Sie einen Async-Aufruf testen können.

Es wurde ein $ timeout auf den Dienst:

var app = angular.module('bad-service', []); 

app.service('BadService', function ($q, $interval, $timeout) 
{ 
    this.innerPromise = function(){ 
     var task = $q.defer(); 
     console.log('Inside inner promise'); 

     $timeout(function() { 
     console.log('Inner promise timer fired'); 
     task.resolve(); 
     }, 500); 
     // $interval(function(){ 

     // }, 500, 1); 
     return task.promise; 
    } 
}); 

Und ich Spülen der $ timeout vor Geltendmachung:

beforeEach(module('test')); 


describe('test', function(){ 
    var service, root, $timeout; 

    beforeEach(inject(function (Service, $rootScope, _$timeout_) 
    { 
     $timeout = _$timeout_; 
     console.log('injecting'); 
     service = Service; 
     root = $rootScope; 
    })); 

    /** 
    Test one 
    */ 
    it('Should work', function(done){ 
     console.log('Before service call'); 
     service.outerPromise().then(function resolve(){ 
     console.log('I should be run!'); 
     expect(true).toBeTruthy(); 
     done(); 
     }); 
     // You will have to use the correct "resolve" here. For example when using: 
     // $httpbackend - $httpBackend.flush(); 
     // $timeout- $timeout.flush(); 
     $timeout.flush(); 

     console.log('After service call'); 
    }); 
}); 
+0

Leider funktioniert dies nicht in unserem Fall, da GetData async bedeutet, dass das Ergebnis wird zu dem Zeitpunkt null sein, zu dem es das erste erwartet (result) .not.toBeNull(); – BrendanM

+0

Diese Lösung ist spezifisch für Async-Aufrufe; hast du getestet ob es nicht funktioniert? Die Kombination von 'fertig'; und 'root. $ digest();' stellt sicher, dass Ihr Async-Aufruf aufgelöst wird, bevor die erwarteten Aufrufe aufgerufen werden. –

+0

Ja Entschuldigung, ich sehe, dass jetzt krank gibt es eine Chance – BrendanM

Verwandte Themen