Skip to content

How to test components with ng-content? #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tonivj5 opened this issue Mar 20, 2020 · 7 comments · Fixed by #82
Closed

How to test components with ng-content? #78

tonivj5 opened this issue Mar 20, 2020 · 7 comments · Fixed by #82
Labels

Comments

@tonivj5
Copy link
Contributor

tonivj5 commented Mar 20, 2020

Hey, I'm testing components that rely completely in <ng-content>.

Here is a component I want to test:

import { Component, ChangeDetectionStrategy, Inject } from '@angular/core';

import { use } from '@core/utils';

import { CONTEXT } from '../table/tokens';

@Component({
  template: `
    <p data-testid="too-long-cell" [style.width]="context">
      <ng-content></ng-content>
    </p>
  `,
  styles: [
    `
      p {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TooLongCellComponent {
  constructor(@Inject(CONTEXT) public context = '150px') {}
}

And I have written this test:

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { render } from '@testing-library/angular';

import { CONTEXT } from '../table/tokens';
import { TooLongCellComponent } from './too-long-cell.component';

export function getTestingComponent(template: string) {
  @Component({
    template,
    changeDetection: ChangeDetectionStrategy.OnPush,
  })
  class TestComponent {}

  return TestComponent;
}

function createComponent({ width }: { width?: number } = {}) {
  TestBed.overrideComponent(TooLongCellComponent, { set: { selector: 'cell' } });

  return render(getTestingComponent('<cell>projected value</cell>'), {
    providers: [
      {
        provide: CONTEXT,
        useValue: width,
      },
    ],
    declarations: [TooLongCellComponent],
  });
}

describe(TooLongCellComponent, () => {
 it('should add a width property with 100px', async () => {
    const { getByTestId } = await createComponent({ width: '100px' });

    const cell = getByTestId('too-long-cell');

    expect(cell.style.width).toBe('100px');
    expect(cell).toHaveTextContent(/^projected value$/);
  });
});

Could we improve the testing of <ng-content> using angular-testing-library? Or should I do in this way?

Thanks 👍

@timdeschryver
Copy link
Member

Hi thanks for raising this issue, it's the first time!

I haven't tested this, but could you use the same approach as with directives? https://github.com/testing-library/angular-testing-library/blob/master/src/app/examples/08-directive.spec.ts

@tonivj5
Copy link
Contributor Author

tonivj5 commented Mar 21, 2020

I'm going to try it rigth now! 👍

@tonivj5
Copy link
Contributor Author

tonivj5 commented Mar 21, 2020

It works 😄! Thanks for the hint 💪

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { render } from '@testing-library/angular';

import { CONTEXT } from '../table/tokens';
import { TooLongCellComponent } from './too-long-cell.component';

function createComponent({ width }: { width?: number } = {}) {
  TestBed.overrideComponent(TooLongCellComponent, { set: { selector: 'cell' } });

  return render(TooLongCellComponent, {
	template: '<cell>projected value</cell>',
    providers: [
      {
        provide: CONTEXT,
        useValue: width,
      },
    ],
  });
}

describe(TooLongCellComponent, () => {
 it('should add a width property with 100px', async () => {
    const { getByTestId } = await createComponent({ width: '100px' });

    const cell = getByTestId('too-long-cell');

    expect(cell.style.width).toBe('100px');
    expect(cell).toHaveTextContent(/^projected value$/);
  });
});

I guess I'm going to keep needing this line TestBed.overrideComponent(TooLongCellComponent, { set: { selector: 'cell' } }). Maybe render options could receive a metadata: Component to set seletor? It's my specific use-case, I don't add selectors to my dynamic-components (components that I create dynamically from ngComponentOutlet or ComponentFactoryResolver) and I don't use in the classic template-way 😅

@timdeschryver
Copy link
Member

I'm leaning towards leaving it as is, since this is a very specific use case, and this would add an extra option to the API.
I think this use case is worth documenting tho, do you want to create an example for this in the examples folder?

@tonivj5
Copy link
Contributor Author

tonivj5 commented Mar 24, 2020

No matter, thanks for the time and the template option! 🚀

I will create an example with my use-case 😸

@tonivj5
Copy link
Contributor Author

tonivj5 commented Mar 26, 2020

I have created a PR to add the use-case #82

timdeschryver added a commit that referenced this issue Mar 29, 2020
@timdeschryver
Copy link
Member

🎉 This issue has been resolved in version 9.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants