Conflict between zone.js and Jasmine's clock
Asked Answered
F

4

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?

Frugivorous answered 20/9, 2016 at 18:0 Comment(0)
P
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.

Petrol answered 1/11, 2016 at 22:21 Comment(3)
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.Heterograft
Do you do uninstall and then install or only uninstall?Petrol
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.Heterograft
G
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();
}));
Gruesome answered 14/12, 2016 at 22:12 Comment(2)
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()Sutlej
I am running into the same issue. Were you able to find a way to mock dates properly in Angular2?Reathareave
C
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

Curb answered 23/12, 2016 at 0:55 Comment(1)
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.Charioteer
D
3

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

Dividers answered 1/2, 2018 at 0:58 Comment(1)
Thanks for fixing this!Coumarone

© 2022 - 2024 — McMap. All rights reserved.