Description
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
npm install --global @angular/cli
.ng new test-app && cd test-app
.npm test
--> Passed ✔️- Add a test in
src/app/app.component.spec.ts
that usesjasmine.clock().install()
. E.g.:it('should pass', () => { jasmine.clock().install(); expect(true).toBe(true); jasmine.clock().uninstall(); });
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.