vendredi 1 septembre 2017

How to test transcluded content in Angular?

While testing an Angular component that has transclusion slots with <ng-content>, we have no explicit means to check if the transcluded content is placed as intended inside the component. For example:

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

Basically, when creating a component instance in the spec file, we do this:

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

We can do this for every property and method of the component, but what about the transcluded content? A workaround would be creating a host component for test purposes:

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

But, as you could imagine, this is rather inconvenient, also because this has to be done for every component with transcluded content, and possibly for every <ng-content> element in its template. Is there another way to do this?

Aucun commentaire:

Enregistrer un commentaire