/** * @license * Copyright Google LLC 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 {COMPILER_OPTIONS, Component, destroyPlatform, NgModule, ViewEncapsulation} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {onlyInIvy, withBody} from '@angular/private/testing'; describe('bootstrap', () => { beforeEach(destroyPlatform); afterEach(destroyPlatform); it('should bootstrap using #id selector', withBody('
before|
', async () => { try { const ngModuleRef = await platformBrowserDynamic().bootstrapModule(IdSelectorAppModule); expect(document.body.textContent).toEqual('before|works!'); ngModuleRef.destroy(); } catch (err) { console.error(err); } })); it('should bootstrap using one of selectors from the list', withBody('
before|
', async () => { try { const ngModuleRef = await platformBrowserDynamic().bootstrapModule(MultipleSelectorsAppModule); expect(document.body.textContent).toEqual('before|works!'); ngModuleRef.destroy(); } catch (err) { console.error(err); } })); describe('options', () => { function createComponentAndModule( options: {encapsulation?: ViewEncapsulation; preserveWhitespaces?: boolean; selector?: string} = {}) { @Component({ selector: options.selector || 'my-app', styles: [''], template: 'a b', encapsulation: options.encapsulation, preserveWhitespaces: options.preserveWhitespaces, jit: true, }) class TestComponent { } @NgModule({ imports: [BrowserModule], declarations: [TestComponent], bootstrap: [TestComponent], jit: true, }) class TestModule { } return TestModule; } it('should use ViewEncapsulation.Emulated as default', withBody('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); expect(document.body.innerHTML).toContain('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( TestModule, {defaultEncapsulation: ViewEncapsulation.None}); expect(document.body.innerHTML).toContain(''); expect(document.body.innerHTML).not.toContain('_ngcontent-'); ngModuleRef.destroy(); })); it('should allow setting defaultEncapsulation using compiler option', withBody('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic([{ provide: COMPILER_OPTIONS, useValue: {defaultEncapsulation: ViewEncapsulation.None}, multi: true }]).bootstrapModule(TestModule); expect(document.body.innerHTML).toContain(''); expect(document.body.innerHTML).not.toContain('_ngcontent-'); ngModuleRef.destroy(); })); it('should prefer encapsulation on component over bootstrap option', withBody('', async () => { const TestModule = createComponentAndModule({encapsulation: ViewEncapsulation.Emulated}); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( TestModule, {defaultEncapsulation: ViewEncapsulation.None}); expect(document.body.innerHTML).toContain('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); expect(document.body.innerHTML).toContain('a b'); ngModuleRef.destroy(); })); it('should allow setting preserveWhitespaces using bootstrap option', withBody('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( TestModule, {preserveWhitespaces: true}); expect(document.body.innerHTML).toContain('a b'); ngModuleRef.destroy(); })); it('should allow setting preserveWhitespaces using compiler option', withBody('', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic([ {provide: COMPILER_OPTIONS, useValue: {preserveWhitespaces: true}, multi: true} ]).bootstrapModule(TestModule); expect(document.body.innerHTML).toContain('a b'); ngModuleRef.destroy(); })); it('should prefer preserveWhitespaces on component over bootstrap option', withBody('', async () => { const TestModule = createComponentAndModule({preserveWhitespaces: false}); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( TestModule, {preserveWhitespaces: true}); expect(document.body.innerHTML).toContain('a b'); ngModuleRef.destroy(); })); onlyInIvy('options cannot be changed in Ivy').describe('changing bootstrap options', () => { beforeEach(() => { spyOn(console, 'error'); }); it('should log an error when changing defaultEncapsulation bootstrap options', withBody('', async () => { const platformRef = platformBrowserDynamic(); const TestModuleA = createComponentAndModule({selector: 'my-app-a'}); const ngModuleRefA = await platformRef.bootstrapModule( TestModuleA, {defaultEncapsulation: ViewEncapsulation.None}); ngModuleRefA.destroy(); const TestModuleB = createComponentAndModule({selector: 'my-app-b'}); const ngModuleRefB = await platformRef.bootstrapModule( TestModuleB, {defaultEncapsulation: ViewEncapsulation.ShadowDom}); expect(console.error) .toHaveBeenCalledWith( 'Provided value for `defaultEncapsulation` can not be changed once it has been set.'); // The options should not have been changed expect(document.body.innerHTML).not.toContain('_ngcontent-'); ngModuleRefB.destroy(); })); it('should log an error when changing preserveWhitespaces bootstrap options', withBody('', async () => { const platformRef = platformBrowserDynamic(); const TestModuleA = createComponentAndModule({selector: 'my-app-a'}); const ngModuleRefA = await platformRef.bootstrapModule(TestModuleA, {preserveWhitespaces: true}); ngModuleRefA.destroy(); const TestModuleB = createComponentAndModule({selector: 'my-app-b'}); const ngModuleRefB = await platformRef.bootstrapModule(TestModuleB, {preserveWhitespaces: false}); expect(console.error) .toHaveBeenCalledWith( 'Provided value for `preserveWhitespaces` can not be changed once it has been set.'); // The options should not have been changed expect(document.body.innerHTML).toContain('a b'); ngModuleRefB.destroy(); })); it('should log an error when changing defaultEncapsulation to its default', withBody('', async () => { const platformRef = platformBrowserDynamic(); const TestModuleA = createComponentAndModule({selector: 'my-app-a'}); const ngModuleRefA = await platformRef.bootstrapModule(TestModuleA); ngModuleRefA.destroy(); const TestModuleB = createComponentAndModule({selector: 'my-app-b'}); const ngModuleRefB = await platformRef.bootstrapModule( TestModuleB, {defaultEncapsulation: ViewEncapsulation.Emulated}); // Although the configured value may be identical to the default, the provided set of // options has still been changed compared to the previously provided options. expect(console.error) .toHaveBeenCalledWith( 'Provided value for `defaultEncapsulation` can not be changed once it has been set.'); ngModuleRefB.destroy(); })); it('should log an error when changing preserveWhitespaces to its default', withBody('', async () => { const platformRef = platformBrowserDynamic(); const TestModuleA = createComponentAndModule({selector: 'my-app-a'}); const ngModuleRefA = await platformRef.bootstrapModule(TestModuleA); ngModuleRefA.destroy(); const TestModuleB = createComponentAndModule({selector: 'my-app-b'}); const ngModuleRefB = await platformRef.bootstrapModule(TestModuleB, {preserveWhitespaces: false}); // Although the configured value may be identical to the default, the provided set of // options has still been changed compared to the previously provided options. expect(console.error) .toHaveBeenCalledWith( 'Provided value for `preserveWhitespaces` can not be changed once it has been set.'); ngModuleRefB.destroy(); })); it('should not log an error when passing identical bootstrap options', withBody('', async () => { const platformRef = platformBrowserDynamic(); const TestModuleA = createComponentAndModule({selector: 'my-app-a'}); const ngModuleRefA = await platformRef.bootstrapModule( TestModuleA, {defaultEncapsulation: ViewEncapsulation.None, preserveWhitespaces: true}); ngModuleRefA.destroy(); // Bootstrapping multiple modules using the exact same options should be allowed. const TestModuleB = createComponentAndModule({selector: 'my-app-b'}); const ngModuleRefB = await platformRef.bootstrapModule( TestModuleB, {defaultEncapsulation: ViewEncapsulation.None, preserveWhitespaces: true}); ngModuleRefB.destroy(); })); }); }); }); @Component({ selector: '#my-app', template: 'works!', }) export class IdSelectorAppComponent { } @NgModule({ imports: [BrowserModule], declarations: [IdSelectorAppComponent], bootstrap: [IdSelectorAppComponent], }) export class IdSelectorAppModule { } @Component({ selector: '[foo],span,.bar', template: 'works!', }) export class MultipleSelectorsAppComponent { } @NgModule({ imports: [BrowserModule], declarations: [MultipleSelectorsAppComponent], bootstrap: [MultipleSelectorsAppComponent], }) export class MultipleSelectorsAppModule { }