Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test a function that contains a setTimeout()

I have a close function in my component that contains a setTimeout() in order to give time for the animation to complete.

public close() {     this.animate = "inactive"     setTimeout(() => {        this.show = false     }, 250) } 

this.show is bound to an ngIf.

this.animate is bound to an animation.

I have a test that needs to test this function

it("tests the exit button click", () => {   comp.close()   fixture.detectChanges()   //verifies the element is no longer in the DOM   const popUpWindow = fixture.debugElement.query(By.css("#popup-window"))   expect(popUpWindow).toEqual(null) }) 

How do you properly test this function when there is a setTimeout()?

I was using jasmine.clock().tick(251) but the window would never disappear. any thoughts on this as well?

like image 939
ed-tester Avatar asked Jan 20 '17 21:01

ed-tester


People also ask

How do I write a test case for setTimeout in Jasmine?

Jasmine supports testing async code. We can test async code with: describe("Using callbacks", function () { beforeEach(function (done) { setTimeout(function () { value = 0; done(); }, 1); }); it("supports sequential execution of async code", function (done) { value++; expect(value). toBeGreaterThan(0); done(); }); });

How do you write a test case for setInterval?

Something like the following: // and some test case like this it('a timer test', function(done){ var interval = a_interval_function(); expect(a_function_should_be_runned. state).to. equal({ name: 'runned', counter: 3, time: 300, }); });

How do you test Jasmine setInterval?

const x = setInterval(() => { const countdown = getElementById('countdownWrapper'); const systemTime = ... const now = new Date(). getTime(); const endTime = systemTime - now; countdown.

How do I cover setTimeout in jest?

useFakeTimers() . This is replacing the original implementation of setTimeout() and other timer functions. Timers can be restored to their normal behavior with jest.


1 Answers

You could do one of two things:

1: Actually wait in the test 250+1 ms in a setTimeout(), then check if the element actually disappeared.

2: use fakeAsync() and tick() to simulate time in the test - a tick() will resolve the setTimeout in the original close(), and the check could happen right after in a fixture.whenStable().then(...).

For example:

it("tests the exit button click", fakeAsync(() => {   comp.close()   tick(500)   fixture.detectChanges()    fixture.whenStable().then(() => {     const popUpWindow = fixture.debugElement.query(By.css("#popup-window"))     expect(popUpWindow).toBe(null)   }) })) 

I suggest using the 2nd one, as it is much more faster than actually waiting for the original method. If you still use the 1st, try lowering the timeout time before the test to make the it run faster.

SEVICES

For services you do not need to call detectChanges after tick and do not need to wrap the expect statements within whenStable. you can do your logic right after tick.

  it('should reresh token after interval', fakeAsync(() => {     // given     const service: any = TestBed.get(CognitoService);     const spy = spyOn(service, 'refreshToken').and.callThrough();     ....     // when     service.scheduleTokenRefresh();     tick(TOKEN_REFRESH_INTERVAL);     // then     expect(spy).toHaveBeenCalled();   })); 
like image 84
Mezo Istvan Avatar answered Sep 28 '22 21:09

Mezo Istvan