Chakra UI V3 中 Jest 测试遇到 emotionSfp 函数错误的解决方案
2025-05-03 04:16:37作者:裴麒琰
问题背景
在使用 Chakra UI V3 和 Jest 29 进行测试时,开发者可能会遇到一个 TypeError 错误,提示 emotionSfp is not a function。这个错误源于 Chakra UI 内部对 @emotion/is-prop-valid 模块的导入方式与 Jest 环境下的模块解析机制不兼容。
问题分析
错误发生在 Chakra UI 的 factory.tsx 文件中,具体是在尝试导入 @emotion/is-prop-valid 模块时。在 Jest 测试环境下,该模块被导出为一个包含 default 属性的对象,而不是直接导出函数本身。
核心问题点:
- Chakra UI 期望
@emotion/is-prop-valid直接导出一个函数 - 但在 Jest 环境中,该模块被包装成了一个 ES 模块,函数位于 default 属性下
- 这导致 Chakra UI 尝试调用
emotionSfp时失败,因为它实际上是一个对象而非函数
解决方案
临时解决方案
对于需要快速解决问题的开发者,可以采用以下步骤:
- 首先添加
@emotion/is-prop-valid作为开发依赖 - 配置 Jest 的
moduleNameMapper来重定向该模块 - 创建模拟文件来替代真实的模块
具体实现:
- 在
jest.config.js中添加配置:
moduleNameMapper: {
'@emotion/is-prop-valid': '<rootDir>/test/__mocks__/emotion.js',
},
setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
- 创建模拟文件
__mocks__/emotion.js:
const isPropValid = '';
export default isPropValid;
- 在
test/setup.js中实现完整的模拟逻辑:
jest.mock(
'@emotion/is-prop-valid',
() => {
const reactPropsRegex = /^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|abbr|accept|acceptCharset|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|disablePictureInPicture|disableRemotePlayback|download|draggable|encType|enterKeyHint|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|translate|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|incremental|fallback|inert|itemProp|itemScope|itemType|itemID|itemRef|on|option|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/;
return function (prop) {
return (
reactPropsRegex.test(prop) ||
(prop.charCodeAt(0) === 111 &&
prop.charCodeAt(1) === 110 &&
prop.charCodeAt(2) < 91)
);
};
},
{ esModule: true },
);
长期解决方案
虽然上述临时方案可以解决问题,但更理想的长期解决方案是:
- 等待 Chakra UI 官方修复此问题,更新对
@emotion/is-prop-valid的导入方式 - 或者在自己的项目中创建一个补丁,修改 Chakra UI 的导入逻辑
技术原理
这个问题的本质是 CommonJS 和 ES 模块系统之间的兼容性问题。在 Node.js 环境中,模块系统正在从 CommonJS 向 ES Modules 过渡,这导致了一些兼容性问题。
@emotion/is-prop-valid 作为一个被广泛使用的工具库,为了兼容不同环境,采用了同时支持两种模块系统的打包方式。但在 Jest 测试环境下,这种双重导出机制有时会导致模块解析出现偏差。
最佳实践建议
- 保持 Jest 和相关测试依赖的最新版本
- 对于 UI 组件库的测试,确保正确配置了所有必要的模拟
- 定期检查项目依赖的兼容性矩阵
- 考虑使用
jest-emotion等专门为 CSS-in-JS 库设计的 Jest 插件
总结
Chakra UI V3 与 Jest 测试环境下的 emotionSfp 函数错误是一个典型的模块系统兼容性问题。通过合理的模拟配置可以解决这个问题,但开发者需要理解其背后的原理,以便在类似问题出现时能够快速定位和解决。随着 JavaScript 生态系统的演进,这类问题有望在未来版本的库中得到根本解决。
登录后查看全文
热门项目推荐
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00
jiuwenclawJiuwenClaw 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。Python0245- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
AtomGit城市坐标计划AtomGit 城市坐标计划开启!让开源有坐标,让城市有星火。致力于与城市合伙人共同构建并长期运营一个健康、活跃的本地开发者生态。01
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python05
项目优选
收起
deepin linux kernel
C
27
13
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
641
4.19 K
Ascend Extension for PyTorch
Python
478
579
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
934
841
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
386
272
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
1.52 K
866
暂无简介
Dart
885
211
仓颉编程语言运行时与标准库。
Cangjie
161
922
昇腾LLM分布式训练框架
Python
139
163
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
69
21