diff --git a/aio/tests/e2e/src/api-pages.e2e-spec.ts b/aio/tests/e2e/src/api-pages.e2e-spec.ts index 2dfb2331b17665..ca4a1a5ac58d82 100644 --- a/aio/tests/e2e/src/api-pages.e2e-spec.ts +++ b/aio/tests/e2e/src/api-pages.e2e-spec.ts @@ -76,11 +76,11 @@ describe('Api pages', () => { it('should show all overloads of interface methods', async () => { await page.navigateTo('api/core/testing/TestBedStatic'); - expect(await (await page.getInstanceMethodOverloads('inject')).length).toEqual(2); + expect(await (await page.getInstanceMethodOverloads('inject')).length).toEqual(3); }); it('should show all overloads of pseudo-class methods', async () => { await page.navigateTo('api/core/testing/TestBed'); - expect(await (await page.getInstanceMethodOverloads('inject')).length).toEqual(2); + expect(await (await page.getInstanceMethodOverloads('inject')).length).toEqual(3); }); }); diff --git a/goldens/public-api/core/testing/index.md b/goldens/public-api/core/testing/index.md index c87ce437d2ab6d..46e5eb15829686 100644 --- a/goldens/public-api/core/testing/index.md +++ b/goldens/public-api/core/testing/index.md @@ -12,6 +12,7 @@ import { Directive } from '@angular/core'; import { ElementRef } from '@angular/core'; import { InjectFlags } from '@angular/core'; import { InjectionToken } from '@angular/core'; +import { InjectOptions } from '@angular/core'; import { NgModule } from '@angular/core'; import { NgZone } from '@angular/core'; import { Pipe } from '@angular/core'; @@ -115,8 +116,12 @@ export interface TestBed { get(token: any, notFoundValue?: any): any; initTestEnvironment(ngModule: Type | Type[], platform: PlatformRef, options?: TestEnvironmentOptions): void; // (undocumented) - inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; // (undocumented) + inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T | null; + // @deprecated (undocumented) + inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + // @deprecated (undocumented) inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T | null; // (undocumented) ngModule: Type | Type[]; @@ -172,8 +177,12 @@ export interface TestBedStatic { get(token: any, notFoundValue?: any): any; initTestEnvironment(ngModule: Type | Type[], platform: PlatformRef, options?: TestEnvironmentOptions): TestBed; // (undocumented) - inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; // (undocumented) + inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T | null; + // @deprecated (undocumented) + inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + // @deprecated (undocumented) inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T | null; // (undocumented) overrideComponent(component: Type, override: MetadataOverride): TestBedStatic; diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 8365cc408f3862..ed3cbd51addacc 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -12,7 +12,7 @@ export {defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffe export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants'; export {Console as ɵConsole} from './console'; export {getDebugNodeR2 as ɵgetDebugNodeR2} from './debug/debug_node'; -export {setCurrentInjector as ɵsetCurrentInjector} from './di/injector_compatibility'; +export {convertToBitFlags as ɵconvertToBitFlags, setCurrentInjector as ɵsetCurrentInjector} from './di/injector_compatibility'; export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDeclaration, ɵɵInjectorDef} from './di/interface/defs'; export {INJECTOR_SCOPE as ɵINJECTOR_SCOPE} from './di/scope'; export {RuntimeError as ɵRuntimeError} from './errors'; diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index 26a789029c2a6d..14c6ee1dcf6169 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -659,6 +659,9 @@ { "name": "containsElement" }, + { + "name": "convertToBitFlags" + }, { "name": "convertToMap" }, diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 93c02d8d9e0560..b56bb2ad6f186c 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -467,6 +467,9 @@ { "name": "connectableObservableDescriptor" }, + { + "name": "convertToBitFlags" + }, { "name": "createElementNode" }, 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 7c97e677389630..671d09fdf94f9e 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -686,6 +686,9 @@ { "name": "controlPath" }, + { + "name": "convertToBitFlags" + }, { "name": "createDirectivesInstances" }, 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 15b19078b0b9c7..56b2213e4ae521 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 @@ -659,6 +659,9 @@ { "name": "controlPath" }, + { + "name": "convertToBitFlags" + }, { "name": "createDirectivesInstances" }, diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index cc346cf1c75205..3d4d087c469786 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -329,6 +329,9 @@ { "name": "connectableObservableDescriptor" }, + { + "name": "convertToBitFlags" + }, { "name": "createElementRef" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index e6774208e8fa16..5d85fb83b9b906 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -920,6 +920,9 @@ { "name": "containsTree" }, + { + "name": "convertToBitFlags" + }, { "name": "convertToParamMap" }, 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 ee82b8c40d1859..6d765fedf3bf1a 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -398,6 +398,9 @@ { "name": "connectableObservableDescriptor" }, + { + "name": "convertToBitFlags" + }, { "name": "createElementRef" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 538e7efc6960b8..5b12cf5d0f68e0 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -569,6 +569,9 @@ { "name": "connectableObservableDescriptor" }, + { + "name": "convertToBitFlags" + }, { "name": "createDirectivesInstances" }, diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 219938f484bba5..cb94f55b9e9f40 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {APP_INITIALIZER, ChangeDetectorRef, Compiler, Component, Directive, ElementRef, ErrorHandler, getNgModuleById, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵelementEnd as elementEnd, ɵɵelementStart as elementStart, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; +import {APP_INITIALIZER, ChangeDetectorRef, Compiler, Component, Directive, ElementRef, ErrorHandler, getNgModuleById, Inject, Injectable, InjectFlags, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵelementEnd as elementEnd, ɵɵelementStart as elementStart, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; import {getTestBed, TestBed} from '@angular/core/testing/src/test_bed'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -1855,6 +1855,33 @@ describe('TestBed', () => { fixture.detectChanges(); expect(fixture!.nativeElement.textContent).toContain('changed'); }); + + describe('TestBed.inject', () => { + describe('injection flags', () => { + it('should be able to optionally inject a topken', () => { + const TOKEN = new InjectionToken('TOKEN'); + + expect(TestBed.inject(TOKEN, undefined, {optional: true})).toBeNull(); + expect(TestBed.inject(TOKEN, undefined, InjectFlags.Optional)).toBeNull(); + + expect(TestBed.inject(TOKEN, undefined, {optional: true})).toBeNull(); + expect(TestBed.inject(TOKEN, undefined, InjectFlags.Optional)).toBeNull(); + }); + + it('should be able to use skipSelf injection', () => { + const TOKEN = new InjectionToken('TOKEN'); + TestBed.configureTestingModule({ + providers: [{provide: TOKEN, useValue: 'from TestBed'}], + }); + + expect(TestBed.inject(TOKEN)).toBe('from TestBed'); + + expect(TestBed.inject(TOKEN, undefined, {skipSelf: true, optional: true})).toBeNull(); + expect(TestBed.inject(TOKEN, undefined, InjectFlags.SkipSelf | InjectFlags.Optional)) + .toBeNull(); + }); + }); + }); }); diff --git a/packages/core/testing/src/r3_test_bed.ts b/packages/core/testing/src/r3_test_bed.ts index 0e0629c162c7f1..c5b50f2808d095 100644 --- a/packages/core/testing/src/r3_test_bed.ts +++ b/packages/core/testing/src/r3_test_bed.ts @@ -16,6 +16,7 @@ import { Directive, InjectFlags, InjectionToken, + InjectOptions, Injector, NgModule, NgZone, @@ -23,6 +24,7 @@ import { PlatformRef, ProviderToken, Type, + ɵconvertToBitFlags as convertToBitFlags, ɵflushModuleScopingQueueAsMuchAsPossible as flushModuleScopingQueueAsMuchAsPossible, ɵgetUnknownElementStrictMode as getUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode as getUnknownPropertyStrictMode, @@ -210,10 +212,16 @@ export class TestBedRender3 implements TestBed { return TestBedRender3 as any as TestBedStatic; } + static inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; + static inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions&{ + optional?: false + }): T; + static inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T|null; static inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; static inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T|null; - static inject(token: ProviderToken, notFoundValue?: T|null, flags?: InjectFlags): T|null { - return _getTestBedRender3().inject(token, notFoundValue, flags); + static inject( + token: ProviderToken, notFoundValue?: T|null, flags?: InjectFlags|InjectOptions): T|null { + return _getTestBedRender3().inject(token, notFoundValue, convertToBitFlags(flags)); } /** @deprecated from v9.0.0 use TestBed.inject */ @@ -376,12 +384,18 @@ export class TestBedRender3 implements TestBed { return this.compiler.compileComponents(); } + inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; + inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T|null; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T|null; - inject(token: ProviderToken, notFoundValue?: T|null, flags?: InjectFlags): T|null { + inject(token: ProviderToken, notFoundValue?: T|null, flags?: InjectFlags|InjectOptions): T + |null { if (token as unknown === TestBedRender3) { return this as any; } + flags = convertToBitFlags(flags); const UNDEFINED = {} as unknown as T; const result = this.testModuleRef.injector.get(token, UNDEFINED, flags); return result === UNDEFINED ? this.compiler.injector.get(token, notFoundValue, flags) as any : diff --git a/packages/core/testing/src/test_bed.ts b/packages/core/testing/src/test_bed.ts index 8e673972bebf59..181ee4adb43a70 100644 --- a/packages/core/testing/src/test_bed.ts +++ b/packages/core/testing/src/test_bed.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, InjectFlags, NgModule, Pipe, PlatformRef, ProviderToken, Type} from '@angular/core'; +import {Component, Directive, InjectFlags, InjectOptions, NgModule, Pipe, PlatformRef, ProviderToken, Type} from '@angular/core'; import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; @@ -49,7 +49,11 @@ export interface TestBed { compileComponents(): Promise; + inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; + inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T|null; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T|null; /** @deprecated from v9.0.0 use TestBed.inject */ diff --git a/packages/core/testing/src/test_bed_common.ts b/packages/core/testing/src/test_bed_common.ts index 3ed811378769b0..23e7a37f097ea4 100644 --- a/packages/core/testing/src/test_bed_common.ts +++ b/packages/core/testing/src/test_bed_common.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, InjectFlags, InjectionToken, NgModule, Pipe, PlatformRef, ProviderToken, SchemaMetadata, Type} from '@angular/core'; +import {Component, Directive, InjectFlags, InjectionToken, InjectOptions, NgModule, Pipe, PlatformRef, ProviderToken, SchemaMetadata, Type} from '@angular/core'; import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; @@ -186,7 +186,11 @@ export interface TestBedStatic { deps?: any[], }): TestBedStatic; + inject(token: ProviderToken, notFoundValue?: T, options?: InjectOptions): T; + inject(token: ProviderToken, notFoundValue: null, options?: InjectOptions): T|null; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue?: T, flags?: InjectFlags): T; + /** @deprecated use object-based flags (`InjectOptions`) instead. */ inject(token: ProviderToken, notFoundValue: null, flags?: InjectFlags): T|null; /** @deprecated from v9.0.0 use TestBed.inject */