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

Angular中Jest测试如何触发matchMedia主题变更事件?

测试Angular主题服务的系统主题变更监听逻辑

完善Mock并编写测试用例

既然已经Mock了window.matchMedia,接下来需要让Mock对象支持事件触发,以此验证listenForPreferredThemeChange的响应逻辑:

1. 构建可触发事件的matchMedia Mock

在测试的beforeEach中,扩展Mock的媒体查询对象,使其支持addEventListener、removeEventListener和dispatchEvent,确保变更事件能正确传递给服务的监听回调:

beforeEach(() => {
  // 重置全局matchMedia
  delete window.matchMedia;

  const mockMediaQuery = {
    matches: false,
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    // 自定义dispatchEvent,触发已注册的change回调
    dispatchEvent: jest.fn((event: Event) => {
      const registeredCallbacks = (mockMediaQuery.addEventListener as jest.Mock).mock.calls;
      registeredCallbacks.forEach(([eventType, callback]) => {
        if (eventType === 'change') callback(event);
      });
    })
  };

  window.matchMedia = jest.fn(() => mockMediaQuery);

  // 注入并初始化主题服务
  TestBed.configureTestingModule({ providers: [ThemeService] });
  themeService = TestBed.inject(ThemeService);
  themeService.listenForPreferredThemeChange();
});

2. 测试系统主题变更的响应逻辑

编写用例模拟系统/浏览器主题切换,验证服务是否正确调用主题设置逻辑:

it('triggers dark theme setup when system switches to dark mode', () => {
  const setThemeSpy = jest.spyOn(themeService, 'setPreferredTheme');
  const mockMediaQuery = window.matchMedia('(prefers-color-scheme: dark)') as jest.Mocked<MediaQueryList>;

  // 模拟系统切换到深色主题
  mockMediaQuery.matches = true;
  mockMediaQuery.dispatchEvent(new Event('change'));

  expect(setThemeSpy).toHaveBeenCalledWith('dark');
});

it('triggers light theme setup when system switches back to light mode', () => {
  const setThemeSpy = jest.spyOn(themeService, 'setPreferredTheme');
  const mockMediaQuery = window.matchMedia('(prefers-color-scheme: dark)') as jest.Mocked<MediaQueryList>;

  // 先切换到深色,再切回浅色
  mockMediaQuery.matches = true;
  mockMediaQuery.dispatchEvent(new Event('change'));
  mockMediaQuery.matches = false;
  mockMediaQuery.dispatchEvent(new Event('change'));

  expect(setThemeSpy).toHaveBeenCalledWith('light');
});

3. 验证事件监听的清理(可选)

如果服务在销毁时会移除事件监听,补充测试确保资源被正确清理:

it('removes theme change listener on service destruction', () => {
  const mockMediaQuery = window.matchMedia('(prefers-color-scheme: dark)') as jest.Mocked<MediaQueryList>;
  
  themeService.ngOnDestroy();

  expect(mockMediaQuery.removeEventListener).toHaveBeenCalledWith('change', expect.any(Function));
});

核心要点

  • 确保Mock的MediaQueryList能正确转发change事件到服务的回调函数,这是触发测试场景的关键。
  • 通过Spy服务的核心方法(如setPreferredTheme)验证业务逻辑,避免依赖DOM或外部状态,保持单元测试的独立性。

内容的提问来源于stack exchange,提问作者Cody Pritchard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:52:50