angular - 使用 popper.js 的指令测试组件失败
问题描述
我确实在 Popper.js 上创建了一个包装器指令,如下所示:
import { Directive, ElementRef, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import Popper, { Placement, PopperOptions } from "popper.js";
import { Subject, merge, fromEvent } from 'rxjs';
import { filter, pluck, takeUntil } from 'rxjs/operators';
@Directive({
selector: "[espTooltip]"
})
export class TooltipDirective implements OnInit, OnDestroy {
// The hint to display
@Input() target: HTMLElement;
// Its positioning (check docs for available options)
@Input() placement?: Placement;
// Optional hint target if you desire using other element than specified one
@Input() appPopper?: HTMLElement;
@Input() text = '';
// The popper instance
private popper: Popper;
private readonly defaultConfig: PopperOptions = {
placement: "bottom",
removeOnDestroy: true,
modifiers: {
arrow: {
element: ".popper__arrow"
}
},
eventsEnabled: false
};
private readonly destroy$ = new Subject<void>();
constructor(
private readonly el: ElementRef,
private readonly renderer: Renderer2
) { }
ngOnInit(): void {
// An element to position the hint relative to
const reference = this.appPopper ? this.appPopper : this.el.nativeElement;
this.popper = new Popper(reference, this.target, {
...this.defaultConfig,
placement: this.placement || this.defaultConfig.placement
});
this.renderer.setStyle(this.target, "display", "none");
merge(
fromEvent(reference, "mouseenter"),
fromEvent(reference, "mouseleave")
)
.pipe(
filter(() => this.popper != null),
pluck("type"),
takeUntil(this.destroy$)
)
.subscribe((e: any) => this.mouseHoverHandler(e));
}
ngOnDestroy(): void {
if (!this.popper) {
return;
}
this.popper.destroy();
this.destroy$.next();
this.destroy$.complete();
}
private mouseHoverHandler(e: string): void {
if (e === "mouseenter") {
this.renderer.removeStyle(this.target, "display");
this.popper.enableEventListeners();
this.popper.scheduleUpdate();
} else {
this.renderer.setStyle(this.target, "display", "none");
this.popper.disableEventListeners();
}
}
}
然后在组件中使用了指令,并且在该组件测试失败并出现以下错误之后:
TypeError: popper_js_1.default is not a constructor
41 | const reference = this.appPopper ? this.appPopper : this.el.nat
iveElement;
42 |
> 43 | this.popper = new Popper(reference, this.target, {
| ^
44 | ...this.defaultConfig,
45 | placement: this.placement || this.defaultConfig.placement
46 | });
测试设置:
@Directive({
selector: '[espTooltip]'
})
export class MockTooltipDirective {
@Input() target: HTMLElement;
// Its positioning (check docs for available options)
@Input() placement?: Popper.Placement;
// Optional hint target if you desire using other element than specified one
@Input() appPopper?: HTMLElement;
@Input() text = '';
private popper: any;
ngOnInit(): void {
// An element to position the hint relative to
this.popper = new Popper({clientHeight: 0, clientWidth: 0, getBoundingClientRect: jest.fn()}, null, {});
}
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
SharedModule
],
declarations: [
MockTooltipDirective,
PanelComponent,
ActiveJobsListComponent
],
})
.compileComponents();
}));
我在这里做错了什么?
解决方案
我认为您的实际实现TooltipDirective
是在您的SharedModule
并且您正在导入它,然后 Angular 将其用作实际实现。
我要做的是依靠NO_ERRORS_SCHEMA
它忽略未在TestBed.configureTestingModule
.
像这样的东西:
import { NO_ERRORS_SCHEMA } from '@angular/core';
....
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
// SharedModule is removed
],
declarations: [
// MockTooltipDirective is removed
PanelComponent,
ActiveJobsListComponent,
// Add all components and directives that your component relies on for the unit test
// For instance, are you going to click on a button nested inside of a child component of this component's unit test
],
Providers: [
// Add all providers from SharedModule here, I would mock them if I were you
],
schemas: [NO_ERRORS_SCHEMA],
})
.compileComponents();
}));
这样,您就可以移除您的MockTooltipDirective
(大赢家),然后只依靠NO_ERRORS_SCHEMA
. Angular 将忽略所有espTooltip
绑定。此外,删除SharedModule
中的imports
,您的单元测试应该更快。
推荐阅读
- sql-server - 根据兄弟值查询 XML 数据以获取信息
- javascript - 如何在本机反应中切换来自地图迭代的单个元素?
- angular - 无法设置未定义或空引用的属性
- ios - 自定义 cocoapod 找不到 swift 文件
- python - 无法安装龙卷风
- ruby - 终止所有“子”到主线程的正确方法是什么
- excel - 如何在一列中查找文本值并将值复制/填充到新列,直到找到第二个值,然后使用 vba 重复新值
- r - Facet wrap 和填充点图
- amazon-web-services - 如何使用 TerraForm 创建部署 lambda 函数的管道
- c# - 使用自定义命名策略生成 Swagger 定义的问题