Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between fakeAsync's tick() and done() in angular2 testing?

I'm trying to figure out what differentiates fakeAsync's tick() method from done() as suggested by some answers on stack overflow.

Using tick() we can simulate a timeout, but can we accomplish the same using done()?

Why does angular consider it more viable method than using async or fakeAsync?

Take for example.

This method works for me...

it("Should display names",(done:any) => {
        component.names = [
            {
                "firstname": "abc",
                "lastname": "max"
            },
            {
                "firstname": "def",
                "lastname": "max"
            },
        ];
        done();
        fixture.detectChanges();
        let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
        console.log(wrapBox);
});

But following method returns '6 timer(s) still in queue' error...

it("Should display names",fakeAsync(() => {
        component.names = [
            {
                "firstname": "abc",
                "lastname": "max"
            },
            {
                "firstname": "def",
                "lastname": "max"
            },
        ];
        tick();
        fixture.detectChanges();
        let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
        console.log(wrapBox);
}));

Note:

  1. The data for array names is asynchronous since it's retrieved from back end using 'get' operation. But here i'm mocking the data.

  2. The data in array is iterated through and passed to another child component which displays it in the view.

like image 913
Sanju Avatar asked Oct 20 '17 06:10

Sanju


People also ask

What is tick () in Angular testing?

ticklink. Simulates the asynchronous passage of time for the timers in the fakeAsync zone.

What is the difference between async ()' and fakeAsync ()?

In almost all cases, they can be used interchangeably, but using fakeAsync()/tick() combo is preferred unless you need to make an XHR call, in which case you MUST use async()/whenStable() combo, as fakeAsync() does not support XHR calls. For the most part they can be used interchangeably.

What is tick in fakeAsync?

fakeAsynclink Timers are synchronous; tick() simulates the asynchronous passage of time.

What does flush () do in Jasmine?

Jasmine: Using fakeAsync() and flush() flush(), on the other hand, will apply the changes to the testing components that will in turn reflect the new changes to the testing component.


1 Answers

Those 2 things have nothing in common.

done is just a callback to let your test runner know when an async operation is done.

For example:

it('should wait for this promise to finish', done => {
  const p = new Promise((resolve, reject) =>
    setTimeout(() => resolve(`I'm the promise result`), 1000)
  );

  p.then(result => {
    // following will display "I'm the promise result" after 1s
    console.log(result);

    // this let your test runner know that it can move forward
    // because we're done here
    // the test will take 1s due to the setTimeout at 1000ms
    done();
  });
});

You might also use async for that (just to avoid calling done manually):

it(
  'should wait for this promise to finish',
  async(() => {
    const p = new Promise((resolve, reject) =>
      setTimeout(() => resolve(`I'm the promise result`), 1000)
    );

    p.then(result =>
      // following will display "I'm the promise result" after 1s
      console.log(result)
    );

    // notice that we didn't call `done` here thanks to async
    // which created a special zone from zone.js
    // this test is now aware of pending async operation and will wait
    // for it before passing to the next one
  })
);

Now, fakeAsync gives you control over time (which is really powerful) so you can write your tests in a synchronous way, and simulate that time goes by to avoid waiting for setTimeout for example:

it(
  'should wait for this promise to finish',
  fakeAsync(() => {
    const p = new Promise((resolve, reject) =>
      setTimeout(() => resolve(`I'm the promise result`), 1000)
    );

    // simulates time moving forward and executing async tasks
    flush();

    p.then(result =>
      // following will display "I'm the promise result" **instantly**
      console.log(result)
    );

    // notice that we didn't call `done` here has there's no async task pending
  })
);

So just to be clear, with fakeAsync in the last example, if the setTimeout was set on 10s, the test would still be executed instantly.

like image 51
maxime1992 Avatar answered Oct 05 '22 06:10

maxime1992