diff --git a/packages/elements/src/ng-element-application-context.ts b/packages/elements/src/ng-element-application-context.ts new file mode 100644 index 0000000000..79a8d587e2 --- /dev/null +++ b/packages/elements/src/ng-element-application-context.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ApplicationRef, Injector, NgZone} from '@angular/core'; + +export class NgElementApplicationContext { + applicationRef = this.injector.get(ApplicationRef); + ngZone = this.injector.get(NgZone); + + constructor(public injector: Injector) {} + + runInNgZone(cb: () => R): R { return this.ngZone.run(cb); } +} diff --git a/packages/elements/test/ng-element-application-context_spec.ts b/packages/elements/test/ng-element-application-context_spec.ts new file mode 100644 index 0000000000..5c40891fd5 --- /dev/null +++ b/packages/elements/test/ng-element-application-context_spec.ts @@ -0,0 +1,52 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ApplicationRef, Injector, NgZone} from '@angular/core'; +import {NgElementApplicationContext} from '../src/ng-element-application-context'; + +export function main() { + describe('NgElementApplicationContext', () => { + let mockInjector: Injector; + let mockZone: NgZone; + let ctx: NgElementApplicationContext; + + beforeEach(() => { + mockZone = new NgZone({}); + mockInjector = Injector.create([ + {provide: ApplicationRef, useValue: 'mockApplicationRef'}, + {provide: NgZone, useValue: mockZone}, + ]); + + ctx = new NgElementApplicationContext(mockInjector); + }); + + it('should expose the `ApplicationRef`', + () => { expect(ctx.applicationRef as any).toBe('mockApplicationRef'); }); + + it('should expose the `Injector`', () => { expect(ctx.injector).toBe(mockInjector); }); + + it('should expose the `NgZone`', () => { expect(ctx.ngZone).toBe(mockZone); }); + + describe('runInNgZone()', () => { + it('should always run the callback inside the Angular zone', () => { + (spyOn(NgZone, 'isInAngularZone').and as any).returnValues(false, true); + spyOn(mockZone, 'run').and.callThrough(); + const callbackSpy = (jasmine.createSpy('callback').and as any).returnValues('foo', 'bar'); + + const retValues = [ + ctx.runInNgZone(callbackSpy), + ctx.runInNgZone(callbackSpy), + ]; + + expect(mockZone.run).toHaveBeenCalledTimes(2); + expect(callbackSpy).toHaveBeenCalledTimes(2); + expect(retValues).toEqual(['foo', 'bar']); + }); + }); + }); +}