I have a directive that changes height of the text within element on window resize:
import {Directive, ElementRef, Renderer2, HostListener} from '@angular/core';
@Directive({selector: '[fittext]'})
export class FittextDirective {
constructor(private element: ElementRef, private renderer: Renderer2) { }
public changeFontSize(): void {
const htmlElement: HTMLElement = this.element.nativeElement;
const elemDims = htmlElement.getBoundingClientRect();
const height = elemDims.height;
// Set new font size on element
this.renderer.setStyle(htmlElement, 'font-size', `${height / 2}px`);
}
@HostListener('window:resize')
public onResize(): void {
this.changeFontSize();
}
}
And I'm trying to test it using custom wrapper component and by dispatching resize event on window.
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FittextDirective } from './fittext.directive';
import { Component, ViewChild, ElementRef } from '@angular/core';
import { By } from '@angular/platform-browser';
@Component({
template: `
<div #div fittext>{{ text }}</div>
<style>
div {
height: 100vh;
width: 100vw;
font-size: 100%;
}
</style>
`
})
class TestComponent {
@ViewChild('div') div: ElementRef;
public text: string = 'This is test string';
}
describe('FittextDirective', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TestComponent,
FittextDirective
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
fit('should trigger on resize', () => {
const {height, width} = component.div.nativeElement.getBoundingClientRect();
const fontSize = component.div.nativeElement.style.fontSize;
window.dispatchEvent(new Event('resize'));
fixture.detectChanges()
const resizedElement = fixture.debugElement.query(By.directive(FittextDirective));
const {newHeight, newWidth} = resizedElement.nativeElement.getBoundingClientRect();
const newFontSize = resizedElement.nativeElement.style.fontSize;
expect(newHeight).not.toEqual(height);
expect(newWidth).not.toEqual(width);
expect(newFontSize).not.toEqual(fontSize);
});
});
However, tests report font sizes to be ''
, and height and width after resize (i.e. newHeight
and newWidth
) to be undefined
. Why is the font size an empty string, even though the font should be sized to match the div? And why are the height and width after window resize undefined? I'm using headless chrome for testing so I can't use window.resizeTo(width, height)
method.
Edit 1: After suggestion by Alex K
I've changed newHeight
and newWidth
to:
const newHeight = resizedElement.nativeElement.getBoundingClientRect().height;
const newWidth = resizedElement.nativeElement.getBoundingClientRect().width;
However, it seems that after resize event, that windows is not resized (I get the error Expected 600 not to equal 600.
and Expected 785 not to equal 785.
). I've also changed the style between tags, to style in the component attribute i.e. styles
attribute, but still, the fontSize
is reported to be ''
(or any style for that matter).
Edit 2: For some strange reason styles can only be fetched using window.getComputedStyle()
(see this). Now, I get the size of the font, but it does not change after resize.
const styles = window.getComputedStyle(element.nativeElement);
const fontSize = styles.fontSize;
...
const newStyles = window.getComputedStyle(resizedElement.nativeElement);
const newFontSize = newStyles.fontSize;
Edit 3: As suggested, I've faked dimensions with spyOn
, however, this does not resize fonts.
spyOn(component.div.nativeElement, 'getBoundingClientRect')
.and.returnValue({height: height / 2, width: width / 2});
window.dispatchEvent(new Event('resize'));
fixture.detectChanges()