fix(ivy): element injector on the host of a component should see viewProviders of that component (#27928)

PR Close #27928
This commit is contained in:
Marc Laval 2019-01-04 15:38:40 +01:00 committed by Kara Erickson
parent 5d3dcfc6ad
commit fb7816fed4
3 changed files with 46 additions and 32 deletions

View File

@ -60,7 +60,7 @@ import {findComponentView, getParentInjectorIndex, getParentInjectorView, hasPar
* *
* ``` * ```
*/ */
let includeViewProviders = false; let includeViewProviders = true;
function setIncludeViewProviders(v: boolean): boolean { function setIncludeViewProviders(v: boolean): boolean {
const oldValue = includeViewProviders; const oldValue = includeViewProviders;

View File

@ -292,21 +292,19 @@ class TestComp {
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2'); expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
}); });
fixmeIvy( it('should instantiate viewProviders that have dependencies', () => {
'FW-889: Element injector cannot access the viewProviders of the component to which it belongs') TestBed.configureTestingModule({declarations: [SimpleComponent]});
.it('should instantiate viewProviders that have dependencies', () => { const viewProviders = [
TestBed.configureTestingModule({declarations: [SimpleComponent]}); {provide: 'injectable1', useValue: 'injectable1'}, {
const viewProviders = [ provide: 'injectable2',
{provide: 'injectable1', useValue: 'injectable1'}, { useFactory: (val: any) => `${val}-injectable2`,
provide: 'injectable2', deps: ['injectable1']
useFactory: (val: any) => `${val}-injectable2`, }
deps: ['injectable1'] ];
} TestBed.overrideComponent(SimpleComponent, {set: {viewProviders}});
]; const el = createComponent('<div simpleComponent></div>');
TestBed.overrideComponent(SimpleComponent, {set: {viewProviders}}); expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
const el = createComponent('<div simpleComponent></div>'); });
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
});
it('should instantiate components that depend on viewProviders providers', () => { it('should instantiate components that depend on viewProviders providers', () => {
TestBed.configureTestingModule({declarations: [NeedsServiceComponent]}); TestBed.configureTestingModule({declarations: [NeedsServiceComponent]});
@ -500,22 +498,20 @@ class TestComp {
expect(destroyed).toBe(true); expect(destroyed).toBe(true);
}); });
fixmeIvy( it('should instantiate view providers lazily', () => {
'FW-889: Element injector cannot access the viewProviders of the component to which it belongs') let created = false;
.it('should instantiate view providers lazily', () => { TestBed.configureTestingModule({declarations: [SimpleComponent]});
let created = false; TestBed.overrideComponent(
TestBed.configureTestingModule({declarations: [SimpleComponent]}); SimpleComponent,
TestBed.overrideComponent( {set: {viewProviders: [{provide: 'service', useFactory: () => created = true}]}});
SimpleComponent, const el = createComponent('<div simpleComponent></div>');
{set: {viewProviders: [{provide: 'service', useFactory: () => created = true}]}});
const el = createComponent('<div simpleComponent></div>');
expect(created).toBe(false); expect(created).toBe(false);
el.children[0].injector.get('service'); el.children[0].injector.get('service');
expect(created).toBe(true); expect(created).toBe(true);
}); });
it('should not instantiate other directives that depend on viewProviders providers (same element)', it('should not instantiate other directives that depend on viewProviders providers (same element)',
() => { () => {

View File

@ -1188,7 +1188,11 @@ describe('providers', () => {
static ngInjectableDef = defineInjectable({factory: () => new SomeInj(inject(String))}); static ngInjectableDef = defineInjectable({factory: () => new SomeInj(inject(String))});
} }
@Component({template: `<p></p>`, providers: [{provide: String, useValue: 'From my component'}]}) @Component({
template: `<p></p>`,
providers: [{provide: String, useValue: 'From my component'}],
viewProviders: [{provide: Number, useValue: 123}]
})
class MyComponent { class MyComponent {
constructor() {} constructor() {}
@ -1204,7 +1208,9 @@ describe('providers', () => {
} }
}, },
features: [ features: [
ProvidersFeature([{provide: String, useValue: 'From my component'}]), ProvidersFeature(
[{provide: String, useValue: 'From my component'}],
[{provide: Number, useValue: 123}]),
], ],
}); });
} }
@ -1237,12 +1243,24 @@ describe('providers', () => {
}); });
} }
it('should work', () => { it('should work from within the template', () => {
const fixture = new ComponentFixture(AppComponent); const fixture = new ComponentFixture(AppComponent);
expect(fixture.html).toEqual('<my-cmp><p></p></my-cmp>'); expect(fixture.html).toEqual('<my-cmp><p></p></my-cmp>');
const p = fixture.hostElement.querySelector('p'); const p = fixture.hostElement.querySelector('p');
const injector = getInjector(p as any); const injector = getInjector(p as any);
expect(injector.get(Number)).toEqual(123);
expect(injector.get(String)).toEqual('From my component');
expect(injector.get(Some).location).toEqual('From app component');
});
it('should work from the host of the component', () => {
const fixture = new ComponentFixture(AppComponent);
expect(fixture.html).toEqual('<my-cmp><p></p></my-cmp>');
const myCmp = fixture.hostElement.querySelector('my-cmp');
const injector = getInjector(myCmp as any);
expect(injector.get(Number)).toEqual(123);
expect(injector.get(String)).toEqual('From my component'); expect(injector.get(String)).toEqual('From my component');
expect(injector.get(Some).location).toEqual('From app component'); expect(injector.get(Some).location).toEqual('From app component');
}); });