jeudi 28 février 2019

Angular: How to fire ngAfterViewChecked() for directive in test

I am writing test for a directive that implements the AfterViewChecked interface. I was following the test written for MatTooltip here I have created a demo component where I applied the directive under test. I read here that for change detection of the component fixture to work, I need to wrap the demo component into another host component, which I did, but it did not fire the ngAfterViewChecked() method of the directive. I can, off course, call the method myself, but it will kind of defeat the purpose of the test. Below is the code. Any help is appreciated. Thanks in advance.

The directive

@Directive({
  selector: '[scroll-into-view]',
})
export class ScrollIntoViewDirective implements AfterViewChecked  {
  private element: HTMLElement;
  @Input() parentContainer: HTMLElement | undefined;

  selected = false;

  constructor(private elRef: ElementRef) {
    this.element = elRef.nativeElement;
  }

  @Input('scroll-into-view') set elementSelected(condition: boolean) {
    this.selected = condition;
  }

  ngAfterViewChecked() {
    if (this.selected && !this.isWithinParent()) {
      this.element.scrollIntoView();
    }
  }          
}

The demo component

@Component({
  selector: 'wvc-scroll-into-view-demo',
  template: `
    <div #container>
      <div [scroll-into-view]="!!scrollIntoView" [parentContainer]="container">
        Test Div
      </div>
    </div>
  `,
})
class ScrollIntoViewDemoComponent {
  @Input() scrollIntoView?: boolean;
}

The host component

@Component({
  selector: 'wvc-scroll-into-view-demo-host',
  template: `
    <wvc-scroll-into-view-demo
      [scrollIntoView]="scrollIntoView"
    ></wvc-scroll-into-view-demo>
  `,
})
class ScrollIntoViewDemoHostComponent {
  scrollIntoView = false;
}

The test

describe('ScrollInViewDirective', () => {
  let fixture: ComponentFixture<ScrollIntoViewDemoHostComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        ScrollIntoViewDemoComponent,
        ScrollIntoViewDemoHostComponent,
        ScrollIntoViewDirective,
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ScrollIntoViewDemoHostComponent);
  });

  fit('should scroll element into view.', () => {
    const demoComponentDebugElement = fixture.debugElement.query(
      By.directive(ScrollIntoViewDemoComponent),
    );

    const directiveNativeElement = demoComponentDebugElement.query(By.directive(ScrollIntoViewDirective)).nativeElement;
    console.log(`Debug Element: ${demoComponentDebugElement.name}`);
    spyOn(directiveNativeElement, 'scrollIntoView');

    const directive = demoComponentDebugElement.injector.get<ScrollIntoViewDirective>(
      ScrollIntoViewDirective,
    );

    spyOn(directive, 'isWithinParent').and.returnValue(true);

    expect(directiveNativeElement.scrollIntoView).not.toHaveBeenCalled();

    fixture.componentInstance.scrollIntoView = true;

    fixture.detectChanges();

    expect(directiveNativeElement.scrollIntoView).toHaveBeenCalled();
  });
});

Aucun commentaire:

Enregistrer un commentaire