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

Angular Material测试:点击mat-button打开mat-menu失败排查

解决Angular MatMenu单元测试无法打开菜单及查找菜单项的问题

问题根源分析

  1. 异步操作未等待:MatMenu打开是异步过程(涉及动画、DOM渲染),点击按钮后直接校验状态会因未完成渲染导致结果错误。
  2. 组件级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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:44:58