从 Angular 组件测试中选择特定的 TemplateRef?

Selecting a specific TemplateRef from Angular component test?

我有以下组件具有打开模式的链接,我可以通过将模板引用传递到其中来改变内容。

<a id="spec-tos" (click)="openModal($event, termsOfServiceModalTemplate)">Terms of Service</a>
<a id="spec-pp" (click)="openModal($event, privacyPolicyModalTemplate)">Privacy</a>

<ng-template #termsOfServiceModalTemplate>
  terms of service text goes here...
</ng-template>

<ng-template #privacyPolicyModalTemplate>
  privacy policy text goes here...
</ng-template>
export class FooterComponent {
  modalRef: undefined | BsModalRef;

  constructor(private modalService: BsModalService) {}

  openModal($event: Event, template: TemplateRef<NgTemplateOutlet>): void {
    $event.preventDefault();
    this.modalRef = this.modalService.show(template, {
      class: 'modal-dialog-scrollable'
    });
  }
}

如何测试链接是否打开了正确的模板?我需要能够 select 我的测试中的 templateRef ID,但我不确定该怎么做。这是我的测试

it('should call the openModal() method when clicking on the privacy policy link', () => {
    spyOn(component, 'openModal');
    const link = debugEl.query(By.css('#spec-pp'));
    //This next line is wrong and does not work
    const tmpl = debugEl.query(By.directive(TemplateRef));
    link.triggerEventHandler('click', null);
    expect(component.openModal).toHaveBeenCalledWith(new MouseEvent('click'), tmpl);
});

我知道 debugEl.query(By.directive(TemplateRef)) 不起作用...但这只是为了说明我想在这里做什么。我如何 select 来自我正在测试的组件的特定模板?


编辑:下面@neo 的回答是解决方案,但我能够采用他的解决方案并将其打包成可重复使用的辅助函数

/**
 * Used for detecting an `<ng-template>` element reference that was passed to a function, typically for modals
 * We don't have access to much except the name of the template and a number that it maps to internally.
 * If we can return the number, then we've found the template by name, which is all we really want to do here
 * //
 */
export const templateExists = (template: TemplateRef<NgTemplateOutlet>, templateName: string): boolean => {
    // tslint:disable-next-line:no-any  --  There is no other way to get this object, it doesn't exist in the typedefs!
    const refs = (template as any)._def.references as {[templateName: string]: number};
    //If we have a number, then we've found the template by name
    return !isNaN(refs[templateName]);
};

这样使用:

it('should call the openModal() method when clicking on the privacy policy link', () => {
    const modalSpy = spyOn(component, 'openModal');
    const link = debugEl.query(By.css('.footer-nav .spec-privacy'));
    link.triggerEventHandler('click', null);
    expect(component.openModal).toHaveBeenCalled();
    expect(templateExists(modalSpy.calls.mostRecent().args[1], 'privacyPolicyModalTemplate')).toEqual(true);
});

抱歉耽误了,这几天比较忙。您应该按如下方式修改您的 spec.ts

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
import { BrowserModule, By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatButtonModule } from '@angular/material';
import { ModalModule } from 'ngx-bootstrap';

describe('FooterComponent ', () => {
  let component: FooterComponent;
  let fixture: ComponentFixture<FooterComponent>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        FooterComponent
      ],
      imports: [
        // your imports here
        ModalModule.forRoot()
      ]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(FooterComponent);
    component = fixture.debugElement.componentInstance;
    fixture.detectChanges();
  });

  it('should create the app', () => {
    expect(component).toBeTruthy();
  });


  it('should call the openModal() method when clicking on the links', () => {
    const obj = spyOn(component, 'openModal');
    let link = fixture.debugElement.query(By.css('#spec-tos'));
    link.triggerEventHandler('click', null);
    expect(component.openModal).toHaveBeenCalled();
    expect(obj.calls.mostRecent().args[1]._def.references.termsOfServiceModalTemplate).toBeDefined();

    link = fixture.debugElement.query(By.css('#spec-pp'));
    link.triggerEventHandler('click', null);
    expect(component.openModal).toHaveBeenCalledTimes(2);
    expect(obj.calls.mostRecent().args[1]._def.references.privacyPolicyModalTemplate).toBeDefined();
  });
});

尽情享受!!