I finally got it. I was thinking to much about the new TestScheduler
and marble testing. But this was no the way to go. Instead fakeAsync
from Zone.js fits very well:
describe('LoginPage', () => {
let component: LoginPage;
let mockAuthService: any;
let fixture: ComponentFixture<LoginPage>;
beforeEach(async () => {
mockAuthService = jasmine.createSpyObj(['authenticate']);
await TestBed.configureTestingModule({
declarations: [LoginPage],
imports: [ReactiveFormsModule],
providers: [{ provide: AuthService, useValue: mockAuthService }]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('is in busy state while loading', fakeAsync(() => {
mockAuthService.authenticate.and.returnValue(of('result').pipe(delay(100)));
component.form.patchValue({ token: '123456' });
tick(250);
discardPeriodicTasks();
expect(component.loadingState).toBe(LoaderState.Loading);
}));
it('it is in error state when auth service denies', fakeAsync(() => {
mockAuthService.authenticate.and.returnValue(throwError({ status: 401 }));
component.form.patchValue({ token: '123456' });
tick(250);
expect(component.loadingState).toBe(LoaderState.Failed);
expect(component.message).toBeDefined();
}));
it('is in success state when auth service accept the key', fakeAsync(() => {
mockAuthService.authenticate.and.returnValue(of('result'));
component.form.patchValue({ key: '123456' });
tick(250);
expect(component.loadingState).toBe(LoaderState.Done);
}));
it('resets state on input', fakeAsync(() => {
mockAuthService.authenticate.and.returnValue(of('token'));
component.form.patchValue({ key: '123456' });
tick(250);
expect(component.loadingState).toBe(LoaderState.Done);
component.form.patchValue({ key: '12345' });
tick(250);
expect(component.loadingState).toBe(LoaderState.Idle);
}));
it('should not have error message after construction', () => {
expect(component.message).toBeNull();
});
it('is in idle state after construction', () => {
expect(component.loadingState).toBe(LoaderState.Idle);
});
});
With the tick()
method time manipulation was no problem!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…