From 3165fa3f4e439def8815870a217075e35c2684cb Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Wed, 4 May 2022 18:01:14 -0700 Subject: [PATCH] perf(platform-browser): avoid including Testability by default in `bootstrapApplication` (#45885) The Testability-related logic was refactored in https://github.com/angular/angular/pull/45657 to become tree-shaking-friendly: it was decoupled from the core providers of the `BrowserModule`. This commit updates the newly-introduced `bootstrapApplication` function to exclude Testability-providers by default (note: the Testability is still included in the NgModule-based bootstrap). In order to add the Testability to the app bootstrapped via `bootstrapApplication`, the `provideProtractorTestingSupport` function is introduced. PR Close #45885 --- goldens/public-api/platform-browser/index.md | 3 ++ .../size-tracking/integration-payloads.json | 2 +- .../e2e/src/app.e2e-spec.ts | 31 +++++------------ packages/core/src/testability/testability.ts | 18 ++++++++-- .../bundle.golden_symbols.json | 24 -------------- packages/platform-browser/src/browser.ts | 33 +++++++++++++++++-- .../platform-browser/src/platform-browser.ts | 2 +- 7 files changed, 60 insertions(+), 53 deletions(-) diff --git a/goldens/public-api/platform-browser/index.md b/goldens/public-api/platform-browser/index.md index 3dde2634fbf..c07d557e08d 100644 --- a/goldens/public-api/platform-browser/index.md +++ b/goldens/public-api/platform-browser/index.md @@ -177,6 +177,9 @@ export type MetaDefinition = { // @public export const platformBrowser: (extraProviders?: StaticProvider[]) => PlatformRef; +// @public +export function provideProtractorTestingSupport(): Provider[]; + // @public export interface SafeHtml extends SafeValue { } diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index f9e147543d2..39bdb4ffb48 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -55,7 +55,7 @@ "standalone-bootstrap": { "uncompressed": { "runtime": 1090, - "main": 87940, + "main": 84237, "polyfills": 33945 } }, diff --git a/integration/standalone-bootstrap/e2e/src/app.e2e-spec.ts b/integration/standalone-bootstrap/e2e/src/app.e2e-spec.ts index 17dc7fcdc95..b29d5ba6c11 100644 --- a/integration/standalone-bootstrap/e2e/src/app.e2e-spec.ts +++ b/integration/standalone-bootstrap/e2e/src/app.e2e-spec.ts @@ -1,24 +1,11 @@ -import {browser, logging} from 'protractor'; - -import {AppPage} from './app.po'; - +/** + * Note: this file contains no e2e tests, since they rely on Protractor, + * which requires Testability. Testability is not included by default when + * the `bootstrapApplication` function is used (which is the case in this app). + * We use this app primarily to measure payload size, so we want to keep + * Testability excluded. + */ describe('Standalone Bootstrap app', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display title', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('Standalone Bootstrap app'); - }); - - afterEach(async () => { - // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); + // Jasmine will throw if there are no tests. + it('should pass', () => {}); }); diff --git a/packages/core/src/testability/testability.ts b/packages/core/src/testability/testability.ts index 160474f4f3b..902c6b024e2 100644 --- a/packages/core/src/testability/testability.ts +++ b/packages/core/src/testability/testability.ts @@ -66,8 +66,22 @@ export const TESTABILITY_GETTER = new InjectionToken(''); /** * The Testability service provides testing hooks that can be accessed from - * the browser. Each bootstrapped Angular application on the page will have - * an instance of Testability. + * the browser. + * + * Angular applications bootstrapped using an NgModule (via `@NgModule.bootstrap` field) will also + * instantiate Testability by default (in both development and production modes). + * + * For applications bootstrapped using the `bootstrapApplication` function, Testability is not + * included by default. You can include it into your applications by getting the list of necessary + * providers using the `provideProtractorTestingSupport()` function and adding them into the + * `options.providers` array. Example: + * + * ```typescript + * import {provideProtractorTestingSupport} from '@angular/platform-browser'; + * + * await bootstrapApplication(RootComponent, providers: [provideProtractorTestingSupport()]); + * ``` + * * @publicApi */ @Injectable() diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index 605faecd24e..e8b88ed7f08 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -68,9 +68,6 @@ { "name": "DefaultDomRenderer2" }, - { - "name": "DomEventsPlugin" - }, { "name": "DomRendererFactory2" }, @@ -137,9 +134,6 @@ { "name": "Injector" }, - { - "name": "KeyEventsPlugin" - }, { "name": "LOCALE_ID2" }, @@ -296,24 +290,12 @@ { "name": "TESTABILITY" }, - { - "name": "TESTABILITY_GETTER" - }, - { - "name": "TESTABILITY_PROVIDERS" - }, { "name": "THROW_IF_NOT_FOUND" }, { "name": "TRACKED_LVIEWS" }, - { - "name": "Testability" - }, - { - "name": "TestabilityRegistry" - }, { "name": "USE_VALUE" }, @@ -362,9 +344,6 @@ { "name": "_renderCompCount" }, - { - "name": "_testabilityGetter" - }, { "name": "_wrapInTimeout" }, @@ -815,9 +794,6 @@ { "name": "scheduleArray" }, - { - "name": "scheduleMicroTask" - }, { "name": "searchTokensOnInjector" }, diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index 633191cac7d..61265c3d73e 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -49,6 +49,17 @@ export interface ApplicationConfig { * const appRef: ApplicationRef = await bootstrapApplication(RootComponent); * ``` * + * Note: this bootstrap method doesn't include [Testability](api/core/Testability) by default. + * You can add [Testability](api/core/Testability) by getting the list of necessary providers + * using `provideProtractorTestingSupport()` function and add them into the `options.providers` + * array. Example: + * + * ```typescript + * import {provideProtractorTestingSupport} from '@angular/platform-browser'; + * + * await bootstrapApplication(RootComponent, providers: [provideProtractorTestingSupport()]); + * ``` + * * @param rootComponent A reference to a Standalone Component that should be rendered. * @param options Additional configuration for the bootstrap operation, see `ApplicationConfig` for * additional info. @@ -62,13 +73,29 @@ export function bootstrapApplication( rootComponent, appProviders: [ ...BROWSER_MODULE_PROVIDERS, - ...TESTABILITY_PROVIDERS, ...(options?.providers ?? []), ], platformProviders: INTERNAL_BROWSER_PLATFORM_PROVIDERS, }); } +/** + * Returns a set of providers required to setup [Testability](api/core/Testability) for an + * application bootstrapped using the `bootstrapApplication` function. The set of providers is + * needed to support testing an application with Protractor (which relies on the Testability APIs + * to be present). + * + * @returns An array of providers required to setup Testability for an application and make it + * available for testing using Protractor. + * + * @publicApi + */ +export function provideProtractorTestingSupport(): Provider[] { + // Return a copy to prevent changes to the original array in case any in-place + // alterations are performed to the `provideProtractorTestingSupport` call results in app code. + return [...TESTABILITY_PROVIDERS]; +} + export function initDomAdapter() { BrowserDomAdapter.makeCurrent(); } @@ -107,7 +134,7 @@ export const platformBrowser: (extraProviders?: StaticProvider[]) => PlatformRef const BROWSER_MODULE_PROVIDERS_MARKER = new InjectionToken(NG_DEV_MODE ? 'BrowserModule Providers Marker' : ''); -export const TESTABILITY_PROVIDERS = [ +const TESTABILITY_PROVIDERS = [ { provide: TESTABILITY_GETTER, useClass: BrowserGetTestability, @@ -125,7 +152,7 @@ export const TESTABILITY_PROVIDERS = [ } ]; -export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [ +const BROWSER_MODULE_PROVIDERS: Provider[] = [ {provide: INJECTOR_SCOPE, useValue: 'root'}, {provide: ErrorHandler, useFactory: errorHandler, deps: []}, { provide: EVENT_MANAGER_PLUGINS, diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index b76a03a5015..cef84560c34 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -export {ApplicationConfig, bootstrapApplication, BrowserModule, platformBrowser} from './browser'; +export {ApplicationConfig, bootstrapApplication, BrowserModule, platformBrowser, provideProtractorTestingSupport} from './browser'; export {Meta, MetaDefinition} from './browser/meta'; export {Title} from './browser/title'; export {disableDebugTools, enableDebugTools} from './browser/tools/tools';