Angular 5中的HostListener滚动测试

时间:2018-05-29 15:51:43

标签: javascript scroll resize angular5

如何在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 :(得分:3)

我发现了怎么做!您需要将窗口注入您正在使用它的位置,以便在测试期间可以模拟它。

首先你必须创建一个文件(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);
        });
    });

第四,你必须在你的module.ts中添加提供者到NgModule:

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}
  ]
})