I am currently exploring the functionality of a column resizable directive that relies on mouse events such as mouseup, mousemove, and 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");
}
};
}
I am looking to create unit tests for this directive but I am encountering difficulties in simulating mouse events. I have tried using triggerEventHandler to handle events but have not been successful in updating the values of max-width and flex-basis after simulating mousedown and mousemove events.
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('ResizableDirective', () => {
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 the component successfully', () => {
expect(component).toBeDefined();
});
it('should correctly update the flex and max-width values 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);
});
});
I would appreciate guidance on how to effectively test this directive and welcome suggestions on alternative methods to write tests for this, as I am relatively new to Jasmine. Thank you in advance.