Angular Material测试:点击mat-button打开mat-menu失败排查
问题根源分析
- 异步操作未等待:MatMenu打开是异步过程(涉及动画、DOM渲染),点击按钮后直接校验状态会因未完成渲染导致结果错误。
- 组件级Loader范围限制:MatMenu面板默认挂载到
body而非组件内部,组件级loader无法检索到外部DOM中的菜单项。
修正后的测试代码
import { ComponentFixture, TestBed, } from '@angular/core/testing'; import { MatMenuModule } from '@angular/material/menu'; import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatMenuHarness } from '@angular/material/menu/testing'; import { MatButtonHarness } from '@angular/material/button/testing'; import { MatMenuItemHarness } from '@angular/material/menu/testing'; import { HelpButtonComponent } from './help-button.component'; describe('HelpButtonComponent', () => { let component: HelpButtonComponent; let fixture: ComponentFixture<HelpButtonComponent>; let componentLoader: HarnessLoader; let rootLoader: HarnessLoader; // 新增:用于检索全局DOM元素 beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MatMenuModule], // 移除不必要的MatFormFieldModule declarations: [HelpButtonComponent], }).compileComponents(); fixture = TestBed.createComponent(HelpButtonComponent); component = fixture.componentInstance; componentLoader = TestbedHarnessEnvironment.loader(fixture); rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture); // 初始化全局Loader fixture.detectChanges(); }); it('should open help menu and display items when clicking help button', async () => { // 获取按钮 const helpButton = await componentLoader.getHarness<MatButtonHarness>( MatButtonHarness.with({ selector: '#helpBtn' }) ); expect(helpButton).toBeTruthy(); // 初始状态:菜单关闭,无菜单项 const helpMenu = await componentLoader.getHarness<MatMenuHarness>(MatMenuHarness); expect(await helpMenu.isOpen()).toBeFalsy(); expect(await rootLoader.getAllHarnesses<MatMenuItemHarness>(MatMenuItemHarness)).toHaveLength(0); // 点击按钮并等待异步渲染完成 await helpButton.click(); await fixture.whenStable(); // 等待菜单渲染完成 fixture.detectChanges(); // 触发变更检测 // 校验菜单已打开 expect(await helpMenu.isOpen()).toBeTruthy(); // 通过全局Loader获取菜单项并校验 const menuItems = await rootLoader.getAllHarnesses<MatMenuItemHarness>(MatMenuItemHarness); expect(menuItems.length).toBe(1); const helpLink = menuItems[0]; expect(await helpLink.getText()).toBe('Help'); expect(await helpLink.getAttribute('href')).toBe('example.com'); }); });
关键修正点说明
- 新增全局Loader:使用
TestbedHarnessEnvironment.documentRootLoader(fixture)检索挂载到body的菜单面板。 - 等待异步操作:点击按钮后调用
fixture.whenStable()等待菜单渲染完成,再触发变更检测。 - 简化依赖:移除不必要的
MatFormFieldModule导入,保持测试环境简洁。 - 分步校验:先验证初始关闭状态,再校验点击后的打开状态及菜单项属性。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

