2017-09-01 1 views
0

転置スロットを持つ角度コンポーネントを<ng-content>でテストしている間に、 は、トランスコードされたコンテンツが意図したとおりにコンポーネント内に配置されているかどうかを確認する明示的な手段がありません。たとえば :我々はこれを行う、specファイルにコンポーネントのインスタンスを作成する際にAngularで継承されたコンテンツをテストするには?

// base-button.component.ts 
@Component({ 
    selector: 'base-button', 
    template: `<button [type]="type"> 
    <ng-content></ng-content> 
    </button>`, 
}) 
export class BaseButtonComponent { 
    @Input() type = 'button'; 
} 

基本的には、:

// 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

本当にそれを行うにはあまりにも曖昧なやり方があります。基本的には、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はすぐにそれを行うことはできませんので残念です。

関連する問題