Skip to content

@angular-devkit/build-angular breaks Jasmine's mock clock #11626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gkalpak opened this issue Jul 23, 2018 · 6 comments · Fixed by #11627
Closed

@angular-devkit/build-angular breaks Jasmine's mock clock #11626

gkalpak opened this issue Jul 23, 2018 · 6 comments · Fixed by #11627

Comments

@gkalpak
Copy link
Member

gkalpak commented Jul 23, 2018

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Command (mark with an x)

- [x] test

Versions

> node --version
v8.11.3

> npm --version
5.6.0

> ng --version
Angular CLI: 6.1.0-rc.3
Node: 8.11.3
OS: win32 x64
Angular: 6.0.9
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.7.0-rc.3
@angular-devkit/build-angular     0.7.0-rc.3
@angular-devkit/build-optimizer   0.7.0-rc.3
@angular-devkit/build-webpack     0.7.0-rc.3
@angular-devkit/core              0.7.0-rc.3
@angular-devkit/schematics        0.7.0-rc.3
@angular/cli                      6.1.0-rc.3
@ngtools/webpack                  6.1.0-rc.3
@schematics/angular               0.7.0-rc.3
@schematics/update                0.7.0-rc.3
rxjs                              6.2.2
typescript                        2.7.2
webpack                           4.9.2

OS: Windows 10

Repro steps

  1. npm install --global @angular/cli.
  2. ng new test-app && cd test-app.
  3. npm test --> Passed ✔️
  4. Add a test in src/app/app.component.spec.ts that uses jasmine.clock().install(). E.g.:
    it('should pass', () => {
      jasmine.clock().install();
      expect(true).toBe(true);
      jasmine.clock().uninstall();
    });
  5. npm test --> Fails ❌

    Error: Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?

The log given by the failure

