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

Angular 2 Jasmine中含*ngIf异步调用的HTML元素单元测试

没问题,我来帮你搞定这个带*ngIf和async管道的Angular组件单元测试,咱们分场景一步步来实现:

核心测试目标

我们需要验证两个核心场景:

  • 当NgRx Store返回有效搜索结果时,目标<div>和子组件<app-client-list>正确渲染,且clients输入属性传递正确
  • 当Store中无搜索结果时,目标<div>不渲染
准备工作:Mock依赖(隔离测试)

单元测试要避免依赖真实子组件和NgRx Store的复杂逻辑,所以我们先创建一个Mock版本的<app-client-list>,并使用NgRx的provideMockStore模拟Store:

// 在你的测试文件顶部,创建Mock子组件
import { Component, Input } from '@angular/core';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { YourComponent } from './your-component.component'; // 替换成你的组件类名
import { By } from '@angular/platform-browser';

@Component({
  selector: 'app-client-list',
  template: '', // 空模板足够满足单元测试需求
  inputs: ['clients']
})
class MockClientListComponent {
  @Input() clients: any[]; // 和真实组件的输入属性保持一致
}

describe('YourComponent', () => {
  let component: YourComponent;
  let fixture: ComponentFixture<YourComponent>;
  let store: MockStore;
  const initialState = {
    // 匹配你的NgRx状态结构,比如这里假设搜索结果存在于clients.searchResults下
    clients: {
      searchResults: []
    }
  };

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [YourComponent, MockClientListComponent], // 声明你的组件和Mock子组件
      providers: [
        provideMockStore({ initialState }) // 提供Mock Store并设置初始状态
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(YourComponent);
    component = fixture.componentInstance;
    store = TestBed.inject(MockStore);
  });
});
测试场景实现

场景1:有搜索结果时,渲染目标元素并传递正确数据

it('should render datalist div and app-client-list with correct clients when search results exist', () => {
  // 准备测试用的模拟客户数据
  const mockSearchResults = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ];

  // 更新Mock Store的状态,让selector返回模拟数据
  store.setState({
    ...initialState,
    clients: { searchResults: mockSearchResults }
  });

  fixture.detectChanges(); // 触发Angular变更检测

  // 验证目标div是否存在
  const dataListDiv = fixture.debugElement.query(By.css('#mydata'));
  expect(dataListDiv).toBeTruthy();

  // 验证子组件是否渲染,且输入属性clients正确传递
  const clientListComp = fixture.debugElement.query(By.css('#clientDataTable1'))
    .componentInstance as MockClientListComponent;
  expect(clientListComp.clients).toEqual(mockSearchResults);
});

场景2:无搜索结果时,不渲染目标元素

it('should NOT render datalist div when no search results are available', () => {
  // 确保Store中的搜索结果为空(或者undefined,根据你的业务逻辑调整)
  store.setState({
    ...initialState,
    clients: { searchResults: [] }
  });

  fixture.detectChanges();

  // 验证目标div不存在
  const dataListDiv = fixture.debugElement.query(By.css('#mydata'));
  expect(dataListDiv).toBeFalsy();
});

可选:验证searchData方法触发Store动作

如果需要验证searchData方法正确触发了NgRx的搜索动作,可以添加这个测试:

it('should dispatch search action when searchData is called', () => {
  const dispatchSpy = spyOn(store, 'dispatch');
  const testSearchQuery = 'test client';

  // 调用组件的searchData方法
  component.searchData(testSearchQuery);

  // 验证是否dispatch了正确的动作(替换成你实际的搜索Action)
  expect(dispatchSpy).toHaveBeenCalledWith(
    // new SearchClientsAction(testSearchQuery)
  );
});
注意事项
  • 确保你的clientSearchResults$ observable是通过NgRx selector创建的,这样Mock Store的状态变更才能正确反映到这个流中
  • 如果searchData方法包含异步逻辑(比如HTTP请求),因为我们用了Mock Store,不需要等待真实异步,直接设置Store状态即可
  • 变更检测fixture.detectChanges()是关键,它会让Angular处理async管道的订阅和视图更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:01:21