Angular Material MatSort单元测试中排序未更新DOM问题
问题分析与解决方案
你遇到的问题是:Angular Material的MatTable在单元测试中按年龄降序排序时,结果与预期相反,但实际应用中功能正常。核心原因是测试流程中,MatSort与MatTableDataSource的绑定时机不匹配,导致排序逻辑未正确触发。
问题根源
在测试用例中,你是在组件初始化完成后才设置displayedColumns和数据源,而组件的ngAfterViewInit在第一次fixture.detectChanges()时就已经执行,此时表格还未渲染列,MatSort并未与数据源建立有效绑定。后续设置列和数据后,排序操作无法正确驱动数据源重新排序。
解决方案
方案1:重新绑定Sort与数据源
在测试中设置完列和数据后,手动将sort重新赋值给数据源,确保列渲染后排序逻辑生效:
it('should render sorted data by age descending', async () => { component.displayedColumns = [{ value: 'name', label: 'Name' }, { value: 'age', label: 'Age' }]; component._dataSource.data = [{ name: 'Jane', age: 25 }, { name: 'John', age: 30 }]; fixture.detectChanges(); // 重新绑定sort到数据源,确保列渲染后排序逻辑生效 component._dataSource.sort = component.sort; component.sort?.sort({ id: 'age', start: 'desc', disableClear: false }); await fixture.whenStable(); fixture.detectChanges(); const rows = fixture.nativeElement.querySelectorAll('tbody tr'); expect(rows[0].querySelectorAll('td')[0].textContent).toContain('John'); expect(rows[0].querySelectorAll('td')[1].textContent).toContain('30'); });
方案2:模拟用户点击表头(更贴近真实场景)
直接调用sort方法可能绕过Angular Material的内部事件处理,模拟用户点击表头的方式更符合实际交互逻辑:
it('should render sorted data by age descending', async () => { component.displayedColumns = [{ value: 'name', label: 'Name' }, { value: 'age', label: 'Age' }]; component._dataSource.data = [{ name: 'Jane', age: 25 }, { name: 'John', age: 30 }]; fixture.detectChanges(); await fixture.whenStable(); // 获取age列表头,点击两次切换到降序(默认第一次点击为升序) const ageHeader = fixture.nativeElement.querySelector('th[mat-sort-header="age"]'); ageHeader.click(); await fixture.whenStable(); ageHeader.click(); await fixture.whenStable(); fixture.detectChanges(); const rows = fixture.nativeElement.querySelectorAll('tbody tr'); expect(rows[0].querySelectorAll('td')[0].textContent).toContain('John'); expect(rows[0].querySelectorAll('td')[1].textContent).toContain('30'); });
如果希望点击一次就触发降序,可以在模板中给mat-sort-header添加start="desc"属性:
<th mat-header-cell *matHeaderCellDef mat-sort-header [start]="'desc'">{{ column.label }}</th>
此时测试中只需点击一次表头即可得到降序结果。
额外优化:修复组件类型错误
组件中displayedColumns的类型定义有误,修正为正确的类型避免潜在问题:
// grid.component.ts displayedColumns: { value: string; label: string }[] = [];
内容的提问来源于stack exchange,提问作者H.Rahimy
相关产品推荐
相关产品推荐

