You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ElementRef.nativeElement.querySelector()编写Angular单元测试?

解决方案

核心问题分析

现有测试代码存在两个关键错误:

  1. 测试模块声明时使用了通用的Component而非实际要测试的SectionItemCrudComponent,导致Angular无法正确识别组件依赖,抛出No provider错误。
  2. 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();
    });
  });
});

关键说明

  1. 修正组件声明:将declarations: [ Component ]改为SectionItemCrudComponent,确保测试模块正确识别组件及其依赖。
  2. 完整Mock行为:让querySelector返回带有focus spy的对象,同时支持动态切换返回值,覆盖元素存在/不存在两种业务场景。
  3. 补全依赖变量:组件的childAdded方法依赖sectionIndex和sectionItemIndex生成元素ID,测试时必须给这两个变量赋值,否则ID拼接会出错。
  4. 验证调用逻辑:通过获取Mock实例,检查querySelector和focus方法的调用情况,确保组件逻辑符合预期。

内容的提问来源于stack exchange,提问作者AneeshPutturi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 06:25:34