14

I am working with a Jasmine testing suite that includes both "vanilla" Jasmine tests along with Jasmine tests for some Angular 2 components. Because of Angular 2's inclusion, zone.js gets loaded. This creates a conflict with Jasmine's clock. For example, the following test fails with the error, Error: Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?

describe('an async test with zone.js present', function() {
  beforeEach(function() {
    jasmine.clock().install();
  });

  afterEach(function() {
    jasmine.clock().uninstall();
  });

  it('cannot install jasmine\'s mock clock', function() {
    var callback = jasmine.createSpy('setTimeoutCallback')
    setTimeout(callback, 55);
    jasmine.clock().tick(56);
    expect(callback).toHaveBeenCalled();
  });
})

Here is plunker for above code.

Short of delivering the Angular 2 tests separately from the "vanilla" tests, I am wondering what options might be available. For example, is it possible to perform the Jasmine clock's job with the zone? For example, is it possible to simulate the tick with the zone or flush all of the scheduled tasks before the assertion?

lewistg
  • 336
  • 4
  • 8

4 Answers4

6

For me it works if you uninstall the clock in beforeEach. Its not recommended by jasmine and a bit strange because for uninstall it makes more sense to use afterEach. But calling uninstall before the first install call happens fixed it for me.

Tim
  • 2,236
  • 1
  • 20
  • 26
  • This also seems to fix the issue for me but I'm not sure what it might cause because now ZoneJS functions are no longer been called. – Ido Ran Nov 15 '17 at 11:53
  • Do you do `uninstall` and then `install` or only uninstall? – Tim Nov 15 '17 at 13:37
  • both, first uninstall and then install. AFAIK the uninstall will reset whatever clock functions currently set back to real-clock, then install will always work because the check that cause the exception in the first place will now always pass because of uninstall. It works for me now but it might cause problems if I'll run a test which need ZoneJS for something. – Ido Ran Nov 15 '17 at 20:45
6

As stated on Angular documentation you should use tick function in a fakeAsync body which is part of the @angular/core/testing module.

Using your example and TypeScript it would look something like this...

import { fakeAsync, tick } from '@angular/core/testing';

...

it('cannot install jasmine\'s mock clock', fakeAsync(() => {
   var callback = jasmine.createSpy('setTimeoutCallback')
   setTimeout(callback, 55);
   tick(56);
   expect(callback).toHaveBeenCalled();
}));
j3ff
  • 5,719
  • 8
  • 38
  • 51
  • 4
    I do this for async tests, but in some tests i just want to use `jasmine.clock().mockDate()` to mock `Date`. Can't do that with `fakeAsync()` – Necros Feb 16 '17 at 09:42
  • 1
    I am running into the same issue. Were you able to find a way to mock dates properly in Angular2? – Goutham Feb 26 '17 at 22:45
4

The code which throws this here.

It implies that jasmine was loaded before Zone.js. Switch the loading order. Zone always needs to be loaded first.

Here's the fixed fork of your plunker:

<script data-require="zone.js@*" data-semver="0.4.1" src="https://cdn.rawgit.com/angular/zone.js/v0.4.1/zone.js"></script>
<script data-require="zone.js@*" data-semver="0.4.1" src="https://cdn.rawgit.com/angular/zone.js/v0.4.1/long-stack-trace-zone.js"></script>
<script data-require="jasmine@*" data-semver="2.4.1" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js"></script>

https://plnkr.co/edit/6iuvWFOZLqHWJIo4

Krzysztof Grzybek
  • 8,818
  • 2
  • 31
  • 35
Misko Hevery
  • 47,936
  • 11
  • 40
  • 36
  • 3
    For the record. To get it working with Karma 1.3 and Jasmine 2.5, we had to resort to override the `customContextFile` in the configuration. We inserted the `zone.js`, `long-stack-trace-zone.js`, and `proxy.js` from zone.js package before including the jasmine lib. Furthermore, a global `afterEach` block with `jasmine.clock().uninstall()` seemed to resolve the issues for use. – RJo Jan 23 '17 at 11:48
3

This have been resolved by https://github.com/angular/zone.js/pull/1009. zone.js and future angular will support jasmine.clock().

jiali passion
  • 1,691
  • 1
  • 14
  • 19