angular: regression: jasmine.clock() inside fakeAsync() doesn't work anymore since 0.8.21

This happens in an Angular application.

Simple steps to reproduce

  • install Angular CLI
  • generate a project with ng new
  • write the following clock.spec.ts test
import { fakeAsync } from '@angular/core/testing';

fdescribe('clock test', () => {

  afterEach(() => jasmine.clock().uninstall());

  it('should fake the clock in fakeAsync', fakeAsync(() => {
    const fakeTime = 12345678;
    jasmine.clock().mockDate(new Date(fakeTime));

    expect(new Date().getTime()).toBe(fakeTime);
  }));
});

Run ng test to execute the test. It fails when zone.js version 0.8.21 is being used (default dependency to zone.js in package.json is ^0.8.19, which now resolves to 0.8.21. If you change it to 0.8.20 and execute npm installor yarn install to make sure the previous version of zone.js is used, the test passes.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 5
  • Comments: 27 (22 by maintainers)

Most upvoted comments

@ohjames, @Teamop, I will check this issue again, thank you for posting the issue.

@JiaLiPassion The reproduction is simple, merely call jasmine.clock().mockDate(...) inside of your beforeEach along with your jasmine.clock().install() and it has no effect. You have to call it inside of the test now, but if you have say 100 tests grouped in the same describe block which should all use the same mocked date, now you have one hundred extra lines in your source code.

@jnizet , thank you! very glad and proud to know that!

@JiaLiPassion you not only helped me and the rest of the Angular community, but you also indirectly helped a small local non-profit organization that cares about old, poor immigrants. đź‘Ź

@JiaLiPassion this is a dumb-down version of my real test. In the actual test, I also use tick(). In fact I use this helper class:

class FakeNow {
  private now = DateTime.local(); // this is just luxon delegating to new Date()

  constructor() {
    jasmine.clock().mockDate(this.now.toJSDate());
  }

  tickSeconds(seconds: number) {
    this.now = this.now.plus({ seconds });
    jasmine.clock().mockDate(this.now.toJSDate());
    tick(seconds * 1000);
  }
}

And call fakeNow.tickSeconds() several times in my test. Everything works fine in 0.8.20.

Since 0.8.21, this doesn’t work anymore.

Based on your comments, I tried:

  • to remove the fakeAsync() wrapper as you suggest, and leave the FakeNow class as is: angular complains that tick() shouldn’t be called outside of the fakeAsync zone
  • to remove the fakeAsync() wrapper as you suggest, and remove the call to tick(seconds * 1000) in FakeNow: doesn’t work, because I use RxJS interval() in my code, and without the call to tick(), the interval observable doesn’t emit anything.

Please tell me if you need more information, and when I have some time, I’ll try to provide a reproduction of the actual problem.

@jnizet , in 0.8.21, if you use jasmine.clock(), you don’t need to call fakeAsync, zone.js will call it for you. could you try

it('should fake the clock in fakeAsync', () => {
    const fakeTime = 12345678;
    jasmine.clock().mockDate(new Date(fakeTime));

    expect(new Date().getTime()).toBe(fakeTime);
  });