【问题标题】:How to simulate mouse events to test Directive in Angular如何模拟鼠标事件以在 Angular 中测试指令
【发布时间】:2020-09-16 18:12:41
【问题描述】:

我正在尝试测试一个可调整大小的列指令,该指令侦听鼠标事件,如 mouseup、mousemove、mousedown。

resize-column.directive.ts

import { Directive, OnInit, Renderer2, Input, ElementRef, HostListener } from "@angular/core";

@Directive({
  selector: "[resizeColumn]"
})
export class ResizeColumnDirective implements OnInit {

  @Input() index: number;    
  private startX: number;    
  private startWidth: number;    
  private column: HTMLElement;    
  private table: HTMLElement;    
  private pressed: boolean;

  constructor(private renderer: Renderer2, private el: ElementRef) {
    this.column = this.el.nativeElement;
  }

  ngOnInit() {
    if (this.resizable) {
      const row = this.renderer.parentNode(this.column);
      this.table = this.renderer.parentNode(row);

      const resizer = this.renderer.createElement("span");
      this.renderer.addClass(resizer, "resize-holder");
      this.renderer.appendChild(this.column, resizer);
      this.renderer.listen(resizer, "mousedown", this.onMouseDown);
    }
  }

  onMouseDown = (event: MouseEvent) => {
    this.pressed = true;
    this.startX = event.pageX;
    this.startWidth = this.column.offsetWidth;
  };

  @HostListener('document: mousemove')
  onMouseMove(event: MouseEvent) {
    const offset = 35;
    if (this.pressed && event.buttons) {
      this.renderer.addClass(this.table, "resizing");

      // Calculate width of column
      let width =
        this.startWidth + (event.pageX - this.startX - offset);

      const tableCells = Array.from(this.table.querySelectorAll(".custom-row")).map(
        (row: any) => row.querySelectorAll(".custom-cell").item(this.index)
      );

      // Set table header width
      this.renderer.setStyle(this.column, "max-width", `${width}px`);
      this.renderer.setStyle(this.column, "flex-basis", `${width}px`);

      // Set table cells width
      for (const cell of tableCells) {
        this.renderer.setStyle(cell, "max-width", `${width}px`);
        this.renderer.setStyle(cell, "flex-basis", `${width}px`);
      }
    }
  };

  @HostListener('document: mouseup')
  onMouseUp(){
    if (this.pressed) {
      this.pressed = false;
      this.renderer.removeClass(this.table, "resizing");
    }
  };
}

我想为此指令创建单元测试,但我无法模拟鼠标事件。我正在使用 triggerEventHandler 来处理事件,但是在模拟 mousedown 和 mousemove 后我无法更新 max-width 和 flex-basis 的值。

resize-column.directive.spec.ts

import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ResizeColumnDirective } from './resize-column.directive';

@Component({
    template: `
    <custom-table>
        <custom-row>
            <custom-header *ngFor="let column of displayedColumns; let i = index"
                 resizeColumn [index]="i">
                {{column.label}}
            </custom-header>
        </custom-row>
        <custom-row *ngFor="let row of rowDatas">
            <custom-cell *ngFor="let column of displayedColumns">{{row[column.field]}}
            </custom-cell>
        </custom-row>
    </custom-table>`
})
class TestComponent {
    displayedColumns = [
        { field: 'name', label: 'Name' },
        { field: 'sex', label: 'Sex' },
        { field: 'age', label: 'Age' }
    ];

    rowDatas = [{
        name: 'Albert',
        sex: 'M',
        age: '20'
    }.....];
}

describe('RsizableDirective', () => {
    let component: TestComponent;
    let fixture: ComponentFixture<TestComponent>;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [ResizeColumnDirective, TestComponent, table component components....]
        });

        fixture = TestBed.createComponent(TestComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create component', () => {
        expect(component).toBeDefined();
    });

    it('should update the flex and max-width value on mouse move', () => {
        const headerEl = fixture.debugElement.query(By.css('custom-header'));
        console.log(headerEl.nativeElement.style.flex);
        headerEl.triggerEventHandler('mousedown', { pageX: 50 });
        headerEl.triggerEventHandler('mousemove', { pageX: 150 });
        fixture.detectChanges();
        console.log(headerEl.nativeElement.style.flex);
    });
});

请帮助我如何测试这个指令,并建议有没有更好的方法来为此编写测试,因为我是 Jasmine 的新手。提前致谢。

【问题讨论】:

    标签: javascript angular typescript jasmine karma-jasmine


    【解决方案1】:

    尝试使用

    headerEl.dispatchEvent(new MouseEvent('mousemove', {clientX: 50, clientY: 150}));
    

    headerEl.dispatchEvent(new Event('mousemove', {pageX: 50, pageY: 150}));
    

    更新:

    我检查了你的代码,这里有两点:

    1. 你应该使用document.dispatchEvent(new MouseEvent('mousemove', {clientX: 50, clientY: 150, buttons: 1}))来模拟鼠标移动事件
    2. '$event' 添加到您的@HostListener 以防止处理程序中未定义
    @HostListener('document: mousemove', ['$event'])
    onMouseMove(event: MouseEvent) {
      const offset = 35;
      if (this.pressed && event.buttons) {
        //your code
      }
    };
    

    请记住,变量 pressed 应该是 true 以使您的代码正常工作

    【讨论】:

    • 在mousemove事件触发前后flex的值仍然没有更新
    • 哦,请尝试从文档级别发送事件(没有注意到您有@HostListener('document: mousemove'))。 document.dispatchEvent(new MouseEvent('mousemove', {clientX: 50, clientY: 150}));
    • 我也尝试过使用文档,但仍然没有更新 flex 值。我是否在正确的地方检查 headerEl.nativeElement.style.flex...?
    • 你可以在测试执行期间调试你的 onMouseMove(event: MouseEvent) 方法,这个“if (this.pressed && event.buttons)”可能是个问题
    • @asif905: 你在做fixture.detectChanges()
    猜你喜欢
    • 2017-10-25
    • 2017-11-04
    • 2019-11-11
    • 2020-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多