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

时间:2019-03-28 19:00:15

标签: angular angular-template angular-test angular-testing

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

<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'
    });
  }
}

如何测试链接是否打开了正确的模板?我需要能够从测试中选择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))不起作用...但这只是为了让我了解我想在这里做什么。如何从正在测试的组件中选择特定模板?


编辑:以下@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
 * //https://stackoverflow.com/a/55432163/79677
 */
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);
});

1 个答案:

答案 0 :(得分:2)

抱歉,延迟了,这几天很忙。您应该按照以下步骤修改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();
  });
});

享受!