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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:38:18