首页
/ Chakra UI V3 中 Jest 测试遇到 emotionSfp 函数错误的解决方案

Chakra UI V3 中 Jest 测试遇到 emotionSfp 函数错误的解决方案

2025-05-03 04:00:42作者:裴麒琰

问题背景

在使用 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 属性的对象,而不是直接导出函数本身。

核心问题点:

  1. Chakra UI 期望 @emotion/is-prop-valid 直接导出一个函数
  2. 但在 Jest 环境中,该模块被包装成了一个 ES 模块,函数位于 default 属性下
  3. 这导致 Chakra UI 尝试调用 emotionSfp 时失败,因为它实际上是一个对象而非函数

解决方案

临时解决方案

对于需要快速解决问题的开发者,可以采用以下步骤:

  1. 首先添加 @emotion/is-prop-valid 作为开发依赖
  2. 配置 Jest 的 moduleNameMapper 来重定向该模块
  3. 创建模拟文件来替代真实的模块

具体实现:

  1. jest.config.js 中添加配置:
moduleNameMapper: {
  '@emotion/is-prop-valid': '<rootDir>/test/__mocks__/emotion.js',
},
setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
  1. 创建模拟文件 __mocks__/emotion.js
const isPropValid = '';
export default isPropValid;
  1. 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 },
);

长期解决方案

虽然上述临时方案可以解决问题,但更理想的长期解决方案是:

  1. 等待 Chakra UI 官方修复此问题,更新对 @emotion/is-prop-valid 的导入方式
  2. 或者在自己的项目中创建一个补丁,修改 Chakra UI 的导入逻辑

技术原理

这个问题的本质是 CommonJS 和 ES 模块系统之间的兼容性问题。在 Node.js 环境中,模块系统正在从 CommonJS 向 ES Modules 过渡,这导致了一些兼容性问题。

@emotion/is-prop-valid 作为一个被广泛使用的工具库,为了兼容不同环境,采用了同时支持两种模块系统的打包方式。但在 Jest 测试环境下,这种双重导出机制有时会导致模块解析出现偏差。

最佳实践建议

  1. 保持 Jest 和相关测试依赖的最新版本
  2. 对于 UI 组件库的测试,确保正确配置了所有必要的模拟
  3. 定期检查项目依赖的兼容性矩阵
  4. 考虑使用 jest-emotion 等专门为 CSS-in-JS 库设计的 Jest 插件

总结

Chakra UI V3 与 Jest 测试环境下的 emotionSfp 函数错误是一个典型的模块系统兼容性问题。通过合理的模拟配置可以解决这个问题,但开发者需要理解其背后的原理,以便在类似问题出现时能够快速定位和解决。随着 JavaScript 生态系统的演进,这类问题有望在未来版本的库中得到根本解决。

登录后查看全文
热门项目推荐

最新内容推荐

项目优选

收起
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
176
261
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
858
511
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
129
182
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
258
298
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
93
15
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
332
1.08 K
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
398
371
note-gennote-gen
一款跨平台的 Markdown AI 笔记软件,致力于使用 AI 建立记录和写作的桥梁。
TSX
83
4
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.07 K
0
kernelkernel
deepin linux kernel
C
22
5