在测试具有<ng-content>
的换位槽的Angular组件时,我们没有
显式意味着检查被转换的内容是否按预期放置在组件内。
例如:
// base-button.component.ts
@Component({
selector: 'base-button',
template: `<button [type]="type">
<ng-content></ng-content>
</button>`,
})
export class BaseButtonComponent {
@Input() type = 'button';
}
基本上,在spec文件中创建组件实例时,我们这样做:
// base-button.component.spec.ts
it('should reflect the `type` property into the "type" attribute of the button', () => {
const fixture = TestBed.createComponent(BaseButtonComponent);
fixture.detectChanges();
const { componentInstance, nativeElement } = fixture;
componentInstance.type = 'reset';
const button = nativeElement.querySelector('button');
expect(button.type === 'reset');
});
我们可以为组件的每个属性和方法执行此操作,但是该怎么做 被抄送的内容?解决方法是创建用于测试目的的主机组件:
// base-button.component.spec.ts
...
@Component({
template: `<base-button>Foo bar</base-button>`
})
export class BaseButtonHostComponent {}
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BaseButtonComponent, BaseButtonHostComponent ]
})
.compileComponents();
}));
it('should transclude the content correctly', () => {
const hostFixture = TestBed.createComponent(BaseButtonHostComponent);
hostFixture.detectChanges();
const button = hostFixture.nativeElement.querySelector('button');
expect(button.textContent === 'Foo bar');
});
...
但是,正如你可以想象的那样,这很不方便,也因为必须这样做
对于每个具有被转换内容的组件,可能对于每个<ng-content>
元素
在它的模板中。还有另一种方法吗?
答案 0 :(得分:1)
确实有一种相当模糊的方法。基本上,TestBed.createComponent
会调用
组件的工厂create
方法,它也支持可投影的DOM节点
插入到翻译位置。
// @angular/core/testing.js
createComponent(component) {
...
const componentFactory = this._compiler.getComponentFactory(component);
...
const componentRef = componentFactory.create(Injector.NULL, [], `#${rootElId}`, this._moduleRef);
...
}
我们必须这样做,这就是诀窍:
// base-button.component.spec.ts
describe('BaseButtonComponent', () => {
let factory: ComponentFactory<BaseButtonComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BaseButtonComponent ]
})
.overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [ BaseButtonComponent ]
}
})
.compileComponents();
const resolver = <ComponentFactoryResolver>TestBed.get(ComponentFactoryResolver, null);
factory = resolver.resolveComponentFactory(BaseButtonComponent);
}));
it('should transclude the provided nodes into the button', () => {
const tnode = document.createTextNode('Foo bar');
const componentRef = factory.create(Injector.NULL, [[ tnode ]]);
const button = componentRef.location.nativeElement.querySelector('button');
expect(button.textContent === 'Foo bar');
});
});
TestBed.get
允许我们检索ComponentFactoryResolver
服务。为了检索
但是,组件的工厂必须在模块的entryComponents
中列出组件的类
属性。有问题的模块是BrowserDynamicTestingModule
,TestBed
公开了一个方便的模块
改变其属性的方法。
一旦你有工厂,就可以获得技巧。唯一恼人的部分是产生所有 手工绘制可投影节点,因此您可以为此创建实用程序函数:
function createComponentWithContents(factory, ...contents) {
const template = document.createElement('template');
const projectableNodes = contents.map(html => {
template.innerHTML = html;
return [ ...template.content.childNodes ];
});
return factory.create(Injector.NULL, projectableNodes);
}
const componentRef = createComponentWithContents(factory, '<i class="fa fa-star"></i> Win!');
遗憾的是TestBed.createComponent
不允许立即这样做。