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
相关产品推荐
相关产品推荐

