diff --git a/goldens/public-api/core/index.md b/goldens/public-api/core/index.md index a26561a7b88..de8a175a2ee 100644 --- a/goldens/public-api/core/index.md +++ b/goldens/public-api/core/index.md @@ -1272,7 +1272,7 @@ export abstract class TemplateRef { // @public export class Testability implements PublicTestability { - constructor(_ngZone: NgZone); + constructor(_ngZone: NgZone, registry: TestabilityRegistry, testabilityGetter: GetTestability); // @deprecated decreasePendingRequestCount(): number; findProviders(using: any, provider: string, exactMatch: boolean): any[]; @@ -1290,7 +1290,6 @@ export class Testability implements PublicTestability { // @public export class TestabilityRegistry { - constructor(); findTestabilityInTree(elem: Node, findInAncestors?: boolean): Testability | null; getAllRootElements(): any[]; getAllTestabilities(): Testability[]; diff --git a/goldens/size-tracking/aio-payloads.json b/goldens/size-tracking/aio-payloads.json index 61da0ac5b3d..25dda699a17 100755 --- a/goldens/size-tracking/aio-payloads.json +++ b/goldens/size-tracking/aio-payloads.json @@ -12,7 +12,7 @@ "aio-local": { "uncompressed": { "runtime": 4343, - "main": 454248, + "main": 454794, "polyfills": 33980, "styles": 71714, "light-theme": 78213, diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index 1080c48bb6a..f9e147543d2 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -2,7 +2,7 @@ "cli-hello-world": { "uncompressed": { "runtime": 1083, - "main": 126738, + "main": 126542, "polyfills": 33824 } }, @@ -19,7 +19,7 @@ "cli-hello-world-ivy-compat": { "uncompressed": { "runtime": 1102, - "main": 133348, + "main": 133968, "polyfills": 33957 } }, @@ -41,7 +41,7 @@ "forms": { "uncompressed": { "runtime": 1063, - "main": 158922, + "main": 159280, "polyfills": 33804 } }, diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index 776dc0dee90..30ccbfab2ed 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -40,7 +40,7 @@ import {setJitOptions} from './render3/jit/jit_options'; import {isStandalone} from './render3/jit/module'; import {createEnvironmentInjector, NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref'; import {publishDefaultGlobalUtils as _publishDefaultGlobalUtils} from './render3/util/global_utils'; -import {Testability, TestabilityRegistry} from './testability/testability'; +import {TESTABILITY} from './testability/testability'; import {isPromise} from './util/lang'; import {scheduleMicroTask} from './util/microtask'; import {stringify} from './util/stringify'; @@ -944,18 +944,13 @@ export class ApplicationRef { const selectorOrNode = rootSelectorOrNode || componentFactory.selector; const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule); const nativeElement = compRef.location.nativeElement; - const testability = compRef.injector.get(Testability, null); - const testabilityRegistry = testability && compRef.injector.get(TestabilityRegistry); - if (testability && testabilityRegistry) { - testabilityRegistry.registerApplication(nativeElement, testability); - } + const testability = compRef.injector.get(TESTABILITY, null); + testability?.registerApplication(nativeElement); compRef.onDestroy(() => { this.detachView(compRef.hostView); remove(this.components, compRef); - if (testabilityRegistry) { - testabilityRegistry.unregisterApplication(nativeElement); - } + testability?.unregisterApplication(nativeElement); }); this._loadComponent(compRef); diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 83207119c43..8365cc408f3 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -24,6 +24,7 @@ export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/r export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, BypassType as ɵBypassType, getSanitizationBypassType as ɵgetSanitizationBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass'; export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer'; export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer'; +export {TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER} from './testability/testability'; export {coerceToBoolean as ɵcoerceToBoolean} from './util/coercion'; export {devModeEqual as ɵdevModeEqual} from './util/comparison'; export {makeDecorator as ɵmakeDecorator} from './util/decorators'; diff --git a/packages/core/src/testability/testability.ts b/packages/core/src/testability/testability.ts index bb1648e63f4..160474f4f3b 100644 --- a/packages/core/src/testability/testability.ts +++ b/packages/core/src/testability/testability.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable} from '../di'; +import {Inject, Injectable, InjectionToken} from '../di'; import {scheduleMicroTask} from '../util/microtask'; import {NgZone} from '../zone/ng_zone'; @@ -48,6 +48,22 @@ interface WaitCallback { updateCb?: UpdateCallback; } +/** + * Internal injection token that can used to access an instance of a Testability class. + * + * This token acts as a bridge between the core bootstrap code and the `Testability` class. This is + * needed to ensure that there are no direct references to the `Testability` class, so it can be + * tree-shaken away (if not referenced). For the environments/setups when the `Testability` class + * should be available, this token is used to add a provider that references the `Testability` + * class. Otherwise, only this token is retained in a bundle, but the `Testability` class is not. + */ +export const TESTABILITY = new InjectionToken(''); + +/** + * Internal injection token to retrieve Testability getter class instance. + */ +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 @@ -69,7 +85,15 @@ export class Testability implements PublicTestability { private taskTrackingZone: {macroTasks: Task[]}|null = null; - constructor(private _ngZone: NgZone) { + constructor( + private _ngZone: NgZone, private registry: TestabilityRegistry, + @Inject(TESTABILITY_GETTER) testabilityGetter: GetTestability) { + // If there was no Testability logic registered in the global scope + // before, register the current testability getter as a global one. + if (!_testabilityGetter) { + setTestabilityGetter(testabilityGetter); + testabilityGetter.addToWindow(registry); + } this._watchAngularEvents(); _ngZone.run(() => { this.taskTrackingZone = @@ -213,6 +237,25 @@ export class Testability implements PublicTestability { getPendingRequestCount(): number { return this._pendingCount; } + /** + * Registers an application with a testability hook so that it can be tracked. + * @param token token of application, root element + * + * @internal + */ + registerApplication(token: any) { + this.registry.registerApplication(token, this); + } + + /** + * Unregisters an application. + * @param token token of application, root element + * + * @internal + */ + unregisterApplication(token: any) { + this.registry.unregisterApplication(token); + } /** * Find providers by name @@ -235,10 +278,6 @@ export class TestabilityRegistry { /** @internal */ _applications = new Map(); - constructor() { - _testabilityGetter.addToWindow(this); - } - /** * Registers an application with a testability hook so that it can be tracked * @param token token of application, root element @@ -292,7 +331,7 @@ export class TestabilityRegistry { * current node */ findTestabilityInTree(elem: Node, findInAncestors: boolean = true): Testability|null { - return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors); + return _testabilityGetter?.findTestabilityInTree(this, elem, findInAncestors) ?? null; } } @@ -308,14 +347,6 @@ export interface GetTestability { Testability|null; } -class _NoopGetTestability implements GetTestability { - addToWindow(registry: TestabilityRegistry): void {} - findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean): - Testability|null { - return null; - } -} - /** * Set the {@link GetTestability} implementation used by the Angular testing framework. * @publicApi @@ -324,4 +355,4 @@ export function setTestabilityGetter(getter: GetTestability): void { _testabilityGetter = getter; } -let _testabilityGetter: GetTestability = new _NoopGetTestability(); +let _testabilityGetter: GetTestability|undefined; diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index a9628ec47b8..f8af9895d8e 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -95,9 +95,6 @@ { "name": "BrowserDomAdapter" }, - { - "name": "BrowserGetTestability" - }, { "name": "BrowserModule" }, @@ -446,6 +443,15 @@ { "name": "Subscription" }, + { + "name": "TESTABILITY" + }, + { + "name": "TESTABILITY_GETTER" + }, + { + "name": "TESTABILITY_PROVIDERS" + }, { "name": "THROW_IF_NOT_FOUND" }, diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index bf3075fda71..8fefd20c098 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -47,9 +47,6 @@ { "name": "BrowserDomAdapter" }, - { - "name": "BrowserGetTestability" - }, { "name": "BrowserModule" }, @@ -458,6 +455,15 @@ { "name": "Subscription" }, + { + "name": "TESTABILITY" + }, + { + "name": "TESTABILITY_GETTER" + }, + { + "name": "TESTABILITY_PROVIDERS" + }, { "name": "THROW_IF_NOT_FOUND" }, diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index a2849668caf..b24fd3660e4 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -50,9 +50,6 @@ { "name": "BrowserDomAdapter" }, - { - "name": "BrowserGetTestability" - }, { "name": "BrowserModule" }, @@ -449,6 +446,15 @@ { "name": "Subscription" }, + { + "name": "TESTABILITY" + }, + { + "name": "TESTABILITY_GETTER" + }, + { + "name": "TESTABILITY_PROVIDERS" + }, { "name": "THROW_IF_NOT_FOUND" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 98954cf46b4..c88474e7ae9 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -53,9 +53,6 @@ { "name": "BrowserDomAdapter" }, - { - "name": "BrowserGetTestability" - }, { "name": "BrowserModule" }, @@ -641,6 +638,15 @@ { "name": "SwitchMapSubscriber" }, + { + "name": "TESTABILITY" + }, + { + "name": "TESTABILITY_GETTER" + }, + { + "name": "TESTABILITY_PROVIDERS" + }, { "name": "THROW_IF_NOT_FOUND" }, 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 7af7c185a39..c44f51d0c68 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -23,9 +23,6 @@ { "name": "BrowserDomAdapter" }, - { - "name": "BrowserGetTestability" - }, { "name": "BrowserXhr" }, @@ -71,6 +68,9 @@ { "name": "DefaultDomRenderer2" }, + { + "name": "DomEventsPlugin" + }, { "name": "DomRendererFactory2" }, @@ -137,6 +137,9 @@ { "name": "Injector" }, + { + "name": "KeyEventsPlugin" + }, { "name": "LOCALE_ID2" }, @@ -290,6 +293,15 @@ { "name": "Subscription" }, + { + "name": "TESTABILITY" + }, + { + "name": "TESTABILITY_GETTER" + }, + { + "name": "TESTABILITY_PROVIDERS" + }, { "name": "THROW_IF_NOT_FOUND" }, diff --git a/packages/core/test/testability/testability_spec.ts b/packages/core/test/testability/testability_spec.ts index 907e64aa2e2..7b506c55299 100644 --- a/packages/core/test/testability/testability_spec.ts +++ b/packages/core/test/testability/testability_spec.ts @@ -8,7 +8,7 @@ import {EventEmitter} from '@angular/core'; import {Injectable} from '@angular/core/src/di'; -import {PendingMacrotask, Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; +import {GetTestability, PendingMacrotask, Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; import {NgZone} from '@angular/core/src/zone/ng_zone'; import {fakeAsync, flush, tick, waitForAsync} from '@angular/core/testing'; @@ -23,6 +23,14 @@ function microTask(fn: Function): void { }); } +class NoopGetTestability implements GetTestability { + addToWindow(registry: TestabilityRegistry): void {} + findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean): + Testability|null { + return null; + } +} + @Injectable() class MockNgZone extends NgZone { /** @internal */ @@ -56,7 +64,7 @@ class MockNgZone extends NgZone { beforeEach(waitForAsync(() => { ngZone = new MockNgZone(); - testability = new Testability(ngZone); + testability = new Testability(ngZone, new TestabilityRegistry(), new NoopGetTestability()); execute = jasmine.createSpy('execute'); execute2 = jasmine.createSpy('execute'); updateCallback = jasmine.createSpy('execute'); @@ -366,9 +374,9 @@ class MockNgZone extends NgZone { beforeEach(waitForAsync(() => { ngZone = new MockNgZone(); - testability1 = new Testability(ngZone); - testability2 = new Testability(ngZone); registry = new TestabilityRegistry(); + testability1 = new Testability(ngZone, registry, new NoopGetTestability()); + testability2 = new Testability(ngZone, registry, new NoopGetTestability()); })); describe('unregister testability', () => { it('should remove the testability when unregistering an existing testability', () => { diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index 964e0fe35d6..633191cac7d 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -7,7 +7,7 @@ */ import {CommonModule, DOCUMENT, XhrFactory, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; -import {APP_ID, ApplicationModule, ApplicationRef, createPlatformFactory, ErrorHandler, ImportedNgModuleProviders, Inject, InjectionToken, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, SkipSelf, StaticProvider, Testability, Type, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵinternalBootstrapApplication as internalBootstrapApplication, ɵsetDocument} from '@angular/core'; +import {APP_ID, ApplicationModule, ApplicationRef, createPlatformFactory, ErrorHandler, ImportedNgModuleProviders, Inject, InjectionToken, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, SkipSelf, StaticProvider, Testability, TestabilityRegistry, Type, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵinternalBootstrapApplication as internalBootstrapApplication, ɵsetDocument, ɵTESTABILITY as TESTABILITY, ɵTESTABILITY_GETTER as TESTABILITY_GETTER} from '@angular/core'; import {BrowserDomAdapter} from './browser/browser_adapter'; import {SERVER_TRANSITION_PROVIDERS, TRANSITION_ID} from './browser/server-transition'; @@ -62,6 +62,7 @@ export function bootstrapApplication( rootComponent, appProviders: [ ...BROWSER_MODULE_PROVIDERS, + ...TESTABILITY_PROVIDERS, ...(options?.providers ?? []), ], platformProviders: INTERNAL_BROWSER_PLATFORM_PROVIDERS, @@ -70,7 +71,6 @@ export function bootstrapApplication( export function initDomAdapter() { BrowserDomAdapter.makeCurrent(); - BrowserGetTestability.init(); } export function errorHandler(): ErrorHandler { @@ -107,6 +107,24 @@ export const platformBrowser: (extraProviders?: StaticProvider[]) => PlatformRef const BROWSER_MODULE_PROVIDERS_MARKER = new InjectionToken(NG_DEV_MODE ? 'BrowserModule Providers Marker' : ''); +export const TESTABILITY_PROVIDERS = [ + { + provide: TESTABILITY_GETTER, + useClass: BrowserGetTestability, + deps: [], + }, + { + provide: TESTABILITY, + useClass: Testability, + deps: [NgZone, TestabilityRegistry, TESTABILITY_GETTER] + }, + { + provide: Testability, // Also provide as `Testability` for backwards-compatibility. + useClass: Testability, + deps: [NgZone, TestabilityRegistry, TESTABILITY_GETTER] + } +]; + export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [ {provide: INJECTOR_SCOPE, useValue: 'root'}, {provide: ErrorHandler, useFactory: errorHandler, deps: []}, { @@ -123,7 +141,6 @@ export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [ {provide: RendererFactory2, useExisting: DomRendererFactory2}, {provide: SharedStylesHost, useExisting: DomSharedStylesHost}, {provide: DomSharedStylesHost, useClass: DomSharedStylesHost, deps: [DOCUMENT]}, - {provide: Testability, useClass: Testability, deps: [NgZone]}, {provide: EventManager, useClass: EventManager, deps: [EVENT_MANAGER_PLUGINS, NgZone]}, {provide: XhrFactory, useClass: BrowserXhr, deps: []}, NG_DEV_MODE ? {provide: BROWSER_MODULE_PROVIDERS_MARKER, useValue: true} : [] @@ -139,7 +156,10 @@ export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [ * @publicApi */ @NgModule({ - providers: BROWSER_MODULE_PROVIDERS, + providers: [ + ...BROWSER_MODULE_PROVIDERS, // + ...TESTABILITY_PROVIDERS + ], exports: [CommonModule, ApplicationModule], }) export class BrowserModule { diff --git a/packages/platform-browser/src/browser/testability.ts b/packages/platform-browser/src/browser/testability.ts index b92063f6852..edc1c1b94f6 100644 --- a/packages/platform-browser/src/browser/testability.ts +++ b/packages/platform-browser/src/browser/testability.ts @@ -7,13 +7,9 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {GetTestability, setTestabilityGetter, Testability, TestabilityRegistry, ɵglobal as global} from '@angular/core'; +import {GetTestability, Testability, TestabilityRegistry, ɵglobal as global} from '@angular/core'; export class BrowserGetTestability implements GetTestability { - static init() { - setTestabilityGetter(new BrowserGetTestability()); - } - addToWindow(registry: TestabilityRegistry): void { global['getAngularTestability'] = (elem: any, findInAncestors: boolean = true) => { const testability = registry.findTestabilityInTree(elem, findInAncestors); diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index 62c6b6ffcab..bcdfcbbe2ec 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -7,11 +7,10 @@ */ import {DOCUMENT, isPlatformBrowser, ɵgetDOM as getDOM} from '@angular/common'; -import {APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, InjectionToken, Injector, Input, LOCALE_ID, NgModule, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Type, VERSION} from '@angular/core'; +import {APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, InjectionToken, Injector, Input, LOCALE_ID, NgModule, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Testability, TestabilityRegistry, Type, VERSION} from '@angular/core'; import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref'; import {Console} from '@angular/core/src/console'; import {ComponentRef} from '@angular/core/src/linker/component_factory'; -import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; import {inject, TestBed} from '@angular/core/testing'; import {Log} from '@angular/core/testing/src/testing_internal'; import {BrowserModule} from '@angular/platform-browser'; diff --git a/packages/platform-server/src/server.ts b/packages/platform-server/src/server.ts index 6defa855418..d46673ea834 100644 --- a/packages/platform-server/src/server.ts +++ b/packages/platform-server/src/server.ts @@ -9,7 +9,7 @@ import {ɵAnimationEngine} from '@angular/animations/browser'; import {DOCUMENT, PlatformLocation, ViewportScroller, ɵgetDOM as getDOM, ɵNullViewportScroller as NullViewportScroller, ɵPLATFORM_SERVER_ID as PLATFORM_SERVER_ID} from '@angular/common'; import {HttpClientModule} from '@angular/common/http'; -import {createPlatformFactory, Injector, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, StaticProvider, Testability, ɵALLOW_MULTIPLE_PLATFORMS as ALLOW_MULTIPLE_PLATFORMS, ɵsetDocument} from '@angular/core'; +import {createPlatformFactory, Injector, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, StaticProvider, Testability, ɵALLOW_MULTIPLE_PLATFORMS as ALLOW_MULTIPLE_PLATFORMS, ɵsetDocument, ɵTESTABILITY as TESTABILITY} from '@angular/core'; import {BrowserModule, EVENT_MANAGER_PLUGINS, ɵSharedStylesHost as SharedStylesHost} from '@angular/platform-browser'; import {ɵplatformCoreDynamic as platformCoreDynamic} from '@angular/platform-browser-dynamic'; import {NoopAnimationsModule, ɵAnimationRendererFactory} from '@angular/platform-browser/animations'; @@ -23,10 +23,6 @@ import {ServerRendererFactory2} from './server_renderer'; import {ServerStylesHost} from './styles_host'; import {INITIAL_CONFIG, PlatformConfig} from './tokens'; -function notSupported(feature: string): Error { - throw new Error(`platform-server does not support '${feature}'.`); -} - export const INTERNAL_SERVER_PLATFORM_PROVIDERS: StaticProvider[] = [ {provide: DOCUMENT, useFactory: _document, deps: [Injector]}, {provide: PLATFORM_ID, useValue: PLATFORM_SERVER_ID}, @@ -74,7 +70,8 @@ export const SERVER_RENDER_PROVIDERS: Provider[] = [ providers: [ SERVER_RENDER_PROVIDERS, SERVER_HTTP_PROVIDERS, - {provide: Testability, useValue: null}, + {provide: Testability, useValue: null}, // Keep for backwards-compatibility. + {provide: TESTABILITY, useValue: null}, {provide: ViewportScroller, useClass: NullViewportScroller}, ], })