Angular10属性指令Mock失效:无法获取模板元素(nativeElement为空)
解决Angular Jasmine测试中Mock结构型指令不生效的问题
问题根源
你写的MockAnnoyingDirective只是普通属性指令,但原annoyingDirective是结构型指令(使用*语法糖,本质是控制视图容器是否渲染内部模板)。普通属性指令不会处理模板的渲染逻辑,所以即使替换了原指令,内部的.class2元素依然不会被渲染,导致查询时返回null。
另外,既然已经用Mock指令完全替换了原指令,原指令依赖的Store不需要额外Mock——原指令根本不会被加载到测试环境中。
解决方案:Mock结构型指令的核心逻辑
修改Mock指令,让它主动渲染模板内容。结构型指令需要注入ViewContainerRef和TemplateRef,在初始化时创建嵌入式视图,确保内部模板被渲染。
修改后的Mock指令代码
@Directive({ selector: '[annoyingDirective]' }) export class MockAnnoyingDirective implements OnInit { @Input() input_data1: string[]; @Input('input_data2') input_data2: boolean = false; // 注入结构型指令必备的两个依赖 constructor( private viewContainerRef: ViewContainerRef, private templateRef: TemplateRef<any> ) {} ngOnInit(): void { // 主动渲染模板,忽略原指令的权限判断逻辑 this.viewContainerRef.createEmbeddedView(this.templateRef); } }
测试模块配置保持不变
你的TestBed配置已经正确声明了MockAnnoyingDirective,不需要额外修改:
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MatSlideToggleModule, TranslateModule.forRoot()], declarations: [ComponentToTest, MockAnnoyingDirective], providers: [/* 你的其他提供者 */] }).compileComponents(); });
验证测试用例
现在执行测试,fixture.debugElement.query(By.css(".class2"))就能正确获取到元素,不会再返回null:
describe('slide-toggle-selection', () => { it('should show the div', () => { const forTest = fixture.debugElement.query(By.css(".class2"))?.nativeElement; expect(forTest).toBeTruthy(); }); });
补充说明
Angular的*语法糖会把结构型指令转换成<ng-template>包裹的形式,比如原模板中的:
<div *annoyingDirective="input_data1; input_data2: true" class="class1"> <!-- 内部内容 --> </div>
会被Angular编译为:
<ng-template [annoyingDirective]="input_data1" [input_data2]="true"> <div class="class1"> <!-- 内部内容 --> </div> </ng-template>
结构型指令的核心职责就是控制这个ng-template是否被渲染到视图容器中,所以你的Mock指令必须实现这个逻辑才能让内部内容显示。
内容的提问来源于stack exchange,提问作者Evelyn Zouras
相关产品推荐
相关产品推荐

