如何在Angular中使用Jasmine对D3元素进行单元测试
问题修复方案
现有测试的核心问题
- 事件类型不匹配:你的d3代码绑定的是
mousemove事件,但测试中触发的是mouseover,无法命中绑定的回调逻辑 - 事件监听顺序错误:先执行dispatchEvent再绑定监听器,回调不会被触发
- 缺少必要的事件属性:d3回调中使用了
d3Event.layerX/d3Event.layerY,构造事件时未传入对应值会导致运行报错 - 未验证事件触发后的实际效果:当前断言仅校验了静态mock数据,没有验证事件触发后的样式变化、tooltip显隐等核心逻辑
- 未确保选中目标元素:默认查询第一个
.country不一定是你mock的MY对应区域,回调拿到的x参数属性id不匹配会走else分支
修正后的测试用例
it('should trigger mousemove event and update state correctly', fakeAsync(() => { // 初始化mock数据 component.data = { values: [], worldMapType: WorldMapType.WORLD, countries:{ MY: countriesMockData } }; fixture.detectChanges(); tick(); // 等待d3渲染完成 // 直接选中MY对应的path元素,确保拿到的绑定数据是目标数据 const targetSelector = `#${component.mapId}-MY`; const de = fixture.debugElement.query(By.css(targetSelector)); expect(de).toBeTruthy('未找到马来西亚对应的地图元素'); const el = de.nativeElement; // 先绑定事件监听,再触发事件 let eventTriggered = false; el.addEventListener('mousemove', () => { eventTriggered = true; fixture.detectChanges(); // 校验核心交互效果 // 1. 目标元素是否添加了高亮类 expect(el.classList.contains('country-on')).toBeTrue('目标区域未添加高亮样式'); // 2. 其他区域是否未添加高亮类 const otherCountry = fixture.debugElement.query(By.css(`.country:not(${targetSelector})`))?.nativeElement; if(otherCountry) expect(otherCountry.classList.contains('country-on')).toBeFalse('非目标区域错误添加高亮'); // 3. tooltip是否可见 const tooltip = fixture.debugElement.query(By.css(`#${component.mapId} .tooltip`))?.nativeElement; expect(tooltip.classList.contains('visible')).toBeTrue('tooltip未正常显示'); // 4. tooltip内容是否符合预期 expect(tooltip.innerHTML).toContain(countriesMockData.description); }); // 构造携带layerX/layerY属性的mousemove事件 const moveEvent = new MouseEvent('mousemove', { bubbles: true, cancelable: true, layerX: 100, layerY: 100 }); el.dispatchEvent(moveEvent); tick(); // 兜底校验事件是否被触发 expect(eventTriggered).toBeTrue('mousemove事件未触发'); }));
额外注意点
- 如果测试环境拿不到
component.mapId,可以先打印确认组件初始化后的mapId值,或者直接用属性选择器匹配对应id后缀的元素 - 如果你需要测试无匹配国家数据的分支,直接选中没有在mock countries里配置的国家区域触发事件,校验tooltip的visible类为false即可
内容的提问来源于stack exchange,提问作者Tarik EN-NAKDI
相关产品推荐
相关产品推荐

