Storyshots技术问题咨询:scrollWidth读取错误及renderOnly模式失效
解决Storyshots renderOnly模式与createNodeMock冲突及scrollWidth报错问题
这问题我之前碰到过,核心矛盾在于renderOnly模式的设计和createNodeMock的作用完全冲突——咱们一点点拆解解决:
为什么加了createNodeMock会让renderOnly失效?
Storyshots的renderOnly模式本质是不创建真实DOM、不挂载组件到DOM树,用轻量的渲染方式生成快照,目的是提升测试速度。而createNodeMock: node => document.createElement(node.type)是全局给所有需要DOM节点的React组件创建真实DOM元素,这直接触发了组件的真实挂载流程,自然就打破了renderOnly的轻量模式。
针对两个问题的解决方案
1. 针对性Mock节点,而非全局创建真实DOM
不要给所有节点都创建真实DOM,只针对那些导致初始报错的组件类型做mock,同时给mock元素补上scrollWidth属性避免报错:
initStoryshots({ // 其他配置... renderer: renderer, createNodeMock: (node) => { // 只处理你需要mock的组件类型(比如div、自定义滚动组件等) const needMockTypes = ['div', 'ScrollContainer']; if (needMockTypes.includes(node.type)) { const mockEl = document.createElement(node.type); // 给mock元素添加scrollWidth的getter,返回测试需要的数值 Object.defineProperty(mockEl, 'scrollWidth', { get: () => 200, // 可根据你的测试场景调整值 configurable: true, }); return mockEl; } // 其他类型用默认mock或返回null,保持renderOnly的轻量性 return null; }, });
这种方式既解决了初始报错,又不会让所有组件都走真实DOM挂载,保留renderOnly的高效性。
2. 模拟依赖DOM的逻辑,避免直接访问真实DOM
如果你的组件里有主动获取scrollWidth的逻辑(比如计算容器宽度、做滚动判断),可以把这部分逻辑抽成独立工具函数,然后在测试中mock它:
// 假设组件里引入了getElementScrollWidth工具函数 jest.mock('../utils/domUtils', () => ({ getElementScrollWidth: () => 200, // 返回测试需要的固定值 }));
这样组件在renderOnly模式下运行时,会直接使用mock的返回值,不会去访问真实DOM的scrollWidth属性,从根源避免报错。
3. 分场景切换渲染模式(兜底方案)
如果某些场景必须依赖真实DOM才能测试,可以给特定story添加参数,让Storyshots针对这些场景使用full render模式,其他场景保持renderOnly:
第一步:给需要特殊处理的story添加参数
// 在你的story文件中 export const NeedDomRender = () => <MyScrollComponent />; NeedDomRender.parameters = { storyshots: { needFullRender: true }, };
第二步:在Storyshots配置中判断切换
initStoryshots({ // 其他配置... test: ({ story, context }) => { // 检查story是否标记需要full render if (story.parameters?.storyshots?.needFullRender) { return renderStoryToDOM({ story, context }); } // 其他场景用renderOnly return renderOnly({ story, context }); }, });
这种方式兼顾了测试效率和特殊场景的准确性,适合复杂组件的测试需求。
内容的提问来源于stack exchange,提问作者Andrew Mayanov
相关产品推荐
相关产品推荐

