fix(upgrade): improve downgrading-related error messages (#26217)
Make the error messages thrown when instantiating downgraded components, injectables and modules more descriptive and actionable, also taking into account incorrect use of the `downgradedModule` field. PR Close #26217
This commit is contained in:
parent
93837e9545
commit
7dbc103cbe
@ -103,11 +103,15 @@ const appModule =
|
|||||||
})
|
})
|
||||||
.directive('ng2A', downgradeComponent({
|
.directive('ng2A', downgradeComponent({
|
||||||
component: Ng2AComponent,
|
component: Ng2AComponent,
|
||||||
|
// Since there are more than one downgraded Angular module,
|
||||||
|
// specify which module this component belongs to.
|
||||||
downgradedModule: downgradedNg2AModule,
|
downgradedModule: downgradedNg2AModule,
|
||||||
propagateDigest: false,
|
propagateDigest: false,
|
||||||
}))
|
}))
|
||||||
.directive('ng2B', downgradeComponent({
|
.directive('ng2B', downgradeComponent({
|
||||||
component: Ng2BComponent,
|
component: Ng2BComponent,
|
||||||
|
// Since there are more than one downgraded Angular module,
|
||||||
|
// specify which module this component belongs to.
|
||||||
downgradedModule: downgradedNg2BModule,
|
downgradedModule: downgradedNg2BModule,
|
||||||
propagateDigest: false,
|
propagateDigest: false,
|
||||||
}))
|
}))
|
||||||
|
@ -23,10 +23,12 @@ export const $TEMPLATE_REQUEST = '$templateRequest';
|
|||||||
export const $$TESTABILITY = '$$testability';
|
export const $$TESTABILITY = '$$testability';
|
||||||
|
|
||||||
export const COMPILER_KEY = '$$angularCompiler';
|
export const COMPILER_KEY = '$$angularCompiler';
|
||||||
|
export const DOWNGRADED_MODULE_COUNT_KEY = '$$angularDowngradedModuleCount';
|
||||||
export const GROUP_PROJECTABLE_NODES_KEY = '$$angularGroupProjectableNodes';
|
export const GROUP_PROJECTABLE_NODES_KEY = '$$angularGroupProjectableNodes';
|
||||||
export const INJECTOR_KEY = '$$angularInjector';
|
export const INJECTOR_KEY = '$$angularInjector';
|
||||||
export const LAZY_MODULE_REF = '$$angularLazyModuleRef';
|
export const LAZY_MODULE_REF = '$$angularLazyModuleRef';
|
||||||
export const NG_ZONE_KEY = '$$angularNgZone';
|
export const NG_ZONE_KEY = '$$angularNgZone';
|
||||||
|
export const UPGRADE_APP_TYPE_KEY = '$$angularUpgradeAppType';
|
||||||
|
|
||||||
export const REQUIRE_INJECTOR = '?^^' + INJECTOR_KEY;
|
export const REQUIRE_INJECTOR = '?^^' + INJECTOR_KEY;
|
||||||
export const REQUIRE_NG_MODEL = '?ngModel';
|
export const REQUIRE_NG_MODEL = '?ngModel';
|
||||||
|
@ -11,7 +11,7 @@ import {ComponentFactory, ComponentFactoryResolver, Injector, NgZone, Type} from
|
|||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
import {$COMPILE, $INJECTOR, $PARSE, INJECTOR_KEY, LAZY_MODULE_REF, REQUIRE_INJECTOR, REQUIRE_NG_MODEL} from './constants';
|
import {$COMPILE, $INJECTOR, $PARSE, INJECTOR_KEY, LAZY_MODULE_REF, REQUIRE_INJECTOR, REQUIRE_NG_MODEL} from './constants';
|
||||||
import {DowngradeComponentAdapter} from './downgrade_component_adapter';
|
import {DowngradeComponentAdapter} from './downgrade_component_adapter';
|
||||||
import {LazyModuleRef, controllerKey, getComponentName, isFunction} from './util';
|
import {LazyModuleRef, controllerKey, getTypeName, isFunction, validateInjectionKey} from './util';
|
||||||
|
|
||||||
|
|
||||||
interface Thenable<T> {
|
interface Thenable<T> {
|
||||||
@ -104,6 +104,10 @@ export function downgradeComponent(info: {
|
|||||||
if (!parentInjector) {
|
if (!parentInjector) {
|
||||||
const downgradedModule = info.downgradedModule || '';
|
const downgradedModule = info.downgradedModule || '';
|
||||||
const lazyModuleRefKey = `${LAZY_MODULE_REF}${downgradedModule}`;
|
const lazyModuleRefKey = `${LAZY_MODULE_REF}${downgradedModule}`;
|
||||||
|
const attemptedAction = `instantiating component '${getTypeName(info.component)}'`;
|
||||||
|
|
||||||
|
validateInjectionKey($injector, downgradedModule, lazyModuleRefKey, attemptedAction);
|
||||||
|
|
||||||
const lazyModuleRef = $injector.get(lazyModuleRefKey) as LazyModuleRef;
|
const lazyModuleRef = $injector.get(lazyModuleRefKey) as LazyModuleRef;
|
||||||
needsNgZone = lazyModuleRef.needsNgZone;
|
needsNgZone = lazyModuleRef.needsNgZone;
|
||||||
parentInjector = lazyModuleRef.injector || lazyModuleRef.promise as Promise<Injector>;
|
parentInjector = lazyModuleRef.injector || lazyModuleRef.promise as Promise<Injector>;
|
||||||
@ -116,7 +120,7 @@ export function downgradeComponent(info: {
|
|||||||
componentFactoryResolver.resolveComponentFactory(info.component) !;
|
componentFactoryResolver.resolveComponentFactory(info.component) !;
|
||||||
|
|
||||||
if (!componentFactory) {
|
if (!componentFactory) {
|
||||||
throw new Error('Expecting ComponentFactory for: ' + getComponentName(info.component));
|
throw new Error(`Expecting ComponentFactory for: ${getTypeName(info.component)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const injectorPromise = new ParentInjectorPromise(element);
|
const injectorPromise = new ParentInjectorPromise(element);
|
||||||
|
@ -11,7 +11,7 @@ import {ApplicationRef, ChangeDetectorRef, ComponentFactory, ComponentRef, Event
|
|||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
import {PropertyBinding} from './component_info';
|
import {PropertyBinding} from './component_info';
|
||||||
import {$SCOPE} from './constants';
|
import {$SCOPE} from './constants';
|
||||||
import {getComponentName, hookupNgModel, strictEquals} from './util';
|
import {getTypeName, hookupNgModel, strictEquals} from './util';
|
||||||
|
|
||||||
const INITIAL_VALUE = {
|
const INITIAL_VALUE = {
|
||||||
__UNINITIALIZED__: true
|
__UNINITIALIZED__: true
|
||||||
@ -208,7 +208,7 @@ export class DowngradeComponentAdapter {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Missing emitter '${output.prop}' on component '${getComponentName(this.componentFactory.componentType)}'!`);
|
`Missing emitter '${output.prop}' on component '${getTypeName(this.componentFactory.componentType)}'!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injector} from '@angular/core';
|
import {Injector} from '@angular/core';
|
||||||
import {INJECTOR_KEY} from './constants';
|
import * as angular from './angular1';
|
||||||
|
import {$INJECTOR, INJECTOR_KEY} from './constants';
|
||||||
|
import {getTypeName, isFunction, validateInjectionKey} from './util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
* @description
|
||||||
@ -70,8 +72,17 @@ import {INJECTOR_KEY} from './constants';
|
|||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export function downgradeInjectable(token: any, downgradedModule: string = ''): Function {
|
export function downgradeInjectable(token: any, downgradedModule: string = ''): Function {
|
||||||
const factory = function(i: Injector) { return i.get(token); };
|
const factory = function($injector: angular.IInjectorService) {
|
||||||
(factory as any)['$inject'] = [`${INJECTOR_KEY}${downgradedModule}`];
|
const injectorKey = `${INJECTOR_KEY}${downgradedModule}`;
|
||||||
|
const injectableName = isFunction(token) ? getTypeName(token) : String(token);
|
||||||
|
const attemptedAction = `instantiating injectable '${injectableName}'`;
|
||||||
|
|
||||||
|
validateInjectionKey($injector, downgradedModule, injectorKey, attemptedAction);
|
||||||
|
|
||||||
|
const injector: Injector = $injector.get(injectorKey);
|
||||||
|
return injector.get(token);
|
||||||
|
};
|
||||||
|
(factory as any)['$inject'] = [$INJECTOR];
|
||||||
|
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import {Injector, Type} from '@angular/core';
|
import {Injector, Type} from '@angular/core';
|
||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
|
import {DOWNGRADED_MODULE_COUNT_KEY, UPGRADE_APP_TYPE_KEY} from './constants';
|
||||||
|
|
||||||
const DIRECTIVE_PREFIX_REGEXP = /^(?:x|data)[:\-_]/i;
|
const DIRECTIVE_PREFIX_REGEXP = /^(?:x|data)[:\-_]/i;
|
||||||
const DIRECTIVE_SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
|
const DIRECTIVE_SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
|
||||||
@ -32,15 +33,66 @@ export function directiveNormalize(name: string): string {
|
|||||||
.replace(DIRECTIVE_SPECIAL_CHARS_REGEXP, (_, letter) => letter.toUpperCase());
|
.replace(DIRECTIVE_SPECIAL_CHARS_REGEXP, (_, letter) => letter.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getComponentName(component: Type<any>): string {
|
export function getTypeName(type: Type<any>): string {
|
||||||
// Return the name of the component or the first line of its stringified version.
|
// Return the name of the type or the first line of its stringified version.
|
||||||
return (component as any).overriddenName || component.name || component.toString().split('\n')[0];
|
return (type as any).overriddenName || type.name || type.toString().split('\n')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDowngradedModuleCount($injector: angular.IInjectorService): number {
|
||||||
|
return $injector.has(DOWNGRADED_MODULE_COUNT_KEY) ? $injector.get(DOWNGRADED_MODULE_COUNT_KEY) :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUpgradeAppType($injector: angular.IInjectorService): UpgradeAppType {
|
||||||
|
return $injector.has(UPGRADE_APP_TYPE_KEY) ? $injector.get(UPGRADE_APP_TYPE_KEY) :
|
||||||
|
UpgradeAppType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFunction(value: any): value is Function {
|
export function isFunction(value: any): value is Function {
|
||||||
return typeof value === 'function';
|
return typeof value === 'function';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function validateInjectionKey(
|
||||||
|
$injector: angular.IInjectorService, downgradedModule: string, injectionKey: string,
|
||||||
|
attemptedAction: string): void {
|
||||||
|
const upgradeAppType = getUpgradeAppType($injector);
|
||||||
|
const downgradedModuleCount = getDowngradedModuleCount($injector);
|
||||||
|
|
||||||
|
// Check for common errors.
|
||||||
|
switch (upgradeAppType) {
|
||||||
|
case UpgradeAppType.Dynamic:
|
||||||
|
case UpgradeAppType.Static:
|
||||||
|
if (downgradedModule) {
|
||||||
|
throw new Error(
|
||||||
|
`Error while ${attemptedAction}: 'downgradedModule' unexpectedly specified.\n` +
|
||||||
|
'You should not specify a value for \'downgradedModule\', unless you are downgrading ' +
|
||||||
|
'more than one Angular module (via \'downgradeModule()\').');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UpgradeAppType.Lite:
|
||||||
|
if (!downgradedModule && (downgradedModuleCount >= 2)) {
|
||||||
|
throw new Error(
|
||||||
|
`Error while ${attemptedAction}: 'downgradedModule' not specified.\n` +
|
||||||
|
'This application contains more than one downgraded Angular module, thus you need to ' +
|
||||||
|
'always specify \'downgradedModule\' when downgrading components and injectables.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$injector.has(injectionKey)) {
|
||||||
|
throw new Error(
|
||||||
|
`Error while ${attemptedAction}: Unable to find the specified downgraded module.\n` +
|
||||||
|
'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
|
||||||
|
'application?');
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Error while ${attemptedAction}: Not a valid '@angular/upgrade' application.\n` +
|
||||||
|
'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
|
||||||
|
'application?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Deferred<R> {
|
export class Deferred<R> {
|
||||||
promise: Promise<R>;
|
promise: Promise<R>;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
@ -64,6 +116,20 @@ export interface LazyModuleRef {
|
|||||||
promise?: Promise<Injector>;
|
promise?: Promise<Injector>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum UpgradeAppType {
|
||||||
|
// App NOT using `@angular/upgrade`. (This should never happen in an `ngUpgrade` app.)
|
||||||
|
None,
|
||||||
|
|
||||||
|
// App using the deprecated `@angular/upgrade` APIs (a.k.a. dynamic `ngUpgrade`).
|
||||||
|
Dynamic,
|
||||||
|
|
||||||
|
// App using `@angular/upgrade/static` with `UpgradeModule`.
|
||||||
|
Static,
|
||||||
|
|
||||||
|
// App using @angular/upgrade/static` with `downgradeModule()` (a.k.a `ngUpgrade`-lite ).
|
||||||
|
Lite,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether the passed-in component implements the subset of the
|
* @return Whether the passed-in component implements the subset of the
|
||||||
* `ControlValueAccessor` interface needed for AngularJS `ng-model`
|
* `ControlValueAccessor` interface needed for AngularJS `ng-model`
|
||||||
|
@ -10,10 +10,10 @@ import {Compiler, CompilerOptions, Directive, Injector, NgModule, NgModuleRef, N
|
|||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
import * as angular from '../common/angular1';
|
import * as angular from '../common/angular1';
|
||||||
import {$$TESTABILITY, $COMPILE, $INJECTOR, $ROOT_SCOPE, COMPILER_KEY, INJECTOR_KEY, LAZY_MODULE_REF, NG_ZONE_KEY} from '../common/constants';
|
import {$$TESTABILITY, $COMPILE, $INJECTOR, $ROOT_SCOPE, COMPILER_KEY, INJECTOR_KEY, LAZY_MODULE_REF, NG_ZONE_KEY, UPGRADE_APP_TYPE_KEY} from '../common/constants';
|
||||||
import {downgradeComponent} from '../common/downgrade_component';
|
import {downgradeComponent} from '../common/downgrade_component';
|
||||||
import {downgradeInjectable} from '../common/downgrade_injectable';
|
import {downgradeInjectable} from '../common/downgrade_injectable';
|
||||||
import {Deferred, LazyModuleRef, controllerKey, onError} from '../common/util';
|
import {Deferred, LazyModuleRef, UpgradeAppType, controllerKey, onError} from '../common/util';
|
||||||
|
|
||||||
import {UpgradeNg1ComponentAdapterBuilder} from './upgrade_ng1_adapter';
|
import {UpgradeNg1ComponentAdapterBuilder} from './upgrade_ng1_adapter';
|
||||||
|
|
||||||
@ -506,7 +506,8 @@ export class UpgradeAdapter {
|
|||||||
|
|
||||||
this.ngZone = new NgZone({enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec')});
|
this.ngZone = new NgZone({enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec')});
|
||||||
this.ng2BootstrapDeferred = new Deferred();
|
this.ng2BootstrapDeferred = new Deferred();
|
||||||
ng1Module.factory(INJECTOR_KEY, () => this.moduleRef !.injector.get(Injector))
|
ng1Module.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Dynamic)
|
||||||
|
.factory(INJECTOR_KEY, () => this.moduleRef !.injector.get(Injector))
|
||||||
.factory(
|
.factory(
|
||||||
LAZY_MODULE_REF,
|
LAZY_MODULE_REF,
|
||||||
[
|
[
|
||||||
|
@ -10,8 +10,8 @@ import {Injector, NgModuleFactory, NgModuleRef, StaticProvider} from '@angular/c
|
|||||||
import {platformBrowser} from '@angular/platform-browser';
|
import {platformBrowser} from '@angular/platform-browser';
|
||||||
|
|
||||||
import * as angular from '../common/angular1';
|
import * as angular from '../common/angular1';
|
||||||
import {$INJECTOR, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_MODULE_NAME} from '../common/constants';
|
import {$INJECTOR, $PROVIDE, DOWNGRADED_MODULE_COUNT_KEY, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_APP_TYPE_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
|
||||||
import {LazyModuleRef, isFunction} from '../common/util';
|
import {LazyModuleRef, UpgradeAppType, getDowngradedModuleCount, isFunction} from '../common/util';
|
||||||
|
|
||||||
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
||||||
import {NgAdapterInjector} from './util';
|
import {NgAdapterInjector} from './util';
|
||||||
@ -119,18 +119,22 @@ export function downgradeModule<T>(
|
|||||||
|
|
||||||
// Create an ng1 module to bootstrap.
|
// Create an ng1 module to bootstrap.
|
||||||
angular.module(lazyModuleName, [])
|
angular.module(lazyModuleName, [])
|
||||||
|
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Lite)
|
||||||
.factory(INJECTOR_KEY, [lazyInjectorKey, identity])
|
.factory(INJECTOR_KEY, [lazyInjectorKey, identity])
|
||||||
.factory(
|
.factory(
|
||||||
lazyInjectorKey,
|
lazyInjectorKey,
|
||||||
() => {
|
() => {
|
||||||
if (!injector) {
|
if (!injector) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Trying to get the Angular injector before bootstrapping an Angular module.');
|
'Trying to get the Angular injector before bootstrapping the corresponding ' +
|
||||||
|
'Angular module.');
|
||||||
}
|
}
|
||||||
return injector;
|
return injector;
|
||||||
})
|
})
|
||||||
.factory(LAZY_MODULE_REF, [lazyModuleRefKey, identity])
|
.factory(LAZY_MODULE_REF, [lazyModuleRefKey, identity])
|
||||||
.factory(lazyModuleRefKey, [
|
.factory(
|
||||||
|
lazyModuleRefKey,
|
||||||
|
[
|
||||||
$INJECTOR,
|
$INJECTOR,
|
||||||
($injector: angular.IInjectorService) => {
|
($injector: angular.IInjectorService) => {
|
||||||
setTempInjectorRef($injector);
|
setTempInjectorRef($injector);
|
||||||
@ -145,6 +149,12 @@ export function downgradeModule<T>(
|
|||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
])
|
||||||
|
.config([
|
||||||
|
$INJECTOR, $PROVIDE,
|
||||||
|
($injector: angular.IInjectorService, $provide: angular.IProvideService) => {
|
||||||
|
$provide.constant(DOWNGRADED_MODULE_COUNT_KEY, getDowngradedModuleCount($injector) + 1);
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return lazyModuleName;
|
return lazyModuleName;
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
import {Injector, NgModule, NgZone, Testability} from '@angular/core';
|
import {Injector, NgModule, NgZone, Testability} from '@angular/core';
|
||||||
|
|
||||||
import * as angular from '../common/angular1';
|
import * as angular from '../common/angular1';
|
||||||
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $INTERVAL, $PROVIDE, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_MODULE_NAME} from '../common/constants';
|
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $INTERVAL, $PROVIDE, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_APP_TYPE_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
|
||||||
import {LazyModuleRef, controllerKey} from '../common/util';
|
import {LazyModuleRef, UpgradeAppType, controllerKey} from '../common/util';
|
||||||
|
|
||||||
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
||||||
import {NgAdapterInjector} from './util';
|
import {NgAdapterInjector} from './util';
|
||||||
@ -173,6 +173,8 @@ export class UpgradeModule {
|
|||||||
angular
|
angular
|
||||||
.module(INIT_MODULE_NAME, [])
|
.module(INIT_MODULE_NAME, [])
|
||||||
|
|
||||||
|
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
|
||||||
|
|
||||||
.value(INJECTOR_KEY, this.injector)
|
.value(INJECTOR_KEY, this.injector)
|
||||||
|
|
||||||
.factory(
|
.factory(
|
||||||
|
@ -6,31 +6,46 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {INJECTOR_KEY} from '@angular/upgrade/src/common/constants';
|
import {Injector} from '@angular/core';
|
||||||
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||||
|
import {$INJECTOR, INJECTOR_KEY, UPGRADE_APP_TYPE_KEY} from '@angular/upgrade/src/common/constants';
|
||||||
import {downgradeInjectable} from '@angular/upgrade/src/common/downgrade_injectable';
|
import {downgradeInjectable} from '@angular/upgrade/src/common/downgrade_injectable';
|
||||||
|
import {UpgradeAppType} from '@angular/upgrade/src/common/util';
|
||||||
|
|
||||||
|
describe('downgradeInjectable', () => {
|
||||||
|
const setupMockInjectors = (downgradedModule = '') => {
|
||||||
|
const mockNg1Injector = jasmine.createSpyObj<angular.IInjectorService>(['get', 'has']);
|
||||||
|
mockNg1Injector.get.and.callFake((key: string) => mockDependencies[key]);
|
||||||
|
mockNg1Injector.has.and.callFake((key: string) => mockDependencies.hasOwnProperty(key));
|
||||||
|
|
||||||
|
const mockNg2Injector = jasmine.createSpyObj<Injector>(['get']);
|
||||||
|
mockNg2Injector.get.and.returnValue('service value');
|
||||||
|
|
||||||
|
const mockDependencies: {[key: string]: any} = {
|
||||||
|
[UPGRADE_APP_TYPE_KEY]: downgradedModule ? UpgradeAppType.Lite : UpgradeAppType.Static,
|
||||||
|
[`${INJECTOR_KEY}${downgradedModule}`]: mockNg2Injector,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {mockNg1Injector, mockNg2Injector};
|
||||||
|
};
|
||||||
|
|
||||||
{
|
|
||||||
describe('downgradeInjectable', () => {
|
|
||||||
it('should return an AngularJS annotated factory for the token', () => {
|
it('should return an AngularJS annotated factory for the token', () => {
|
||||||
const factory = downgradeInjectable('someToken');
|
const factory = downgradeInjectable('someToken');
|
||||||
expect(factory).toEqual(jasmine.any(Function));
|
expect(factory).toEqual(jasmine.any(Function));
|
||||||
expect((factory as any).$inject).toEqual([INJECTOR_KEY]);
|
expect((factory as any).$inject).toEqual([$INJECTOR]);
|
||||||
|
|
||||||
const injector = {get: jasmine.createSpy('get').and.returnValue('service value')};
|
const {mockNg1Injector, mockNg2Injector} = setupMockInjectors();
|
||||||
const value = factory(injector);
|
expect(factory(mockNg1Injector)).toEqual('service value');
|
||||||
expect(injector.get).toHaveBeenCalledWith('someToken');
|
expect(mockNg2Injector.get).toHaveBeenCalledWith('someToken');
|
||||||
expect(value).toEqual('service value');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject the specified module\'s injector when specifying a module name', () => {
|
it('should inject the specified module\'s injector when specifying a module name', () => {
|
||||||
const factory = downgradeInjectable('someToken', 'someModule');
|
const factory = downgradeInjectable('someToken', 'someModule');
|
||||||
expect(factory).toEqual(jasmine.any(Function));
|
expect(factory).toEqual(jasmine.any(Function));
|
||||||
expect((factory as any).$inject).toEqual([`${INJECTOR_KEY}someModule`]);
|
expect((factory as any).$inject).toEqual([$INJECTOR]);
|
||||||
|
|
||||||
const injector = {get: jasmine.createSpy('get').and.returnValue('service value')};
|
const {mockNg1Injector, mockNg2Injector} = setupMockInjectors('someModule');
|
||||||
const value = factory(injector);
|
expect(factory(mockNg1Injector)).toEqual('service value');
|
||||||
expect(injector.get).toHaveBeenCalledWith('someToken');
|
expect(mockNg2Injector.get).toHaveBeenCalledWith('someToken');
|
||||||
expect(value).toEqual('service value');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
@ -784,5 +784,37 @@ withEachNg1Version(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should throw if `downgradedModule` is specified', async(() => {
|
||||||
|
@Component({selector: 'ng2', template: ''})
|
||||||
|
class Ng2Component {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [Ng2Component],
|
||||||
|
entryComponents: [Ng2Component],
|
||||||
|
imports: [BrowserModule, UpgradeModule],
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ng1Module = angular.module('ng1', []).directive(
|
||||||
|
'ng2', downgradeComponent({component: Ng2Component, downgradedModule: 'foo'}));
|
||||||
|
|
||||||
|
const element = html('<ng2></ng2>');
|
||||||
|
|
||||||
|
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module)
|
||||||
|
.then(
|
||||||
|
() => { throw new Error('Expected bootstraping to fail.'); },
|
||||||
|
err =>
|
||||||
|
expect(err.message)
|
||||||
|
.toBe(
|
||||||
|
'Error while instantiating component \'Ng2Component\': \'downgradedModule\' ' +
|
||||||
|
'unexpectedly specified.\n' +
|
||||||
|
'You should not specify a value for \'downgradedModule\', unless you are ' +
|
||||||
|
'downgrading more than one Angular module (via \'downgradeModule()\').'));
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
|||||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||||
import {downgradeComponent, downgradeModule} from '@angular/upgrade/static';
|
import {downgradeComponent, downgradeModule} from '@angular/upgrade/static';
|
||||||
import * as angular from '@angular/upgrade/static/src/common/angular1';
|
import * as angular from '@angular/upgrade/static/src/common/angular1';
|
||||||
import {$ROOT_SCOPE, INJECTOR_KEY, LAZY_MODULE_REF} from '@angular/upgrade/static/src/common/constants';
|
import {$EXCEPTION_HANDLER, $ROOT_SCOPE, INJECTOR_KEY, LAZY_MODULE_REF} from '@angular/upgrade/static/src/common/constants';
|
||||||
import {LazyModuleRef} from '@angular/upgrade/static/src/common/util';
|
import {LazyModuleRef} from '@angular/upgrade/static/src/common/util';
|
||||||
|
|
||||||
import {html, multiTrim, withEachNg1Version} from '../test_helpers';
|
import {html, multiTrim, withEachNg1Version} from '../test_helpers';
|
||||||
@ -661,6 +661,138 @@ withEachNg1Version(() => {
|
|||||||
// Wait for the module to be bootstrapped.
|
// Wait for the module to be bootstrapped.
|
||||||
setTimeout(() => expect($injectorFromNg2).toBe($injectorFromNg1));
|
setTimeout(() => expect($injectorFromNg2).toBe($injectorFromNg1));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
describe('(common error)', () => {
|
||||||
|
let Ng2CompA: Type<any>;
|
||||||
|
let Ng2CompB: Type<any>;
|
||||||
|
let downModA: string;
|
||||||
|
let downModB: string;
|
||||||
|
let errorSpy: jasmine.Spy;
|
||||||
|
|
||||||
|
const doDowngradeModule = (module: Type<any>) => {
|
||||||
|
const bootstrapFn = (extraProviders: StaticProvider[]) =>
|
||||||
|
(getPlatform() || platformBrowserDynamic(extraProviders)).bootstrapModule(module);
|
||||||
|
return downgradeModule(bootstrapFn);
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
@Component({selector: 'ng2A', template: 'a'})
|
||||||
|
class Ng2ComponentA {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'ng2B', template: 'b'})
|
||||||
|
class Ng2ComponentB {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [Ng2ComponentA],
|
||||||
|
entryComponents: [Ng2ComponentA],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
})
|
||||||
|
class Ng2ModuleA {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [Ng2ComponentB],
|
||||||
|
entryComponents: [Ng2ComponentB],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
})
|
||||||
|
class Ng2ModuleB {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ng2CompA = Ng2ComponentA;
|
||||||
|
Ng2CompB = Ng2ComponentB;
|
||||||
|
downModA = doDowngradeModule(Ng2ModuleA);
|
||||||
|
downModB = doDowngradeModule(Ng2ModuleB);
|
||||||
|
errorSpy = jasmine.createSpy($EXCEPTION_HANDLER);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if no downgraded module is included', async(() => {
|
||||||
|
const ng1Module = angular.module('ng1', [])
|
||||||
|
.value($EXCEPTION_HANDLER, errorSpy)
|
||||||
|
.directive('ng2A', downgradeComponent({
|
||||||
|
component: Ng2CompA,
|
||||||
|
downgradedModule: downModA, propagateDigest,
|
||||||
|
}))
|
||||||
|
.directive('ng2B', downgradeComponent({
|
||||||
|
component: Ng2CompB,
|
||||||
|
propagateDigest,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const element = html('<ng2-a></ng2-a> | <ng2-b></ng2-b>');
|
||||||
|
angular.bootstrap(element, [ng1Module.name]);
|
||||||
|
|
||||||
|
expect(errorSpy).toHaveBeenCalledTimes(2);
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'Error while instantiating component \'Ng2ComponentA\': Not a valid ' +
|
||||||
|
'\'@angular/upgrade\' application.\n' +
|
||||||
|
'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
|
||||||
|
'application?'),
|
||||||
|
'<ng2-a>');
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'Error while instantiating component \'Ng2ComponentB\': Not a valid ' +
|
||||||
|
'\'@angular/upgrade\' application.\n' +
|
||||||
|
'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
|
||||||
|
'application?'),
|
||||||
|
'<ng2-b>');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should throw if the corresponding downgraded module is not included', async(() => {
|
||||||
|
const ng1Module = angular.module('ng1', [downModA])
|
||||||
|
.value($EXCEPTION_HANDLER, errorSpy)
|
||||||
|
.directive('ng2A', downgradeComponent({
|
||||||
|
component: Ng2CompA,
|
||||||
|
downgradedModule: downModA, propagateDigest,
|
||||||
|
}))
|
||||||
|
.directive('ng2B', downgradeComponent({
|
||||||
|
component: Ng2CompB,
|
||||||
|
downgradedModule: downModB, propagateDigest,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const element = html('<ng2-a></ng2-a> | <ng2-b></ng2-b>');
|
||||||
|
angular.bootstrap(element, [ng1Module.name]);
|
||||||
|
|
||||||
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'Error while instantiating component \'Ng2ComponentB\': Unable to find the ' +
|
||||||
|
'specified downgraded module.\n' +
|
||||||
|
'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
|
||||||
|
'application?'),
|
||||||
|
'<ng2-b>');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should throw if `downgradedModule` is not specified and there are multiple downgraded modules',
|
||||||
|
async(() => {
|
||||||
|
const ng1Module = angular.module('ng1', [downModA, downModB])
|
||||||
|
.value($EXCEPTION_HANDLER, errorSpy)
|
||||||
|
.directive('ng2A', downgradeComponent({
|
||||||
|
component: Ng2CompA,
|
||||||
|
downgradedModule: downModA, propagateDigest,
|
||||||
|
}))
|
||||||
|
.directive('ng2B', downgradeComponent({
|
||||||
|
component: Ng2CompB,
|
||||||
|
propagateDigest,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const element = html('<ng2-a></ng2-a> | <ng2-b></ng2-b>');
|
||||||
|
angular.bootstrap(element, [ng1Module.name]);
|
||||||
|
|
||||||
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'Error while instantiating component \'Ng2ComponentB\': \'downgradedModule\' not ' +
|
||||||
|
'specified.\n' +
|
||||||
|
'This application contains more than one downgraded Angular module, thus you need ' +
|
||||||
|
'to always specify \'downgradedModule\' when downgrading components and ' +
|
||||||
|
'injectables.'),
|
||||||
|
'<ng2-b>');
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user