getsaf / shallow-render

Angular testing made easy with shallow rendering and easy mocking. https://getsaf.github.io/shallow-render
MIT License
273 stars 25 forks source link

Mock structural directives #209

Closed FrEaKmAn closed 2 years ago

FrEaKmAn commented 2 years ago

I couldn't find an information in old issues, so I apologize if this question was already asked.

Is there a way I could control how the structural directive is behaving? I tried providing mock for directive injected stuff which control how directive is rendered, but it has no effect. I tried providing as mock of directive without any success.

Is there a way to mock structural directives?

getsaf commented 2 years ago

Yes, you can manually or globally control structural directives. They are automatically mocked but are fully controllable in your test.

Here's the docs for structural directives: https://getsaf.github.io/shallow-render/#structural-directives

This portion sounds like what you're looking for: https://getsaf.github.io/shallow-render/#per-test-configuration

FrEaKmAn commented 2 years ago

Thank you for your reply. I checked the docs, but I still don't see an option to control how the directive is rendering. I have following directive

@Directive({
  selector: "[appHasRole]",
})
export class HasRoleDirective implements OnInit {
  @Input("appHasRole") role?: RoleCheck | null;

  constructor(
    private _viewContainer: ViewContainerRef,
    private _templateRef: TemplateRef<unknown>,
    private _authService: AuthService
  ) {}

  ngOnInit(): void {
    if (this._authService.hasRole(this.role)) {
      this._viewContainer.clear();
      this._viewContainer.createEmbeddedView(this._templateRef);
    } else {
      this._viewContainer.clear();
    }
  }
}
  1. I tried to mock AuthService to once return true and other time false. No success.
  2. If I create dummy Directive that would always evaluate else condition, I cannot override the initial directive.

Is it possible to control how the directive is rendering?

getsaf commented 2 years ago

All directives are mocked by default. It sounds like your test is just using the mocked directive which makes it unresponsive to your service calls.

I would suspect that your test would look something like this:

describe('component with structural directive', () => {
  let shallow: Shallow<MyComponent>;

  beforeEach(() => {
    shallow = new Shallow(MyComponent, MyModule);
  });

  it('renders content when role matches', async () => {
    const { find } = await shallow
      .dontMock(HasRoleDirective) // <-- If you want to use the *REAL* HasRoleDirective, you have to skip mocking
      .mock(AuthService, { hasRole: (role) => role === 'fooRole' })
      .render();

    expect(find('h1').nativeElement.textContent).toBe('Has foo role!');
  });
});

Here's a working StackBlitz example with your directive.

getsaf commented 2 years ago

I assume this question was answered. Closing the issue.