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
相关产品推荐
相关产品推荐

