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 }}) | '})