如何对以 TemplateRef 作为输入的 Angular 组件进行单元测试?

Posted

技术标签:

【中文标题】如何对以 TemplateRef 作为输入的 Angular 组件进行单元测试?【英文标题】:How to make a Unit Test of an Angular Component which has a TemplateRef as Input? 【发布时间】:2019-11-21 08:21:00 【问题描述】:

我正在尝试为 Angular 组件编写单元测试,该组件可以隐藏/显示一些作为输入传递给组件本身的内容。 预期的输入被定义为 TemplateRef。

my-component.component.ts

@Component(
    selector: "my-component",
    templateUrl: "./my-component.component.html",
    styleUrls: ["./my-component.component.scss"],
    exportAs: "mycomponent"
)
export class MyComponent 
    private _expanded = false;

    @Input()
    set expanded(value: boolean) 
        this._expanded = value;
    

    @Input()
    body: TemplateRef<any>;
    @Input()
    handler: TemplateRef<any>;

    constructor() 

    toggleView() 
        this.expanded = !this._expanded;
    


my-component.component.html

<div class="wrap">
    <!-- Header -->
    <main #header>
        <header (click)="toggleAccordion()">
            <div class="handler">
                <ng-container [ngTemplateOutlet]="handler">
                </ng-container>
            </div>
            <i class="icon icon-expand" [ngClass]=" 'icon-expand': _expanded, 'icon-collapse': !_expanded "></i>
        </header>
    </main>
    <!-- Body -->
    <div class="body" *ngIf="_expanded">
        <ng-container [ngTemplateOutlet]="body"></ng-container>
    </div>
</div>

我想测试通过输入“body”传递的内容是否可见,但我不知道如何在 jasmine 中使用 TemplateRef 输入实例化“my-component”。

The Angular documentation explains how to pass an input 在单元测试脚本上,但是由于 TemplateRef 是一个抽象类,我无法实例化任何 TemplateRef 对象,我不知道如何管理它。

my-component.component.spec.ts


...

    beforeEach(async(() => 
        TestBed.configureTestingModule(
            declarations: [MyComponent]
        ).compileComponents();
    ));

    beforeEach(() => 
        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;
        component.body = /* What should I put here? */;
        fixture.detectChanges();
    );

....

【问题讨论】:

【参考方案1】:

我会尝试给你一个演示代码,你可以进一步扩展它

基本上,您需要以不同的方式对此进行测试。由于不使用另一个组件的TemplateRef 就无法创建组件,因此您需要创建一个包装器组件并通过为 WrapperComponent 编写测试用例来测试您的组件


@Component(
  template: `
    <ng-template #div1>Something here</ng-template>
    <ng-template #div2>Many things here</ng-template>
    <my-component [expanded]="expandedVal" [body]="div1" [handler]="div2"> </my-component>
  `,
)
class WrapperComponent 
     @ViewChild(MyComponent,  static: true ) appComponentRef: MyComponent;
     public expandedVal = true;


describe('MyComponent', () => 
  let app: MyComponent;
  let fixture: ComponentFixture<WrapperComponent>;
  beforeEach(async(() => 
    TestBed.configureTestingModule(
      declarations: [WrapperComponent, MyComponent],
    ).compileComponents();
  ));
  beforeEach(() => 
    fixture = TestBed.createComponent(WrapperComponent);
    const wrapperComponent = fixture.debugElement.componentInstance;
    app = wrapperComponent.appComponentRef; // this is where you get "MyComponent" component for testing
    fixture.detectChanges();
  );
  it('should create the app', async(() => 
    expect(app).toBeDefined();
  ));
);

【讨论】:

您写的 shashankvivek-7.medium.com/… 引导我到这里的文章非常有帮助 @BenTaliadoros:这种赞赏意义重大。谢谢本! :) 我最初无法让上述示例正常工作。我必须像 @ViewChild(ChildComponent, static: true ) 这样声明 ViewChild 才能使其工作。这意味着在更改检测发生之前解决子级,在示例中发生在 组件分配给测试属性之后。 @FantasticJamieBurns 谢谢。这里没有。

以上是关于如何对以 TemplateRef 作为输入的 Angular 组件进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

从指令中创建/获取 TemplateRef

我可以从字符串创建 TemplateRef 吗?

没有 TemplateRef 的提供者! (NgIf -> 模板参考)

typescript ElementRef,TemplateRef,ViewContainerRef

如何在c#中对以空格分隔的数字进行舍入?

如何对以第一个字符开头的字符串数组进行排序?