2016-07-25 4 views
5

Ich bin ein Upgrade unserer Angular2 App rufen rc4 zu verwenden und ich begann, einen Fehler auf meiner Unit-Tests bekommen:Angular2 Tests laufen, die setTimeout Fehler mit „setInterval innerhalb einer Test Asynchron-Zone verwenden, kann nicht“

Can not verwenden setInterval innerhalb einer Zone async Test

My Widget eine Anforderung für Daten von seinem ngOnInit Methode macht und einen Ladeindikator setzt, während die Anforderung gemacht wird. Mein verspotter Dienst gibt einige Daten nach 1 ms zurück.

Hier ist eine vereinfachte Version, die das Problem

import { inject, async, TestComponentBuilder, ComponentFixture} from '@angular/core/testing'; 
import {Http, Headers, RequestOptions, Response, HTTP_PROVIDERS} from '@angular/http'; 
import {provide, Component} from '@angular/core'; 

import {Observable} from "rxjs/Rx"; 

class MyService { 
    constructor(private _http: Http) {} 
    getData() { 
     return this._http.get('/some/rule').map(resp => resp.text()); 
    } 
} 

@Component({ 
    template: `<div> 
     <div class="loader" *ngIf="_isLoading">Loading</div> 
     <div class="data" *ngIf="_data">{{_data}}</div> 
    </div>` 
}) 
class FakeComponent { 
    private _isLoading: boolean = false; 
    private _data: string = ''; 

    constructor(private _service: MyService) {} 

    ngOnInit() { 
     this._isLoading = true; 
     this._service.getData().subscribe(data => { 
      this._isLoading = false; 
      this._data = data; 
     }); 
    } 
} 

describe('FakeComponent',() => { 
    var service = new MyService(null); 
    var _fixture:ComponentFixture<FakeComponent>; 

    beforeEach(async(inject([TestComponentBuilder], (tcb:TestComponentBuilder) => { 
     return tcb 
      .overrideProviders(FakeComponent, [ 
       HTTP_PROVIDERS, 
       provide(MyService, {useValue: service}), 
      ]) 
      .createAsync(FakeComponent) 
      .then((fixture:ComponentFixture<FakeComponent>) => { 
       _fixture = fixture; 
      }); 
    }))); 

    it('Shows loading while fetching data', (cb) => { 
     // Make the call to getData take one ms so we can verify its state while the request is pending 
     // Error occurs here, when the widget is initialized and sends out an XHR 
     spyOn(service, 'getData').and.returnValue(Observable.of('value').delay(1)); 
     _fixture.detectChanges(); 
     expect(_fixture.nativeElement.querySelector('.loader')).toBeTruthy(); 
     // Wait a few ms, should not be loading 
     // This doesn't seem to be the problem 
     setTimeout(() => { 
      _fixture.detectChanges(); 
      expect(_fixture.nativeElement.querySelector('.loader')).toBeFalsy(); 
      cb(); 
     }, 10); 
    }); 
}); 

Dies funktionierte gut in Angular2 rc1 aussetzt und es wirft einen Fehler in rc4, irgendwelche Vorschläge?

Auch gibt es keine Fehler, wenn Sie einen setTimeout verwenden, um direkt aus dem Test selbst

 fit('lets you run timeouts', async(() => { 
      setTimeout(() => { 
       expect(1).toBe(1); 
      }, 10); 
     })); 
+0

Können Sie Jasmines done() Setup verwenden? - https://stackoverflow.com/questions/38697656/testing-angular2-components-that-use-setinterval-or-settimeout/40688469#40688469 – spinkus

+0

@ S.Pinkus ich bin, sehen Sie die CB-Funktion? –

+0

Oh ja, mein Schlechter. – spinkus

Antwort

2

ich das gleiche Problem gestoßen sind. Und ich konnte es mit dem Jasmin done Parameter umgehen.

fit('lets you run timeouts', (done) => { 
    async(() => { 
     setTimeout(() => { 
      expect(1).toBe(1); 
      done(); 
     }, 10); 
    }); 
}); 
+0

Danke, aber das Beispiel, das du kopiert hast, verursacht nicht das Problem für mich. –

+0

Auch das Hinzufügen eines Rückrufs zum ersten Beispiel in meiner Frage löst das Problem nicht. So hatte ich es früher, bevor ich herausgefunden habe, wie Async funktioniert. –

3

Ich habe festgestellt, dass aus irgendeinem Grunde nicht ein Versprechen erstellt mit Observable.of(anything).delay() in einem Test verwenden kann.

Meine Lösung dafür war, diese Zeile selbst zu implementieren, was fast Sinn ergibt, wenn man bedenkt, dass das andere Beispiel in der Frage funktioniert hat.

// This is what we should be doing, but somehow, it isn't working. 
// return Observable.of(result).delay(0)); 
function createDelayedObservable <T>(result:any, time:number = 0):Observable<T> { 
    return new Observable<T>(observer => { 
     setTimeout(() => observer.next(result), time); 
    }); 
} 

Allerdings habe ich immer noch nicht verstehen, warum die folgenden nicht fehlschlägt, so dass ich nicht in der Hoffnung, meine eigene Antwort zu akzeptieren, dass jemand mit einem soliden Verständnis der Zonen kann mir sagen, was passiert.

it('should be able to use delay in tests', (cb) => { 
    var obs = Observable.of(1).delay(0); 
    obs.subscribe(val => { 
     expect(val).toBe(1); 
     cb() 
    }); 
}); 
+0

Ich habe ein ähnliches Problem Ich möchte eine Komponente testen, die ein 'this.scroll = Observable.fromEvent (document.querySelector ('nav'), 'scroll') enthält. DebounceTime (100) .subscribe ((event) => {this.check();}); ' aber da es eine Komponente ist, habe ich keine Ahnung, wo ich den Callback platzieren würde – select

Verwandte Themen