2015-09-22 36 views
9

Attualmente stiamo provando a testare i nostri servizi angolari che utilizzano le promesse per restituire valori ai controller. Il problema è che le funzioni che assegniamo al .then non vengono chiamate in Jasmine.

Abbiamo rilevato che l'aggiunta di $ rootScope.digest() alla funzione dopo che la promessa viene restituita consente di chiamare le promesse sincrone, tuttavia non funziona ancora per le promesse asincrone.

Il codice finora è

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 questo caso la promessa viene chiamato bene ma se è asincrono non sarà chiamato perché la promessa non è pronto per "digestione" dal tempo di radice. $ digest() è chiamato.

C'è un modo per dire quando una promessa è dopo essere stata risolta in modo che io possa chiamare digest? O forse qualcosa che lo farebbe automaticamente? Grazie;)

parziale del Servizio dobbiamo testare (gestione degli errori rimosso):

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; 
    } 
    ... 

Nel caso in cui ci sia un problema è quando service.getData è asincrona la promessa viene risolto ma la funzione attaccato a quella promessa dal codice di prova non viene chiamato perché la radice. $ digest è già stato chiamato. Spero che questo dà più informazioni

Soluzione

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

ho finito per usare la soluzione precedente per chiamare ripetutamente il digest così ogni strato della promessa avrebbe avuto la possibilità di correre ... non il suo ideale o abbastanza ma funziona per il test ...

+0

State beffardo il vostro servizio e quindi la promessa tornato? – CainBot

+0

No Stavo cercando di testare il servizio effettivo. – BrendanM

+0

Se si sta testando il servizio effettivo e si sta utilizzando internamente il servizio $ http, credo che un digest verrà avviato da angularjs quando la chiamata remota ha esito positivo o negativo. – CainBot

risposta

0

si dovrebbe spostare il vostro afferma al di fuori della allora credo:

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); 
}); 

Aggiornamento

Biforco il plunkr del commento qui sotto per mostrare come è possibile testare una chiamata asincrona.

Aggiunto un $ timeout per il servizio:

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; 
    } 
}); 

E sto lavaggio del $ timeout prima di affermare:

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

Sfortunatamente questo non funzionerà nel nostro caso perché getData è asincrono, il che significa che il risultato sarà essere nullo dal momento in cui raggiunge la prima attesa (risultato) .not.toBeNull(); – BrendanM

+0

Questa soluzione è specifica per le chiamate asincrone; hai provato se non funziona? La combinazione di 'done();' e 'root. $ digest();' farà in modo che la tua chiamata asincrona venga risolta prima che vengano chiamate le aspettative. –

+0

Sì, scusami, vedo che ora mi dà un colpo – BrendanM

Problemi correlati