Reputation: 655
On the angular documentation I see these two functions, tick()
and flush()
. Both of these seem to do similar things. From the angular documentation, it says for tick:
Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
and for flush:
Simulates the asynchronous passage of time for the timers in the fakeAsync zone by draining the macrotask queue until it is empty. The returned value is the milliseconds of time that would have been elapsed.
Can anyone explain the difference to me?
EDIT (answered in the comments):
In addition, in the angular documentation tick()
is used without parameters, and the comment on that line even uses the phrase "flush"
it('should display error when TwainService fails', fakeAsync(() => {
// tell spy to return an error observable
getQuoteSpy.and.returnValue(
throwError('TwainService test failure'));
fixture.detectChanges(); // onInit()
// sync spy errors immediately after init
tick(); // flush the component's setTimeout()
fixture.detectChanges(); // update errorMessage within setTimeout()
expect(errorMessage()).toMatch(/test failure/, 'should display error');
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
}));
Upvotes: 36
Views: 27639
Reputation: 1724
As of Angular 15, tick and flush call Zone.js's FakeAsyncTestZoneSpec.
tick
and flush
flush all microtasks first, e.g. Promise.then
and queueMicrotask
.tick
has a default tick count of 0, defined by Angular in milliseconds. It executes macrotasks, including periodic tasks like setInterval
, scheduled up to the current time plus the tick count.
tick
only executes the tasks scheduled up to but not at the current time.flush
has a default turn count of 20, defined by the Zone.js fake async test scheduler. It executes macrotasks, but not periodic tasks, up to the turn count number of tasks (which is treated as the limit) or the first periodic task.
flush
executes macrotasks up until the first periodic task or a maximum of 20.flush
throws an error.See async.spec.ts for a complete set of example tests.
it('tick executes all microtasks and macrotasks', fakeAsync(() => {
const spy = jasmine.createSpy('interval');
zone.runTask(() => queueMicrotask(() => { }));
zone.runTask(() => setInterval(spy, 1));
zone.runTask(() => queueMicrotask(() => { }));
expect(zone.hasPendingMicrotasks).toBeTrue();
expect(zone.hasPendingMacrotasks).toBeTrue();
tick(1);
expect(zone.hasPendingMicrotasks).toBeFalse();
expect(zone.hasPendingMacrotasks).toBeTrue();
expect(spy).toHaveBeenCalledOnceWith();
discardPeriodicTasks();
}));
it('flush executes all microtasks and non-periodic macrotasks', fakeAsync(() => {
const spy = jasmine.createSpy('interval');
zone.runTask(() => queueMicrotask(() => { }));
zone.runTask(() => setTimeout(spy));
zone.runTask(() => queueMicrotask(() => { }));
expect(zone.hasPendingMicrotasks).toBeTrue();
expect(zone.hasPendingMacrotasks).toBeTrue();
flush();
expect(zone.hasPendingMicrotasks).toBeFalse();
expect(spy).toHaveBeenCalledOnceWith();
}));
Upvotes: 1
Reputation: 54811
They do different things relative to async operations that were previously started. For example; calling setTimeout(...)
starts an async operation.
tick()
moves time forward.flush()
moves time to the end.This can be better illustrated with the unit tests for those functions.
This unit test shows tick being used to move time forward in steps until all 10 timers have finished. Tick is called multiple times.
https://github.com/angular/angular/blob/master/packages/core/test/fake_async_spec.ts#L205
it('should clear periodic timers', fakeAsync(() => {
let cycles = 0;
const id = setInterval(() => { cycles++; }, 10);
tick(10);
expect(cycles).toEqual(1);
discardPeriodicTasks();
// Tick once to clear out the timer which already started.
tick(10);
expect(cycles).toEqual(2);
tick(10);
// Nothing should change
expect(cycles).toEqual(2);
}));
This unit test shows that all async tasks should be finished when it returns, and that the returned value tells you how long it took for them to finish.
https://github.com/angular/angular/blob/master/packages/core/test/fake_async_spec.ts#L273
it('should flush multiple tasks', fakeAsync(() => {
let ran = false;
let ran2 = false;
setTimeout(() => { ran = true; }, 10);
setTimeout(() => { ran2 = true; }, 30);
let elapsed = flush();
expect(ran).toEqual(true);
expect(ran2).toEqual(true);
expect(elapsed).toEqual(30);
}));
Upvotes: 41