使用@HostLinener'window:scroll'的Angest Jest测试指令

问题描述

问题:我想测试一个指令,该指令应该在'window:scroll'事件后更改元素的样式,但不知道如何触发该事件

指令:

@Directive({
    selector: '[directiveSelector]',})
export class Directive {
    private breakpointOffset: number;
    private fixed = false;

    constructor(
        private readonly elementRef: ElementRef,) {}

    ngAfterViewInit() {
            //fix the element when scrollTop reaches past element's offsetTop
            this.breakpointOffset = this.elementRef.nativeElement.offsetTop;
    }

    @HostListener('window:scroll')
    addScrollTrigger() {
        if (!this.fixed && window.pageYOffset > this.breakpointOffset) {
            this.elementRef.nativeElement.setAttribute(
                'style','position: fixed;
            );
            this.fixed = true;
        }

        if (this.fixed && window.pageYOffset <= this.breakpointOffset) {
            this.elementRef.nativeElement.setAttribute('style','');
            this.fixed = false;
        }
    }
}

我尝试过的事情:

@Component({
    template: ` <div #container directive></div> `,})
class TestComponent {
    @ViewChild('container') container: ElementRef;
}

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

    beforeEach(async(() => {
        Testbed.configureTestingModule({
            declarations: [TestComponent,Directive],}).compileComponents();

        fixture = Testbed.createComponent(TestComponent);
        component = fixture.componentInstance;
    }));

    describe('addScrollTrigger',() => {
        it('sets fixed style',() => {
            //Trigger scroll event?

            expect(component.container.nativeElement.styles).toEqual(....);
        });
    });
});

在我的测试中,我尝试使用带有带有该指令的div的模板创建组件。我无法执行的操作是触发滚动事件,因为我必须直接访问该指令并且不能调用“ addScrollTrigger”功能,可以吗?

解决方法

这是解决方案:

@Component({
    template: ` <div #container directive></div> `,})
class TestComponent {
    @ViewChild('container',{ static: true }) container: ElementRef;
}

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

    beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
            declarations: [TestComponent,Directive],}).compileComponents();

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

        // mocking the offsetParent
        Object.defineProperty(HTMLElement.prototype,'offsetParent',{
            get: function () {
                return { offsetTop: 100 };
            },});

        // mocking the offsetTop
        Object.defineProperty(HTMLElement.prototype,'offsetTop',{
            get: function () {
                return 50;
            },});

        fixture.detectChanges();
    }));

    describe('addScrollTrigger',() => {
        it('sets fixed style',() => {
            //Trigger window scroll event 
            window.dispatchEvent(new Event('scroll'));
            fixture.detectChanges();
            
            expect(component.container.nativeElement.styles).toEqual(....);
        });
    });
});