Chrome 67.0.3396 (Windows 10.0.0) AppComponent should pass FAILED
        Error: Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?
            at UserContext.eval (webpack:///./src/app/app.component.spec.ts?:31:25)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:387:26)
            at ProxyZoneSpec.onInvoke (webpack:///./node_modules/zone.js/dist/zone-testing.js?:287:39)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:386:32)
            at Zone.run (webpack:///./node_modules/zone.js/dist/zone.js?:137:43)
            at runInTestZone (webpack:///./node_modules/zone.js/dist/zone-testing.js?:508:34)
Chrome 67.0.3396 (Windows 10.0.0) AppComponent should pass FAILED
        Error: Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?
            at UserContext.eval (webpack:///./src/app/app.component.spec.ts?:31:25)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:387:26)
            at ProxyZoneSpec.onInvoke (webpack:///./node_modules/zone.js/dist/zone-testing.js?:287:39)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:386:32)
            at Zone.run (webpack:///./node_modules/zone.js/dist/zone.js?:137:43)
            at runInTestZone (webpack:///./node_modules/zone.js/dist/zone-testing.js?:508:34)
            at UserContext.eval (webpack:///./node_modules/zone.js/dist/zone-testing.js?:523:20)
Chrome 67.0.3396 (Windows 10.0.0): Executed 4 of 4 (1 FAILED) (0 secs / 0.433 secs)
Chrome 67.0.3396 (Windows 10.0.0) AppComponent should pass FAILED
        Error: Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?
            at UserContext.eval (webpack:///./src/app/app.component.spec.ts?:31:25)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:387:26)
            at ProxyZoneSpec.onInvoke (webpack:///./node_modules/zone.js/dist/zone-testing.js?:287:39)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:386:32)
            at Zone.run (webpack:///./node_modules/zone.js/dist/zone.js?:137:43)
            at runInTestZone (webpack:///./node_modules/zone.js/dist/zone-testing.js?:508:34)
Chrome 67.0.3396 (Windows 10.0.0): Executed 4 of 4 (1 FAILED) (0.462 secs / 0.433 secs)

Desired functionality

No errors 😁

Mention any other details that might be useful

AFAICT, the problem is caused by incorrect order of code execution. More specifically:

  • Jasmine stores the global timing functions (such as setTimeout).
  • When calling jasmine.clock().install(), it overwrites the timing functions with mocks.
  • Before doign so, it checks whether the currently global timing functions are different than what it has stored in step 1. If so, it assumes the clock is already installed (i.e. the functions are overwritten) and throws.
  • Zone.js also overwrites the global timing functions to make them zone-aware.

In order for this to work, Zone.js must patch the global functions before Jasmine stores the "original" global functions (to later compare them and determine if the clock is already installed). For some reason, it seems that Jasmine is storing the global functions before Zone.js has patched them. Then, once we call jasmine.clock().install(), Jasmine compares the orignal, unpatched global functions with the current global functions (which have since been patched by Zone.js) and finds that they are not the same (and throws).

I have no idea why this is happening, but by trying out several versions I have found out this is broken in @angular-devkit/build-angular v0.6.8 (and all the way through v0.7.0-rc.3). The commit that broke it is 0b126f6 and more specifically this change.

Reverting the test property back to also check !chunks.some(({ name }) => name === 'polyfills') fixes the issue.

@gkalpak
Copy link
Member Author

gkalpak commented Jul 23, 2018

I assume the fix would be just restoring the test property to be a function that also checks chunks, but since I have no idea what consequences it has (or how to test this), I'll leave it to someone more knowledgeable 😁

@filipesilva
Copy link
Contributor

This might be the root cause of #11164 as well.

@gkalpak
Copy link
Member Author

gkalpak commented Jul 23, 2018

Yes, I tried it and the proposed fix (reverting test to also check chunks) does fix #11164.

gkalpak added a commit to alxhub/angular that referenced this issue Jul 23, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
@gkalpak
Copy link
Member Author

gkalpak commented Jul 23, 2018

I have also confirmed that the proposed fix does affect the actual fix for #10485 (used the repro in #10485 (comment)). I will submit a PR.

gkalpak added a commit to gkalpak/angular-cli that referenced this issue Jul 23, 2018
gkalpak added a commit to gkalpak/angular-cli that referenced this issue Jul 23, 2018
gkalpak added a commit to alxhub/angular that referenced this issue Jul 23, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to gkalpak/angular-cli that referenced this issue Jul 23, 2018
gkalpak added a commit to alxhub/angular that referenced this issue Aug 23, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 24, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 24, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 24, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 24, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 24, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to alxhub/angular that referenced this issue Aug 27, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
matsko pushed a commit to angular/angular that referenced this issue Aug 27, 2018
…19795)

The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.

PR Close #19795
gkalpak added a commit to gkalpak/angular that referenced this issue Sep 18, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to gkalpak/angular that referenced this issue Sep 20, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to gkalpak/angular that referenced this issue Oct 1, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
gkalpak added a commit to gkalpak/angular that referenced this issue Oct 1, 2018
The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.
alxhub pushed a commit to angular/angular that referenced this issue Oct 3, 2018
…25997)

The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.

PR Close #25997
@whyboris
Copy link

whyboris commented Nov 16, 2018

Turns out running jasmine.clock() in fakeAsync fails, but passes without that

with "@angular-devkit/build-angular": "0.10.6" and "jasmine-core": "3.3.0" I run the following test:

  it('should do stuff', fakeAsync(() =>
      jasmine.clock().install();
      const baseTime: Date = new Date(2017, 3, 21);
      jasmine.clock().mockDate(baseTime);

      expect(...some-code...).toEqual('20170421');
  ));

but the actual outcome is 20181116 (today's date, not the mocked date).

Without fakeAsync it passes. Thank you for comment: https://github.com/angular/zone.js/issues/1063#issuecomment-377674202

Note: test worked in Angular 5 before I upgraded to Angular 7

FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this issue Jan 3, 2019
…ngular#19795)

The is a bug in versions 0.6.8+ that breaks when trying to use Jasmine's
mock clock.

Related to angular/angular-cli#11626.

PR Close angular#19795
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants