1

I'm writing an Angular service that uses requestIdleCallback to call another function, foo. In my test, I want to make sure that foo is being called eventually.

Currently I have a test that looks like this:

   it('test', fakeAsync(() => {
     // Triggers a requestIdleCallback call.
     service.doSomething();

     flush();
     expect(otherService.foo).toHaveBeenCalled();
   }));

But when I run this test, I get an error saying that otherService.foo was never called. I've tried replacing the flush with flushMicroTasks() and tick() with a long timer to no avail. The only thing that has worked so far was to use done() and add a setTimeout to the test itself like this:

   it('test', (done) => {
     // Triggers a requestIdleCallback call.
     service.doSomething();

     setTimeout(() => {
       expect(otherService.foo).toHaveBeenCalled();      
       done();
     }, 1);
   });

But I would like to avoid this because it could cause some flakiness. Is there anyway to guarantee that requestIdleCallback was flushed before I make my test assertion?

Evan
  • 222
  • 3
  • 9

1 Answers1

0

According to this PR comment, you can define custom macroTasks to be tested by fakeAsync zone.

They say you have two options:

  1. pass the options from FakeAsyncTestSpec constructor

    const testZoneSpec = new FakeAsyncTestZoneSpec('name', false, [{source: 'HTMLCanvasElement.toBlob'}]);
    
  2. sometimes application test code can't access FakeAsyncTestSpec initialize process, so user can also define a global variable before load fakeAsyncTest.

    [...]

    window['__zone_symbol__FakeAsyncTestMacroTask'] = [{
      source: 'HTMLCanvasElement.toBlob',
      callbackArgs: ['testBlobData']  // the test blob data which will be passed back to callback
    }];
    

So in your case you'd replace source: HTMLCanvasElement.toBlob with source: window.requestIdleCallback.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • This looked promising but it didn't work for me. Typescript didn't find the property: `__zone_symbol__FakeAsyncTestMacroTask` on window or global so it could be an environmental issue? And setting it to the souce you suggested did not pass the test. – Evan Apr 11 '20 at 04:24
  • @Evan I'm far from being an Angular ninja, but the quote says "user can also define a global variable before load fakeAsyncTest." You have to define it, and to do it **before** you import fakeAsyncTest. – Kaiido Apr 11 '20 at 08:35
  • Right, I've tried to replicate the test like so: https://github.com/angular/angular/blob/master/aio/content/examples/testing/src/app/shared/canvas.component.spec.ts but it did not work. – Evan Apr 13 '20 at 07:18