简体   繁体   English

如何使用Renderer2测试指令?

[英]How test directive with Renderer2?

I have created a small directive that prevents default of event(s) passed to it. 我创建了一个小指令,以防止传递给它的默认事件。

@Directive({
    selector: '[sPreventDefault]'
})
export class PreventDefaultDirective {
    private events: (() => void)[] = [];
    @Input('sPreventDefault') set listenOn(events: string | string[]) {
        this.removeListeners();

        if (typeof events == 'string') {
            events = [events];
        }
        this.registerEventListener(
            events,
            e => {
                if (e instanceof Event) {
                    e.stopPropagation();
                } else {
                    e.srcEvent.stopPropagation();
                }
            },
        );
    }

    constructor(private elementRef: ElementRef<HTMLElement>, private renderer: Renderer2) {
        super(elementRef, renderer);
    }

    protected registerEventListener(listenOn: string[], eventListener: (e: Event | HammerJSEvent) => void): void {
        this.events = listenOn.map(eventName => {
            return this.renderer.listen(this.elementRef.nativeElement, eventName, eventListener);
        });
    }
    protected removeListeners(): void {
        this.events.forEach(dispose => dispose());
        this.events = [];
    }
}

Test suit 测试服

@Component({
    selector: 'test-host',
    template: `<div [sPreventDefault]="events">`,
})
class TestHostComponent {
    @ViewChild(PreventDefaultDirective) directive!: PreventDefaultDirective;
    @Input() events: PreventDefaultDirective['listenOn'] = [];
}

fdescribe('PreventDefaultDirective', () => {
    let host: TestHostComponent;
    let hostElement: DebugElement;
    let fixture: ComponentFixture<TestHostComponent>;
    let directive: PreventDefaultDirective;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [
                TestHostComponent,
                PreventDefaultDirective,
            ],
        }).compileComponents();

        fixture = TestBed.createComponent(TestHostComponent);
        hostElement = fixture.debugElement;
        host = fixture.componentInstance;
        directive = host.directive;
    }));

    it('should create an instance', () => {
        host.events = ['testEvent'];
        fixture.detectChanges();
        expect(directive).toBeTruthy();
    });

    it('should add listener', () => {
        host.events = ['testEvent'];
        fixture.detectChanges();

        //  DebugElement.listeners is null
        expect(hostElement.listeners.length).toBe(1);
        expect(hostElement.listeners.map(l => l.name)).toBe(host.events);
    });
});

My problem is, that DebugElement , does not seems to know about events registered via Renderer2.listen method. 我的问题是, DebugElement似乎不了解通过Renderer2.listen方法注册的事件。 What is the right way to test this? 什么是正确的测试方法?

Ok since got interested I checked some things but it won't be straight answer or even solution to your problem although you can find something useful. 好吧,自从有兴趣以来,我检查了一些事情,尽管您可以找到有用的东西,但它不是直截了当的答案,甚至也无法解决您的问题。

It looks like hostElement.listeners points to event listeners added by @HostListener decorator, you can easily check that. 看起来hostElement.listeners指向@HostListener装饰器添加的事件侦听器,您可以轻松地进行检查。 I've also try to find way to retrieve listeners but without success. 我也尝试寻找方法来检索侦听器,但没有成功。

What I would do here is to check whenever renderer.listen was called and leave implementation behind - this way could be wrong for testing higher than "unit tests" since you want to check if this really works but for unit it should be fine. 我在这里要做的是检查何时调用renderer.listen并把实现留在后面-这种方式对于高于“单元测试”的测试可能是错误的,因为您要检查这是否确实有效,但对于单元来说应该没问题。 If you want to spy on Renderer2 you can do this: 如果要监视Renderer2 ,可以执行以下操作:

const renderer = fixture.componentRef.injector.get(Renderer2);
const listenSpy = spyOn(renderer, 'listen');
expect(listenSpy).toHaveBeenCalled();

Edit 1: Since provided way of getting Renderer2 is deprecated this should be used: 编辑1:由于不建议使用提供Renderer2方式,因此应使用:

const renderer = fixture.componentRef.injector.get(Renderer2 as Type<Renderer2>);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM