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:
George Kalpakas
2018-10-08 15:25:37 +03:00
committed by Kara Erickson
parent 93837e9545
commit 7dbc103cbe
12 changed files with 333 additions and 54 deletions

View File

@ -13,7 +13,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
import {downgradeComponent, downgradeModule} from '@angular/upgrade/static';
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 {html, multiTrim, withEachNg1Version} from '../test_helpers';
@ -661,6 +661,138 @@ withEachNg1Version(() => {
// Wait for the module to be bootstrapped.
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>');
}));
});
});
});
});