Тестирование прокрутки HostListener в Angular 5 - PullRequest
0 голосов
/ 29 мая 2018

Как проверить прокрутку в Angular 5?Как макетировать окно в тестах?

Это мой код:

import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[escElementPreventOverlap]'
})
export class ElementPreventOverlapDirective {
  private offsetTop: number;
  private scrollTop: number;

  constructor(private element: ElementRef) {
  }

  @HostListener('window:scroll', ['$event'])
  @HostListener('window:resize', ['$event'])
  event(event) {
    this.offsetTop= this.element.nativeElement.parentElement.offsetTop + this.element.nativeElement.parentElement.offsetHeight;
    this.scrollTop= document.documentElement.scrollTop + window.innerHeight;

    if (this.scrollTop> this.offsetTop) {
      this.element.nativeElement.classList.remove('fixed');
    } else {
      this.element.nativeElement.classList.add('fixed');
    }
  }
}

Работает нормально, но я не могу понять, как его протестировать.

1 Ответ

0 голосов
/ 31 мая 2018

Я узнал, как это сделать!Вам нужно внедрить окно в место, где вы его используете, чтобы во время тестирования вы могли его смоделировать.

Сначала вы должны создать файл (options.ts) и написать это:

import { InjectionToken } from '@angular/core';

export const N_DOCUMENT = new InjectionToken<Document>('DocumentToken');
export const N_WINDOW = new InjectionToken<Window>('WindowToken');

Во-вторых, вы должны добавить окно в директиву / компонент:

import { Directive, ElementRef, HostListener, Inject } from '@angular/core';
import { N_WINDOW, N_DOCUMENT } from '../options';

@Directive({
  selector: '[appElement]'
})
export class ElementDirective {
  parentOffsetTopWithHeight: number;
  documentScrollTopWithHeight: number;

  constructor(public element: ElementRef, @Inject(N_WINDOW) window, @Inject(N_DOCUMENT) document) {
  }
 @HostListener('window:scroll', ['$event'])
  scroll(event) {...}
    }

В-третьих, вы можете использовать это в таких тестах:

import { ElementRef } from '@angular/core';
import { TestBed } from '@angular/core/testing';

import { ElementDirective } from '../element.directive';
import { N_WINDOW, N_DOCUMENT } from '../options';


class ElementRefMock extends ElementRef {
  nativeElement = {
    parentElement: {
      offsetTop: 1200,
      offsetHeight: 200,
    },
    classList: {
      list: [],
      add (className) {
        if (this.list.indexOf(className) === -1) {
          this.list.push(className);
        }
      },
      remove (className) {
        const classIndex = this.list.indexOf(className);
        if (classIndex !== -1) {
          this.list.splice(classIndex, 1);
        }
      },
      contains (className) {
        return this.list.indexOf(className) !== -1;
      }
    }
      };

      setNativeElement(nativeElement) {
        this.nativeElement = nativeElement;
      }
    }

    describe('ElementDirective', () => {
      let directive: ElementDirective;
      const elemDom = document.createElement('div');
      const elementRef = new ElementRefMock(elemDom);

      beforeEach(() => {
        TestBed.configureTestingModule({
          providers: [
            {provide: N_WINDOW, useValue: window},
            {provide: N_DOCUMENT, useValue: document}
          ],
        });
        directive = new ElementDirective(elementRef, window, document);
      });

      it('should create an instance', () => {
        expect(directive).toBeTruthy();
      });

      describe('scroll', () => {

        it('should add class position-fixed', () => {
          spyOnProperty(window, 'innerHeight', 'get').and.returnValue(1000);
          spyOnProperty(document.documentElement, 'scrollTop', 'get').and.returnValue(100);
          directive.scroll(<any>{});
          expect(directive.element.nativeElement.classList.contains('position-fixed')).toBe(true);
        });
    });

В-четвертых, вы должны добавить провайдеровNgModule в вашем module.ts:

import { DOCUMENT } from '@angular/common';
import { N_WINDOW, N_DOCUMENT } from '../options';

export function nWindowFactory() {
  return window;
}

@NgModule({
...
  providers: [
    {provide: N_WINDOW, useFactory: nWindowFactory},
    {provide: N_DOCUMENT, useExisting: DOCUMENT}
  ]
})
...