简体   繁体   English

Angular 5中的HostListener滚动测试

[英]HostListener scroll testing in Angular 5

How do I test scroll in Angular 5? 如何在Angular 5中测试滚动? How to mock window in tests? 如何在测试中模拟窗口?

This is my code: 这是我的代码:

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');
    }
  }
}

Works fine, but I can't figure out how do I test it. 工作正常,但我不知道如何测试。

I found out how to do that! 我发现了该怎么做! You need to inject window into the place you're using it, so that during testing you can mock it. 您需要将窗口注入到使用它的位置,以便在测试期间可以对其进行模拟。

First you have to create a file (options.ts) an write this: 首先,您必须创建一个文件(options.ts),并编写以下代码:

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

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

Second you have to inject window in your directive/component: 其次,您必须在指令/组件中注入窗口:

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) {...}
    }

Third you can use that in tests like that: 第三,您可以在类似的测试中使用它:

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

Fourth you have to add providers to NgModule in your module.ts: 第四,必须在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}
  ]
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM