使用Jasmine单元测试时无法模拟keyup事件更新过滤值
问题:过滤值更新的Jasmine单元测试失败
我设置过滤字段初始值为空,触发keyup事件后期望它更新为过滤组件的当前值,但编写的Jasmine单元测试始终获取不到更新后的值,只能拿到初始值。
测试代码
describe('Component', () => { let component: Component1; let fixture: ComponentFixture<Component1>; let mockDialog: MatDialog; let mockDataService: Service1; let mockToastr: ToastrService; let mockPaginator: MatPaginator; let mockSort: MatSort; let mockFilterElement: ElementRef<HTMLInputElement>; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [Component1], imports: [MatPaginatorModule], providers: [ { provide: MatDialog, useValue: jasmine.createSpyObj('MatDialog', ['open']) }, { provide: Service1, useValue: jasmine.createSpyObj('Service1', ['fetchData', 'update', 'getAll']) }, { provide: ToastrService, useValue: jasmine.createSpyObj('ToastrService', ['success', 'error']) }, ], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(Component1); component = fixture.componentInstance; mockDialog = TestBed.inject(MatDialog); mockDataService = TestBed.inject(Service1); mockToastr = TestBed.inject(ToastrService); mockPaginator = jasmine.createSpyObj('MatPaginator', ['previousPage', 'nextPage']); mockSort = jasmine.createSpyObj('MatSort', ['sort']); mockFilterElement = new ElementRef<HTMLInputElement>(document.createElement('input')); component.dialog = mockDialog; component.dataService = mockDataService; component.paginator = mockPaginator; component.sort = mockSort; component.filter = mockFilterElement; component.dataSource = new ExampleDataSource(null, mockPaginator, mockSort); fixture.detectChanges(); }); it('should handle filter changes', async () => { const filterValue = 'test'; mockFilterElement.nativeElement.value = filterValue; await component.ngOnInit(); const event = new Event('keyup'); mockFilterElement.nativeElement.dispatchEvent(event); expect(component.dataSource.filter).toBe(filterValue); }); // More Tests... });
组件代码
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild('filter', { static: true }) filter: ElementRef; ngOnInit(): void { Observable.fromEvent(this.filter.nativeElement, 'keyup').pipe( debounceTime(150), distinctUntilChanged() ).subscribe(() => { if (!this.dataSource) { return; } this.dataSource.filter = this.filter.nativeElement.value }); }
问题原因
- 重复调用ngOnInit:
fixture.detectChanges()执行时已经触发了组件的ngOnInit,手动调用await component.ngOnInit()会重复绑定keyup事件,且ngOnInit是同步方法,await无实际作用。 - 防抖未等待:组件里用了
debounceTime(150),单元测试触发keyup事件后直接断言,此时防抖还未完成,订阅回调尚未执行,因此dataSource.filter还是初始值。
修复方案
使用Jasmine的fakeAsync和tick()模拟时间流逝,等待防抖完成,同时移除不必要的await component.ngOnInit()调用:
修改后的测试用例:
import { fakeAsync, tick } from '@angular/core/testing'; // ... 其他代码 it('should handle filter changes', fakeAsync(() => { const filterValue = 'test'; mockFilterElement.nativeElement.value = filterValue; const event = new Event('keyup'); mockFilterElement.nativeElement.dispatchEvent(event); // 等待防抖时间结束,触发订阅回调 tick(150); // 触发变更检测确保组件状态同步(按需添加) fixture.detectChanges(); expect(component.dataSource.filter).toBe(filterValue); }));
内容的提问来源于stack exchange,提问作者Kenzo_Gilead
相关产品推荐
相关产品推荐

