Question
How do I get tick
to work, or at least, how do I get the test to advance 10s to appropriately call submit
in my component?
Note: I don't want to do await new Promise(r => setTimeout(r, 10000))
because it will make my tests run long, and tests are supposed to be short
Goal
I want submit
to only call cb
after 10 seconds has elapsed from the creation of the component
Description
I have a timer in my component that completes after 10s. This timer changes a subject from false to true, and is used to determine whether or not it is considered valid to submit the data in the component.
In testing, tick
does not seem to advance the timer at all, and it actually runs a full 10s. I attempted to fix this by putting a fakeAsync
in the beforeEach
that creates the component to no avail.
What I have tried
- Using
fakeAsync
in the test component init, as well as the test - Using
fakeAsync
in only the test - Using
setTimeout(() => this.obs.next(true), 10_000)
instead of timer - Using
empty().pipe(delay(10000)).subscribe(() => this.obs.next(true));
instead of timer - Putting the
timer
inngOnInit
instead of constructor - Putting the
timer
in constructor instead ofngOnInit
Observations
If you adjust this code
timer(10_000).subscribe(() => this.testThis$.next(true));
to instead be this
timer(10_000).subscribe(() => {
debugger;
this.testThis$.next(true)
});
You will find that every time a test runs, the Javascript debugger in Dev Tools is triggered 10 seconds after component creation (instead of instantly if tick worked).
Code
Here's the code. At the bottom is a link to a minimal reproduction on GitHub.
// component code
import { Component, OnInit, Inject } from '@angular/core';
import { BehaviorSubject, Subject, timer } from 'rxjs';
import { first, filter } from 'rxjs/operators';
@Component({
selector: 'app-tick-test',
templateUrl: './tick-test.component.html',
styleUrls: ['./tick-test.component.scss']
})
export class TickTestComponent implements OnInit {
public testThis$: Subject<boolean>;
constructor(
@Inject('TICK_CALLBACK') private readonly cb: () => void,
) {
this.testThis$ = new BehaviorSubject<boolean>(false);
timer(10_000).subscribe(() => this.testThis$.next(true));
}
public ngOnInit(): void {
}
public submit(): void {
// call the callback after 10s
this.testThis$
.pipe(first(), filter(a => !!a))
.subscribe(() => this.cb());
}
}
// test code
/**
* The problem in this one is that I am expecting `tick` to advance the
* time for the timer that was created in the constructor, but it is not working
*/
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
import { TickTestComponent } from './tick-test.component';
describe('TickTestComponent', () => {
let component: TickTestComponent;
let fixture: ComponentFixture<TickTestComponent>;
let callback: jasmine.Spy;
beforeEach(async(() => {
callback = jasmine.createSpy('TICK_CALLBACK');
TestBed.configureTestingModule({
providers: [
{ provide: 'TICK_CALLBACK', useValue: callback },
],
declarations: [ TickTestComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TickTestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should be true after 10s', fakeAsync(() => {
tick(10_001);
component.submit();
expect(callback).toHaveBeenCalled();
}));
});
Aucun commentaire:
Enregistrer un commentaire