From 077a5fb04b07fb202d5cb0fb8f9d213d86899b32 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Tue, 20 Nov 2018 22:08:34 +0200 Subject: [PATCH] test(upgrade): test injector tree traversal for downgraded components (#27217) This commit adds tests that verify the current behavior wrt injector tree traversal for downgraded components, so that it is easier to contrast with changed behavior is future commits (should we decide to actually change it). PR Close #27217 --- .../integration/downgrade_module_spec.ts | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/packages/upgrade/test/static/integration/downgrade_module_spec.ts b/packages/upgrade/test/static/integration/downgrade_module_spec.ts index 929ac34afa..1643f12d94 100644 --- a/packages/upgrade/test/static/integration/downgrade_module_spec.ts +++ b/packages/upgrade/test/static/integration/downgrade_module_spec.ts @@ -331,6 +331,216 @@ withEachNg1Version(() => { expect(multiTrim(element.children[1].textContent)).toBe('Counter:1'); })); + fixmeIvy('FW-714: ng1 projected content is not being rendered') + .it('should correctly traverse the injector tree of downgraded components', async(() => { + @Component({ + selector: 'ng2A', + template: 'ng2A()', + providers: [ + {provide: 'FOO', useValue: 'CompA-foo'}, + {provide: 'BAR', useValue: 'CompA-bar'}, + ], + }) + class Ng2ComponentA { + } + + @Component({ + selector: 'ng2B', + template: ` + FOO:{{ foo }} + BAR:{{ bar }} + BAZ:{{ baz }} + QUX:{{ qux }} + `, + providers: [ + {provide: 'FOO', useValue: 'CompB-foo'}, + ], + }) + class Ng2ComponentB { + constructor( + @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, + @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string) {} + } + + @NgModule({ + declarations: [Ng2ComponentA, Ng2ComponentB], + entryComponents: [Ng2ComponentA, Ng2ComponentB], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'Mod-foo'}, + {provide: 'BAR', useValue: 'Mod-bar'}, + {provide: 'BAZ', useValue: 'Mod-baz'}, + ], + }) + class Ng2Module { + ngDoBootstrap() {} + } + + const bootstrapFn = (extraProviders: StaticProvider[]) => { + const platformRef = getPlatform() || platformBrowserDynamic([ + ...extraProviders, + {provide: 'FOO', useValue: 'Plat-foo'}, + {provide: 'BAR', useValue: 'Plat-bar'}, + {provide: 'BAZ', useValue: 'Plat-baz'}, + {provide: 'QUX', useValue: 'Plat-qux'}, + ]); + return platformRef.bootstrapModule(Ng2Module); + }; + + const downMod = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [downMod]) + .directive( + 'ng2A', downgradeComponent({component: Ng2ComponentA, propagateDigest})) + .directive( + 'ng2B', + downgradeComponent({component: Ng2ComponentB, propagateDigest})); + + const element = html(` + + + `); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + + // Wait for the module to be bootstrapped. + setTimeout(() => { + expect(multiTrim(element.textContent)).toBe('ng2A()'); + + // Nested component B. + $rootScope.$apply('showB1 = true'); + expect(multiTrim(element.children[0].textContent)) + .toBe('ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:Mod-baz QUX:Plat-qux )'); + + // Standalone component B. + $rootScope.$apply('showB2 = true'); + expect(multiTrim(element.children[1].textContent)) + .toBe('FOO:CompB-foo BAR:Mod-bar BAZ:Mod-baz QUX:Plat-qux'); + }); + })); + + fixmeIvy('FW-714: ng1 projected content is not being rendered') + .it('should correctly traverse the injector tree of downgraded components (from different modules)', + async(() => { + @Component({ + selector: 'ng2A', + template: 'ng2A()', + providers: [ + {provide: 'FOO', useValue: 'CompA-foo'}, + {provide: 'BAR', useValue: 'CompA-bar'}, + ], + }) + class Ng2ComponentA { + } + + @Component({ + selector: 'ng2B', + template: ` + FOO:{{ foo }} + BAR:{{ bar }} + BAZ:{{ baz }} + QUX:{{ qux }} + QUUX:{{ quux }} + `, + providers: [ + {provide: 'FOO', useValue: 'CompB-foo'}, + ], + }) + class Ng2ComponentB { + constructor( + @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, + @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string, + @Inject('QUUX') public quux: string) {} + } + + @NgModule({ + declarations: [Ng2ComponentA], + entryComponents: [Ng2ComponentA], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'ModA-foo'}, + {provide: 'BAR', useValue: 'ModA-bar'}, + {provide: 'BAZ', useValue: 'ModA-baz'}, + {provide: 'QUX', useValue: 'ModA-qux'}, + ], + }) + class Ng2ModuleA { + ngDoBootstrap() {} + } + + @NgModule({ + declarations: [Ng2ComponentB], + entryComponents: [Ng2ComponentB], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'ModB-foo'}, + {provide: 'BAR', useValue: 'ModB-bar'}, + {provide: 'BAZ', useValue: 'ModB-baz'}, + ], + }) + class Ng2ModuleB { + ngDoBootstrap() {} + } + + const doDowngradeModule = (module: Type) => { + const bootstrapFn = (extraProviders: StaticProvider[]) => { + const platformRef = getPlatform() || platformBrowserDynamic([ + ...extraProviders, + {provide: 'FOO', useValue: 'Plat-foo'}, + {provide: 'BAR', useValue: 'Plat-bar'}, + {provide: 'BAZ', useValue: 'Plat-baz'}, + {provide: 'QUX', useValue: 'Plat-qux'}, + {provide: 'QUUX', useValue: 'Plat-quux'}, + ]); + return platformRef.bootstrapModule(module); + }; + return downgradeModule(bootstrapFn); + }; + + const downModA = doDowngradeModule(Ng2ModuleA); + const downModB = doDowngradeModule(Ng2ModuleB); + const ng1Module = angular.module('ng1', [downModA, downModB]) + .directive('ng2A', downgradeComponent({ + component: Ng2ComponentA, + downgradedModule: downModA, propagateDigest, + })) + .directive('ng2B', downgradeComponent({ + component: Ng2ComponentB, + downgradedModule: downModB, propagateDigest, + })); + + const element = html(` + + + `); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + + // Wait for module A to be bootstrapped. + setTimeout(() => { + expect(multiTrim(element.textContent)).toBe('ng2A()'); + + // Nested component B. + $rootScope.$apply('showB1 = true'); + + // Wait for module B to be bootstrapped. + setTimeout(() => { + // It is debatable, whether the order of traversal should be: + // CompB > CompA > ModB > ModA > Plat (similar to how lazy-loaded components + // work) + expect(multiTrim(element.children[0].textContent)) + .toBe( + 'ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux )'); + + // Standalone component B. + $rootScope.$apply('showB2 = true'); + expect(multiTrim(element.children[1].textContent)) + .toBe( + 'FOO:CompB-foo BAR:ModB-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux'); + }); + }); + })); + it('should support downgrading a component and propagate inputs', async(() => { @Component( {selector: 'ng2A', template: 'a({{ value }}) | '})