Skip to content

Commit 85da672

Browse files
author
Andrea Barbasso
committed
[UXP-126] add tests for text-select.directive
1 parent d0c9480 commit 85da672

2 files changed

Lines changed: 48 additions & 10 deletions

File tree

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,62 @@
11
import { TextSelectDirective } from './text-select.directive';
2-
import { ElementRef, NgZone } from '@angular/core';
2+
import { ApplicationRef, ElementRef, NgZone } from '@angular/core';
33
import { TestBed } from '@angular/core/testing';
44

55
describe('TextSelectDirective', () => {
66
let directive: TextSelectDirective;
77
let elementRef: ElementRef;
88
let ngZone: NgZone;
9+
let appRef: ApplicationRef;
910

1011
beforeEach(() => {
1112
TestBed.configureTestingModule({
1213
providers: [
1314
TextSelectDirective,
15+
{ provide: ApplicationRef, useValue: { attachView: () => ({ rootNodes: [{}] }) } },
1416
{ provide: ElementRef, useValue: { nativeElement: document.createElement('div') } },
15-
NgZone
17+
{ provide: NgZone, useValue: new NgZone({}) },
1618
]
1719
});
1820

1921
directive = TestBed.inject(TextSelectDirective);
2022
elementRef = TestBed.inject(ElementRef);
2123
ngZone = TestBed.inject(NgZone);
24+
appRef = TestBed.inject(ApplicationRef);
2225
});
2326

2427
it('should create an instance', () => {
2528
expect(directive).toBeTruthy();
2629
});
30+
31+
it('should set up event listener on ngOnInit', () => {
32+
spyOn(elementRef.nativeElement, 'addEventListener');
33+
directive.ngOnInit();
34+
expect(elementRef.nativeElement.addEventListener).toHaveBeenCalledWith('mousedown', directive.handleMousedown, false);
35+
});
36+
37+
it('should remove event listener on ngOnDestroy', () => {
38+
spyOn(elementRef.nativeElement, 'removeEventListener');
39+
directive.ngOnDestroy();
40+
expect(elementRef.nativeElement.removeEventListener).toHaveBeenCalledWith('mousedown', directive.handleMousedown, false);
41+
});
42+
43+
it('should process selection correctly', () => {
44+
const selection = {
45+
rangeCount: 1,
46+
toString: () => 'test',
47+
getRangeAt: () => ({ getBoundingClientRect: () => ({}) }),
48+
};
49+
spyOn(document, 'getSelection').and.returnValue(selection as any);
50+
spyOn(directive, 'getRangeContainer').and.returnValue(elementRef.nativeElement);
51+
spyOn(elementRef.nativeElement, 'contains').and.returnValue(true);
52+
spyOn(directive, 'createTooltipComponent').and.returnValue({ instance: {}, hostView: {rootNodes: []} } as any);
53+
spyOn(document.body, 'appendChild').and.returnValue({} as Node);
54+
spyOn(appRef, 'attachView').and.returnValue();
55+
56+
directive.processSelection();
57+
58+
expect(directive.hasSelection).toBeTrue();
59+
expect(directive.selectedText).toBe('test');
60+
expect(directive.componentRef).toBeTruthy();
61+
});
2762
});

src/app/directives/text-select/text-select.directive.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class TextSelectDirective implements OnInit, OnDestroy {
2424
hasSelection = false;
2525
selectedText = '';
2626

27-
private componentRef: ComponentRef<any> = null;
27+
componentRef: ComponentRef<any> = null;
2828

2929
// Initialize the directive.
3030
constructor(
@@ -36,20 +36,20 @@ export class TextSelectDirective implements OnInit, OnDestroy {
3636
}
3737

3838
// Clean up when the directive is destroyed.
39-
public ngOnDestroy(): void {
39+
ngOnDestroy(): void {
4040
this.elementRef.nativeElement.removeEventListener('mousedown', this.handleMousedown, false);
4141
document.removeEventListener('mouseup', this.handleMouseup, false);
4242
}
4343

4444
// Set up event listeners when the directive is initialized.
45-
public ngOnInit(): void {
45+
ngOnInit(): void {
4646
this.zone.runOutsideAngular(() => {
4747
this.elementRef.nativeElement.addEventListener('mousedown', this.handleMousedown, false);
4848
});
4949
}
5050

5151
// Get the deepest Element node in the DOM tree that contains the entire range.
52-
private getRangeContainer(range: Range): Node {
52+
getRangeContainer(range: Range): Node {
5353
let container = range.commonAncestorContainer;
5454
while (container.nodeType !== Node.ELEMENT_NODE) {
5555
container = container.parentNode;
@@ -58,7 +58,7 @@ export class TextSelectDirective implements OnInit, OnDestroy {
5858
}
5959

6060
// Handle mousedown events inside the current element.
61-
private handleMousedown = (): void => {
61+
handleMousedown = (): void => {
6262
document.addEventListener('mouseup', this.handleMouseup, false);
6363
};
6464

@@ -68,8 +68,11 @@ export class TextSelectDirective implements OnInit, OnDestroy {
6868
this.processSelection();
6969
};
7070

71+
createTooltipComponent(): ComponentRef<TextSelectionTooltipComponent> {
72+
return createComponent(TextSelectionTooltipComponent, {environmentInjector: this.injector});
73+
}
7174

72-
private processSelection(): void {
75+
processSelection(): void {
7376
const selection = document.getSelection();
7477
const stringSelection = selection.toString().trim();
7578
const previousSelection = this.selectedText;
@@ -88,6 +91,7 @@ export class TextSelectDirective implements OnInit, OnDestroy {
8891
if (!selection.rangeCount || !stringSelection || previousSelection === stringSelection) {
8992
return;
9093
}
94+
console.warn('selection', stringSelection);
9195
let range = selection.getRangeAt(0);
9296
let rangeContainer = this.getRangeContainer(range);
9397
// check if the range container is inside the current element
@@ -98,11 +102,10 @@ export class TextSelectDirective implements OnInit, OnDestroy {
98102
this.zone.runGuarded(() => {
99103
this.hasSelection = true;
100104
if (this.componentRef === null) {
101-
this.componentRef = createComponent(TextSelectionTooltipComponent, {environmentInjector: this.injector});
105+
this.componentRef = this.createTooltipComponent();
102106
this.appRef.attachView(this.componentRef.hostView);
103107

104108
const domElem = (this.componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
105-
106109
document.body.appendChild(domElem);
107110

108111
this.componentRef.instance.elementRectangleLeft = viewportRectangle.left + window.scrollX;

0 commit comments

Comments
 (0)