如何为ElementRef.nativeElement.querySelector()编写Angular单元测试?
解决方案
核心问题分析
现有测试代码存在两个关键错误:
- 测试模块声明时使用了通用的
Component而非实际要测试的SectionItemCrudComponent,导致Angular无法正确识别组件依赖,抛出No provider错误。 - Mock的
ElementRef未模拟完整的元素行为,且未处理组件中用到的sectionIndex和sectionItemIndex变量,导致测试逻辑不完整。
修正后的测试代码
import { ElementRef } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { SectionItemCrudComponent } from './section-item-crud.component'; // 模拟带focus方法的DOM元素 const mockFocusElement = { focus: jasmine.createSpy('focus') }; // 完善ElementRef的Mock实现 class MockElementRef implements ElementRef { nativeElement = { querySelector: jasmine.createSpy('querySelector').and.returnValue(mockFocusElement) }; } describe('SectionItemCrudComponent', () => { let component: SectionItemCrudComponent; let fixture: ComponentFixture<SectionItemCrudComponent>; let mockElementRef: MockElementRef; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [SectionItemCrudComponent], // 替换为实际组件类 providers: [ { provide: ElementRef, useClass: MockElementRef } ], imports: [TranslateModule.forRoot()] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(SectionItemCrudComponent); component = fixture.componentInstance; // 获取注入的Mock实例,用于后续验证 mockElementRef = TestBed.inject(ElementRef) as MockElementRef; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); describe('childAdded function', () => { it('should trigger focus on the target element when found', () => { // 给组件的依赖变量赋值,确保ID拼接正确 component.sectionIndex = 1; component.sectionItemIndex = 0; component.childAdded(); // 验证querySelector传入了预期的ID参数 expect(mockElementRef.nativeElement.querySelector).toHaveBeenCalledWith('#id1_1'); // 验证focus方法被调用 expect(mockFocusElement.focus).toHaveBeenCalled(); }); it('should do nothing if target element does not exist', () => { // 修改Mock返回值,模拟元素不存在的场景 mockElementRef.nativeElement.querySelector.and.returnValue(null); component.sectionIndex = 1; component.sectionItemIndex = 0; component.childAdded(); expect(mockElementRef.nativeElement.querySelector).toHaveBeenCalledWith('#id1_1'); // 验证focus方法未被调用 expect(mockFocusElement.focus).not.toHaveBeenCalled(); }); }); });
关键说明
- 修正组件声明:将
declarations: [ Component ]改为SectionItemCrudComponent,确保测试模块正确识别组件及其依赖。 - 完整Mock行为:让
querySelector返回带有focusspy的对象,同时支持动态切换返回值,覆盖元素存在/不存在两种业务场景。 - 补全依赖变量:组件的
childAdded方法依赖sectionIndex和sectionItemIndex生成元素ID,测试时必须给这两个变量赋值,否则ID拼接会出错。 - 验证调用逻辑:通过获取Mock实例,检查
querySelector和focus方法的调用情况,确保组件逻辑符合预期。
内容的提问来源于stack exchange,提问作者AneeshPutturi
相关产品推荐
相关产品推荐

