Skip to content

Commit

Permalink
feat(core): support object-based DI flags in TestBed.inject()
Browse files Browse the repository at this point in the history
This commit applies the changes similar to the ones performed for the `inject()` function in df246bb.

The `TestBed.inject` function is updated to use previously added object-based API for options: now the flags argument supports passing an object which configures injection flags.

DEPRECATED:

The bit field signature of `TestBed.inject()` has been deprecated, in favor of the new options object.
  • Loading branch information
AndrewKushnir committed Jul 10, 2022
1 parent bb4c0da commit 3553e1e
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 14 deletions.
4 changes: 2 additions & 2 deletions aio/tests/e2e/src/api-pages.e2e-spec.ts
Expand Up @@ -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);
});
});
13 changes: 11 additions & 2 deletions goldens/public-api/core/testing/index.md
Expand Up @@ -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';
Expand Down Expand Up @@ -115,8 +116,12 @@ export interface TestBed {
get(token: any, notFoundValue?: any): any;
initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, options?: TestEnvironmentOptions): void;
// (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
// (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T | null;
// @deprecated (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
// @deprecated (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T | null;
// (undocumented)
ngModule: Type<any> | Type<any>[];
Expand Down Expand Up @@ -172,8 +177,12 @@ export interface TestBedStatic {
get(token: any, notFoundValue?: any): any;
initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, options?: TestEnvironmentOptions): TestBed;
// (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
// (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T | null;
// @deprecated (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
// @deprecated (undocumented)
inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T | null;
// (undocumented)
overrideComponent(component: Type<any>, override: MetadataOverride<Component>): TestBedStatic;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/core_private_export.ts
Expand Up @@ -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';
Expand Down
29 changes: 28 additions & 1 deletion packages/core/test/test_bed_spec.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -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<string>('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<string>('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();
});
});
});
});


Expand Down
20 changes: 17 additions & 3 deletions packages/core/testing/src/r3_test_bed.ts
Expand Up @@ -16,13 +16,15 @@ import {
Directive,
InjectFlags,
InjectionToken,
InjectOptions,
Injector,
NgModule,
NgZone,
Pipe,
PlatformRef,
ProviderToken,
Type,
ɵconvertToBitFlags as convertToBitFlags,
ɵflushModuleScopingQueueAsMuchAsPossible as flushModuleScopingQueueAsMuchAsPossible,
ɵgetUnknownElementStrictMode as getUnknownElementStrictMode,
ɵgetUnknownPropertyStrictMode as getUnknownPropertyStrictMode,
Expand Down Expand Up @@ -210,10 +212,16 @@ export class TestBedRender3 implements TestBed {
return TestBedRender3 as any as TestBedStatic;
}

static inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
static inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions&{
optional?: false
}): T;
static inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T|null;
static inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
static inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T|null;
static inject<T>(token: ProviderToken<T>, notFoundValue?: T|null, flags?: InjectFlags): T|null {
return _getTestBedRender3().inject(token, notFoundValue, flags);
static inject<T>(
token: ProviderToken<T>, notFoundValue?: T|null, flags?: InjectFlags|InjectOptions): T|null {
return _getTestBedRender3().inject(token, notFoundValue, convertToBitFlags(flags));
}

/** @deprecated from v9.0.0 use TestBed.inject */
Expand Down Expand Up @@ -376,12 +384,18 @@ export class TestBedRender3 implements TestBed {
return this.compiler.compileComponents();
}

inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T|null;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T|null;
inject<T>(token: ProviderToken<T>, notFoundValue?: T|null, flags?: InjectFlags): T|null {
inject<T>(token: ProviderToken<T>, 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 :
Expand Down
6 changes: 5 additions & 1 deletion packages/core/testing/src/test_bed.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -49,7 +49,11 @@ export interface TestBed {

compileComponents(): Promise<any>;

inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T|null;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T|null;

/** @deprecated from v9.0.0 use TestBed.inject */
Expand Down
6 changes: 5 additions & 1 deletion packages/core/testing/src/test_bed_common.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -186,7 +186,11 @@ export interface TestBedStatic {
deps?: any[],
}): TestBedStatic;

inject<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
inject<T>(token: ProviderToken<T>, notFoundValue: null, options?: InjectOptions): T|null;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
/** @deprecated use object-based flags (`InjectOptions`) instead. */
inject<T>(token: ProviderToken<T>, notFoundValue: null, flags?: InjectFlags): T|null;

/** @deprecated from v9.0.0 use TestBed.inject */
Expand Down
6 changes: 3 additions & 3 deletions packages/examples/core/di/ts/injector_spec.ts
Expand Up @@ -11,16 +11,16 @@ import {inject, InjectFlags, InjectionToken, Injector, ProviderToken, ɵsetCurre
class MockRootScopeInjector implements Injector {
constructor(readonly parent: Injector) {}

get<T>(token: ProviderToken<T>, defaultValue?: any, flags: InjectFlags = InjectFlags.Default): T {
get<T>(token: ProviderToken<T>, defaultValue?: any): T {
if ((token as any).ɵprov && (token as any).ɵprov.providedIn === 'root') {
const old = setCurrentInjector(this);
const old = setCurrentInjector(this as Injector);
try {
return (token as any).ɵprov.factory();
} finally {
setCurrentInjector(old);
}
}
return this.parent.get(token, defaultValue, flags);
return this.parent.get(token, defaultValue);
}
}

Expand Down

0 comments on commit 3553e1e

Please sign in to comment.