admin管理员组

文章数量:1323318

What are ways to unit test requestAnimationFrame?

requestAnimationFrame has same nature as setTimeout/setInterval have. It is also patched by zone.js like fn's like setTimeout are patched. So options which first came to my mind are

  1. async + whenStable
  2. fakeAsync + tick(void)
  3. fakeAsync + flush
  4. fakeAsync + tick(number)
  5. setTimeout(1000) + done (jasmine)

The results:

  1. async + whenStable : just don't work
  2. fakeAsync + tick(void) : don't work
  3. fakeAsync + flush : don't work
  4. fakeAsync + tick(number) : works (read below)
  5. setTimeout(1000) + done (jasmine) : don't work

Here is the method:

 reqAnimFrame() {
   requestAnimationFrame(() => {
     console.log('log stuff');
     this.title = 'req frame title';
   });
 }

Here is the unit test (working unit test):

it('fakeAsync', fakeAsync(function () {
  const fixture = TestBed.createComponent(AppComponent);
  const app: AppComponent = fixture.debugElementponentInstance;

  fixture.detectChanges();

  app.reqAnimFrame();

  tick(16);

  expect(app.title).toBe('req frame title');
}));

Magic number. 16 is some magic number like 1000/60. It is the frame size. I just found this magic number by experiments.

Also, idea which came to my mind when I was writing this question: probably, I can somehow mock ng zone and all code which passes through it will be called synchronously (I need that). I haven't tried this yet.

UPD: After some research RAF call just put a task into macrotask zone queue. How to flush this queue from the test?

So what I am missing? How to correctly unit test method with requestAnimationFrame call?

What are ways to unit test requestAnimationFrame?

requestAnimationFrame has same nature as setTimeout/setInterval have. It is also patched by zone.js like fn's like setTimeout are patched. So options which first came to my mind are

  1. async + whenStable
  2. fakeAsync + tick(void)
  3. fakeAsync + flush
  4. fakeAsync + tick(number)
  5. setTimeout(1000) + done (jasmine)

The results:

  1. async + whenStable : just don't work
  2. fakeAsync + tick(void) : don't work
  3. fakeAsync + flush : don't work
  4. fakeAsync + tick(number) : works (read below)
  5. setTimeout(1000) + done (jasmine) : don't work

Here is the method:

 reqAnimFrame() {
   requestAnimationFrame(() => {
     console.log('log stuff');
     this.title = 'req frame title';
   });
 }

Here is the unit test (working unit test):

it('fakeAsync', fakeAsync(function () {
  const fixture = TestBed.createComponent(AppComponent);
  const app: AppComponent = fixture.debugElement.ponentInstance;

  fixture.detectChanges();

  app.reqAnimFrame();

  tick(16);

  expect(app.title).toBe('req frame title');
}));

Magic number. 16 is some magic number like 1000/60. It is the frame size. I just found this magic number by experiments.

Also, idea which came to my mind when I was writing this question: probably, I can somehow mock ng zone and all code which passes through it will be called synchronously (I need that). I haven't tried this yet.

UPD: After some research RAF call just put a task into macrotask zone queue. How to flush this queue from the test?

So what I am missing? How to correctly unit test method with requestAnimationFrame call?

Share edited May 10, 2018 at 19:35 Sharikov Vladislav asked May 10, 2018 at 17:51 Sharikov VladislavSharikov Vladislav 7,2799 gold badges52 silver badges89 bronze badges 2
  • 1 It is not opinion based at all. I am asking for the ways of testing specific stuff. – Sharikov Vladislav Commented May 10, 2018 at 18:04
  • github./angular/angular/issues/12372. Ta-daaa. – Sharikov Vladislav Commented May 11, 2018 at 10:26
Add a ment  | 

1 Answer 1

Reset to default 8

tick(16) is correct, because requestAnimationFrame in fakeAsync is just a 16ms delay macroTask.

if you want to flush in fakeAsync, just call flush(), flush is also imported from @angular/core/testing.

本文标签: javascriptWhat are options to unit test requestAnimationFrame in AngularStack Overflow