diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 65ba667766..edcb9b1800 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 149205, + "main": 146225, "polyfills": 43567 } } diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index fad9dd161f..422e7dcc74 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -291,4 +291,6 @@ export { export {createInjector as ɵcreateInjector} from './di/r3_injector'; +export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector'; + // clang-format on diff --git a/packages/core/src/di/index.ts b/packages/core/src/di/index.ts index 3c098f3306..6435213cad 100644 --- a/packages/core/src/di/index.ts +++ b/packages/core/src/di/index.ts @@ -17,8 +17,8 @@ export {InjectFlags} from './interface/injector'; export {ɵɵdefineInjectable, defineInjectable, ɵɵdefineInjector, InjectableType, InjectorType} from './interface/defs'; export {forwardRef, resolveForwardRef, ForwardRefFn} from './forward_ref'; export {Injectable, InjectableDecorator, InjectableProvider} from './injectable'; -export {INJECTOR, Injector} from './injector'; -export {ɵɵinject, inject} from './injector_compatibility'; +export {Injector} from './injector'; +export {ɵɵinject, inject, INJECTOR} from './injector_compatibility'; export {ReflectiveInjector} from './reflective_injector'; export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './interface/provider'; export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './reflective_provider'; diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index bc7ab65bde..bac0d1fe20 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -7,48 +7,29 @@ */ import {Type} from '../interface/type'; -import {getClosureSafeProperty} from '../util/property'; import {stringify} from '../util/stringify'; + import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {ɵɵinject} from './injector_compatibility'; +import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, formatError, ɵɵinject} from './injector_compatibility'; import {ɵɵdefineInjectable} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; +import {createInjector} from './r3_injector'; -export const SOURCE = '__source'; -const _THROW_IF_NOT_FOUND = new Object(); -export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; - -/** - * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. - * - * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a - * project. - * - * @publicApi - */ -export const INJECTOR = new InjectionToken( - 'INJECTOR', - -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. - ); - -export class NullInjector implements Injector { - get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any { - if (notFoundValue === _THROW_IF_NOT_FOUND) { - // Intentionally left behind: With dev tools open the debugger will stop here. There is no - // reason why correctly written application should cause this exception. - // TODO(misko): uncomment the next line once `ngDevMode` works with closure. - // if(ngDevMode) debugger; - const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); - error.name = 'NullInjectorError'; - throw error; - } - return notFoundValue; - } +export function INJECTOR_IMPL__PRE_R3__( + providers: StaticProvider[], parent: Injector | undefined, name: string) { + return new StaticInjector(providers, parent, name); } +export function INJECTOR_IMPL__POST_R3__( + providers: StaticProvider[], parent: Injector | undefined, name: string) { + return createInjector({name: name}, parent, providers, name); +} + +export const INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__; + /** * Concrete injectors implement this interface. * @@ -66,7 +47,7 @@ export class NullInjector implements Injector { * @publicApi */ export abstract class Injector { - static THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; + static THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND; static NULL: Injector = new NullInjector(); /** @@ -100,9 +81,9 @@ export abstract class Injector { options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string}, parent?: Injector): Injector { if (Array.isArray(options)) { - return new StaticInjector(options, parent); + return INJECTOR_IMPL(options, parent, ''); } else { - return new StaticInjector(options.providers, options.parent, options.name || null); + return INJECTOR_IMPL(options.providers, options.parent, options.name || ''); } } @@ -129,10 +110,7 @@ const CIRCULAR = IDENT; const MULTI_PROVIDER_FN = function(): any[] { return Array.prototype.slice.call(arguments); }; -export const USE_VALUE = - getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); -const NG_TOKEN_PATH = 'ngTokenPath'; -export const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; + const enum OptionFlags { Optional = 1 << 0, CheckSelf = 1 << 1, @@ -140,7 +118,6 @@ const enum OptionFlags { Default = CheckSelf | CheckParent } const NULL_INJECTOR = Injector.NULL; -const NEW_LINE = /\n/gm; const NO_NEW_LINE = 'ɵ'; export class StaticInjector implements Injector { @@ -377,38 +354,6 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] { return deps; } -export function catchInjectorError( - e: any, token: any, injectorErrorName: string, source: string | null): never { - const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; - if (token[SOURCE]) { - tokenPath.unshift(token[SOURCE]); - } - e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); - e[NG_TOKEN_PATH] = tokenPath; - e[NG_TEMP_TOKEN_PATH] = null; - throw e; -} - -function formatError( - text: string, obj: any, injectorErrorName: string, source: string | null = null): string { - text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; - let context = stringify(obj); - if (obj instanceof Array) { - context = obj.map(stringify).join(' -> '); - } else if (typeof obj === 'object') { - let parts = []; - for (let key in obj) { - if (obj.hasOwnProperty(key)) { - let value = obj[key]; - parts.push( - key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); - } - } - context = `{${parts.join(', ')}}`; - } - return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; -} - function staticError(text: string, obj: any): Error { return new Error(formatError(text, obj, 'StaticInjectorError')); } diff --git a/packages/core/src/di/injector_compatibility.ts b/packages/core/src/di/injector_compatibility.ts index 423289a5d2..83cc2638ab 100644 --- a/packages/core/src/di/injector_compatibility.ts +++ b/packages/core/src/di/injector_compatibility.ts @@ -7,6 +7,7 @@ */ import {Type} from '../interface/type'; +import {getClosureSafeProperty} from '../util/property'; import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; @@ -14,10 +15,36 @@ import {InjectionToken} from './injection_token'; import {Injector} from './injector'; import {getInjectableDef, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; +import {ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; +/** + * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. + * + * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a + * project. + * + * @publicApi + */ +export const INJECTOR = new InjectionToken( + 'INJECTOR', + -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. + ); + +const _THROW_IF_NOT_FOUND = new Object(); +export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; + +export const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; +const NG_TOKEN_PATH = 'ngTokenPath'; +const NEW_LINE = /\n/gm; +const NO_NEW_LINE = 'ɵ'; +export const SOURCE = '__source'; + +export const USE_VALUE = + getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); + /** * Current injector value used by `inject`. * - `undefined`: it is an error to call `inject` @@ -166,3 +193,52 @@ export function injectArgs(types: (Type| InjectionToken| any[])[]): an } return args; } + + +export class NullInjector implements Injector { + get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any { + if (notFoundValue === THROW_IF_NOT_FOUND) { + // Intentionally left behind: With dev tools open the debugger will stop here. There is no + // reason why correctly written application should cause this exception. + // TODO(misko): uncomment the next line once `ngDevMode` works with closure. + // if(ngDevMode) debugger; + const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); + error.name = 'NullInjectorError'; + throw error; + } + return notFoundValue; + } +} + + +export function catchInjectorError( + e: any, token: any, injectorErrorName: string, source: string | null): never { + const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; + if (token[SOURCE]) { + tokenPath.unshift(token[SOURCE]); + } + e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); + e[NG_TOKEN_PATH] = tokenPath; + e[NG_TEMP_TOKEN_PATH] = null; + throw e; +} + +export function formatError( + text: string, obj: any, injectorErrorName: string, source: string | null = null): string { + text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; + let context = stringify(obj); + if (obj instanceof Array) { + context = obj.map(stringify).join(' -> '); + } else if (typeof obj === 'object') { + let parts = []; + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + let value = obj[key]; + parts.push( + key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); + } + } + context = `{${parts.join(', ')}}`; + } + return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; +} diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 9532e23741..670c9902c5 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -8,12 +8,13 @@ import {OnDestroy} from '../interface/lifecycle_hooks'; import {Type} from '../interface/type'; +import {throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError} from '../render3/errors'; import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {INJECTOR, Injector, NG_TEMP_TOKEN_PATH, NullInjector, USE_VALUE, catchInjectorError} from './injector'; -import {injectArgs, setCurrentInjector, ɵɵinject} from './injector_compatibility'; +import {Injector} from './injector'; +import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, injectArgs, setCurrentInjector, ɵɵinject} from './injector_compatibility'; import {InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './interface/provider'; @@ -131,7 +132,7 @@ export class R3Injector { this.injectorDefTypes.forEach(defType => this.get(defType)); // Source name, used for debugging - this.source = source || (def instanceof Array ? null : stringify(def)); + this.source = source || (typeof def === 'object' ? null : stringify(def)); } /** @@ -157,7 +158,7 @@ export class R3Injector { } get( - token: Type|InjectionToken, notFoundValue: any = Injector.THROW_IF_NOT_FOUND, + token: Type|InjectionToken, notFoundValue: any = THROW_IF_NOT_FOUND, flags = InjectFlags.Default): T { this.assertNotDestroyed(); // Set the injection context. @@ -208,6 +209,12 @@ export class R3Injector { } } + toString() { + const tokens = [], records = this.records; + records.forEach((v, token) => tokens.push(stringify(token))); + return `R3Injector[${tokens.join(', ')}]`; + } + private assertNotDestroyed(): void { if (this._destroyed) { throw new Error('Injector has already been destroyed.'); @@ -242,7 +249,8 @@ export class R3Injector { (ngModule === undefined) ? (defOrWrappedDef as InjectorType) : ngModule; // Check for circular dependencies. - if (ngDevMode && parents.indexOf(defType) !== -1) { + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + if (parents.indexOf(defType) !== -1) { const defName = stringify(defType); throw new Error( `Circular dependency in DI detected for type ${defName}. Dependency path: ${parents.map(defType => stringify(defType)).join(' > ')} > ${defName}.`); @@ -278,7 +286,8 @@ export class R3Injector { if (def.imports != null && !isDuplicate) { // Before processing defType's imports, add it to the set of parents. This way, if it ends // up deeply importing itself, this can be detected. - ngDevMode && parents.push(defType); + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + parents.push(defType); // Add it to the set of dedups. This way we can detect multiple imports of the same module dedupStack.push(defType); @@ -287,7 +296,8 @@ export class R3Injector { def.imports, imported => this.processInjectorType(imported, parents, dedupStack)); } finally { // Remove it from the parents set when finished. - ngDevMode && parents.pop(); + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + parents.pop(); } } @@ -325,7 +335,7 @@ export class R3Injector { if (multiRecord) { // It has. Throw a nice error if if (multiRecord.multi === undefined) { - throw new Error(`Mixed multi-provider for ${token}.`); + throwMixedMultiProviderError(); } } else { multiRecord = makeRecord(undefined, NOT_YET, true); @@ -337,7 +347,7 @@ export class R3Injector { } else { const existing = this.records.get(token); if (existing && existing.multi !== undefined) { - throw new Error(`Mixed multi-provider for ${stringify(token)}`); + throwMixedMultiProviderError(); } } this.records.set(token, record); @@ -345,7 +355,7 @@ export class R3Injector { private hydrate(token: Type|InjectionToken, record: Record): T { if (record.value === CIRCULAR) { - throw new Error(`Cannot instantiate cyclic dependency! ${stringify(token)}`); + throwCyclicDependencyError(stringify(token)); } else if (record.value === NOT_YET) { record.value = CIRCULAR; record.value = record.factory !(); @@ -421,14 +431,7 @@ export function providerToFactory( provider && ((provider as StaticClassProvider | ClassProvider).useClass || provider.provide)); if (!classRef) { - let ngModuleDetail = ''; - if (ngModuleType && providers) { - const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); - ngModuleDetail = - ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`; - } - throw new Error( - `Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail); + throwInvalidProviderError(ngModuleType, providers, provider); } if (hasDeps(provider)) { factory = () => new (classRef)(...injectArgs(provider.deps)); diff --git a/packages/core/src/di/reflective_injector.ts b/packages/core/src/di/reflective_injector.ts index 8ce87b226f..20ba0c39cf 100644 --- a/packages/core/src/di/reflective_injector.ts +++ b/packages/core/src/di/reflective_injector.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, THROW_IF_NOT_FOUND} from './injector'; +import {Injector} from './injector'; +import {THROW_IF_NOT_FOUND} from './injector_compatibility'; import {Provider} from './interface/provider'; import {Self, SkipSelf} from './metadata'; import {cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError} from './reflective_errors'; diff --git a/packages/core/src/render3/errors.ts b/packages/core/src/render3/errors.ts index c390767208..f0dff261cf 100644 --- a/packages/core/src/render3/errors.ts +++ b/packages/core/src/render3/errors.ts @@ -6,8 +6,12 @@ * 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 {InjectorType} from '../di/interface/defs'; +import {stringify} from '../util/stringify'; + import {TNode} from './interfaces/node'; + /** Called when directives inject each other (creating a circular dependency) */ export function throwCyclicDependencyError(token: any): never { throw new Error(`Cannot instantiate cyclic dependency! ${token}`); @@ -31,3 +35,20 @@ export function throwErrorIfNoChangesMode( // TODO: include debug context throw new Error(msg); } + +export function throwMixedMultiProviderError() { + throw new Error(`Cannot mix multi providers and regular providers`); +} + +export function throwInvalidProviderError( + ngModuleType?: InjectorType, providers?: any[], provider?: any) { + let ngModuleDetail = ''; + if (ngModuleType && providers) { + const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); + ngModuleDetail = + ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`; + } + + throw new Error( + `Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail); +} diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index d445ded545..889548a86b 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {INJECTOR, Injector} from '../di/injector'; +import {Injector} from '../di/injector'; +import {INJECTOR} from '../di/injector_compatibility'; import {InjectFlags} from '../di/interface/injector'; import {StaticProvider} from '../di/interface/provider'; import {R3Injector, createInjector} from '../di/r3_injector'; diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index 37fed07345..6d064e91af 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -7,8 +7,8 @@ */ import {resolveForwardRef} from '../di/forward_ref'; -import {INJECTOR, Injector} from '../di/injector'; -import {setCurrentInjector} from '../di/injector_compatibility'; +import {Injector} from '../di/injector'; +import {INJECTOR, setCurrentInjector} from '../di/injector_compatibility'; import {getInjectableDef, ɵɵInjectableDef} from '../di/interface/defs'; import {APP_ROOT} from '../di/scope'; import {NgModuleRef} from '../linker/ng_module_factory'; diff --git a/packages/core/src/view/util.ts b/packages/core/src/view/util.ts index aaeec68753..5e88b2124b 100644 --- a/packages/core/src/view/util.ts +++ b/packages/core/src/view/util.ts @@ -7,7 +7,7 @@ */ import {WrappedValue, devModeEqual} from '../change_detection/change_detection'; -import {SOURCE} from '../di/injector'; +import {SOURCE} from '../di/injector_compatibility'; import {ViewEncapsulation} from '../metadata/view'; import {RendererType2} from '../render/api'; import {looseIdentical} from '../util/comparison'; diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index 62887f7ba6..057315aa95 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -5,21 +5,12 @@ { "name": "CIRCULAR" }, - { - "name": "CIRCULAR" - }, - { - "name": "EMPTY" - }, { "name": "EMPTY_ARRAY" }, { "name": "EmptyErrorImpl" }, - { - "name": "IDENT" - }, { "name": "INJECTOR" }, @@ -32,12 +23,6 @@ { "name": "InjectionToken" }, - { - "name": "Injector" - }, - { - "name": "MULTI_PROVIDER_FN" - }, { "name": "NEW_LINE" }, @@ -62,9 +47,6 @@ { "name": "NULL_INJECTOR" }, - { - "name": "NULL_INJECTOR" - }, { "name": "NullInjector" }, @@ -93,7 +75,7 @@ "name": "SkipSelf" }, { - "name": "StaticInjector" + "name": "THROW_IF_NOT_FOUND" }, { "name": "USE_VALUE" @@ -101,9 +83,6 @@ { "name": "UnsubscriptionErrorImpl" }, - { - "name": "_THROW_IF_NOT_FOUND" - }, { "name": "__forward_ref__" }, @@ -122,9 +101,6 @@ { "name": "catchInjectorError" }, - { - "name": "computeDeps" - }, { "name": "couldBeInjectableType" }, @@ -194,38 +170,29 @@ { "name": "makeRecord" }, - { - "name": "multiProviderMixError" - }, { "name": "providerToFactory" }, { "name": "providerToRecord" }, - { - "name": "recursivelyProcessProviders" - }, { "name": "resolveForwardRef" }, - { - "name": "resolveProvider" - }, - { - "name": "resolveToken" - }, { "name": "setCurrentInjector" }, - { - "name": "staticError" - }, { "name": "stringify" }, { - "name": "tryResolveToken" + "name": "throwCyclicDependencyError" + }, + { + "name": "throwInvalidProviderError" + }, + { + "name": "throwMixedMultiProviderError" }, { "name": "ɵɵdefineInjectable" diff --git a/packages/core/test/di/static_injector_spec.ts b/packages/core/test/di/static_injector_spec.ts index 778cc96ecf..6d4920006e 100644 --- a/packages/core/test/di/static_injector_spec.ts +++ b/packages/core/test/di/static_injector_spec.ts @@ -8,6 +8,7 @@ import {Inject, InjectionToken, Injector, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {ivyEnabled, modifiedInIvy} from '@angular/private/testing'; import {stringify} from '../../src/util/stringify'; @@ -86,7 +87,7 @@ function factoryFn(a: any){} {provide: 'provider10', useValue: 1} ]; - describe(`StaticInjector`, () => { + modifiedInIvy('Ivy uses R3Injector').describe(`StaticInjector`, () => { it('should instantiate a class without dependencies', () => { const injector = Injector.create([Engine.PROVIDER]); @@ -413,9 +414,11 @@ function factoryFn(a: any){} [{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}], parent); + const injectorName = ivyEnabled ? `R3Injector` : `StaticInjector`; + expect(() => child.get(Car)) .toThrowError( - `StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)}]: \n` + + `${injectorName}Error[${stringify(Car)} -> ${stringify(Engine)}]: \n` + ' NullInjectorError: No provider for Engine!'); }); }); @@ -472,8 +475,11 @@ function factoryFn(a: any){} describe('displayName', () => { it('should work', () => { + const ivyError = `R3Injector[Engine, BrokenEngine, InjectionToken INJECTOR]`; + const viewEngineError = + `StaticInjector[Injector, InjectionToken INJECTOR, Engine, BrokenEngine]`; expect(Injector.create([Engine.PROVIDER, {provide: BrokenEngine, useValue: null}]).toString()) - .toEqual('StaticInjector[Injector, InjectionToken INJECTOR, Engine, BrokenEngine]'); + .toEqual(ivyEnabled ? ivyError : viewEngineError); }); }); } diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index 88b85f4441..ec81d5c0ed 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -8,7 +8,8 @@ import {NgModuleRef} from '@angular/core'; import {InjectFlags, inject} from '@angular/core/src/di'; -import {INJECTOR, Injector} from '@angular/core/src/di/injector'; +import {Injector} from '@angular/core/src/di/injector'; +import {INJECTOR} from '@angular/core/src/di/injector_compatibility'; import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs'; import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view'; import {moduleDef} from '@angular/core/src/view/ng_module'; diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index ce478f8782..3a057c3a74 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -232,10 +232,7 @@ function bootstrap( ]).then(null, (e: Error) => { let errorMsg: string; if (ivyEnabled) { - errorMsg = `R3InjectorError(TestModule)[IDontExist]: \n` + - ' StaticInjectorError(TestModule)[IDontExist]: \n' + - ' StaticInjectorError(Platform: core)[IDontExist]: \n' + - ' NullInjectorError: No provider for IDontExist!'; + errorMsg = `R3InjectorError(TestModule)[IDontExist -> IDontExist -> IDontExist]: \n`; } else { errorMsg = `StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: \n` + ' StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: \n' +