From 7d9aa67d8cd42fb85c8a6094076a4d018bfb22bd Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Fri, 25 Jan 2019 18:18:19 -0800 Subject: [PATCH] fix(ivy): verify bootstrapped types are Components (#28386) Prior to this change we didn't verify types passed to bootstrap as a part of NgModule semantics verification. Now we check whether all types passed to bootstrap are actually Components. PR Close #28386 --- packages/core/src/render3/jit/module.ts | 8 +++++++ .../test/browser/bootstrap_spec.ts | 24 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index ef4c8d9820..4773018e48 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -169,6 +169,7 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { ngModule.imports && flatten(ngModule.imports, unwrapModuleWithProvidersImports) .forEach(verifySemanticsOfNgModuleDef); + ngModule.bootstrap && ngModule.bootstrap.forEach(verifyCorrectBootstrapType); ngModule.bootstrap && ngModule.bootstrap.forEach(verifyComponentIsPartOfNgModule); ngModule.entryComponents && ngModule.entryComponents.forEach(verifyComponentIsPartOfNgModule); } @@ -226,6 +227,13 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { } } + function verifyCorrectBootstrapType(type: Type) { + type = resolveForwardRef(type); + if (!getComponentDef(type)) { + errors.push(`${renderStringify(type)} cannot be used as an entry component.`); + } + } + function verifyComponentEntryComponentsIsPartOfNgModule(type: Type) { type = resolveForwardRef(type); if (getComponentDef(type)) { diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index bc64dd6da8..3d2bf9c0ef 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -18,7 +18,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; +import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; @Component({selector: 'non-existent', template: ''}) class NonExistentComp { @@ -160,10 +160,8 @@ function bootstrap( afterEach(destroyPlatform); - // TODO(misko): can't use `fixmeIvy.it` because the `it` is somehow special here. - fixmeIvy( - 'FW-876: Bootstrap factory method should throw if bootstrapped Directive is not a Component') - .isEnabled && + // TODO(misko): can't use `modifiedInIvy.it` because the `it` is somehow special here. + modifiedInIvy('bootstrapping non-Component throws in View Engine').isEnabled && it('should throw if bootstrapped Directive is not a Component', inject([AsyncTestCompleter], (done: AsyncTestCompleter) => { const logger = new MockConsole(); @@ -176,6 +174,22 @@ function bootstrap( done.done(); })); + // TODO(misko): can't use `onlyInIvy.it` because the `it` is somehow special here. + onlyInIvy('bootstrapping non-Component rejects Promise in Ivy').isEnabled && + it('should throw if bootstrapped Directive is not a Component', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const logger = new MockConsole(); + const errorHandler = new ErrorHandler(); + (errorHandler as any)._console = logger as any; + bootstrap(HelloRootDirectiveIsNotCmp, [ + {provide: ErrorHandler, useValue: errorHandler} + ]).catch((error: Error) => { + expect(error).toEqual( + new Error(`HelloRootDirectiveIsNotCmp cannot be used as an entry component.`)); + async.done(); + }); + })); + it('should throw if no element is found', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const logger = new MockConsole();