使用@material-ui/pickers v3.2.10遇TypeError: Utils is not a constructor问题求助
解决MuiPickersUtilsProvider测试报错"Utils is not a constructor"
我之前也碰到过@material-ui/pickers@v3.2.10搭配@date-io/date-fns时的这个测试兼容问题,给你几个亲测有效的解决方案:
问题回顾
你现在的情况是:
- 项目UI运行完全正常,但跑Jest测试时就抛出
TypeError: Utils is not a constructor - 换了几种
import方式,要么测试正常但UI崩了,要么两边都报错,而且看了官方issue也没找到直接解决办法
方案1:在测试初始化文件里模拟date-io的导出
Jest的模块解析逻辑和浏览器不一样,我们可以直接在测试环境里给@date-io/date-fns做个简单模拟,让它返回一个符合要求的工具类。在你现有的测试setup文件末尾加上这段代码:
// 模拟@date-io/date-fns的导出,适配测试环境 jest.mock('@date-io/date-fns', () => { class MockDateFnsUtils { // 实现picker需要的核心方法,按需添加 parse = (value, format) => new Date(value); format = (date, format) => date.toISOString(); addDays = (date, days) => { const newDate = new Date(date); newDate.setDate(newDate.getDate() + days); return newDate; }; } return { default: MockDateFnsUtils }; });
这样测试的时候就不会去加载真实的date-fns模块,而是用我们写的模拟类,既能满足MuiPickersUtilsProvider的要求,又不会触发构造函数错误。
方案2:调整Babel配置让Jest正确识别默认导出
如果你的项目用了Babel,可以给测试环境单独加个插件,把ES模块转换成CommonJS格式,让Jest能正确解析默认导出。
在.babelrc或者babel.config.js里添加:
{ "env": { "test": { "plugins": ["@babel/plugin-transform-modules-commonjs"] } } }
然后保持你原来的导入方式不变:
import DateFnsUtils from '@date-io/date-fns'; import { DateTimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers';
这个配置只会在测试环境生效,不会影响浏览器端的打包。
方案3:用Jest的moduleNameMapper重定向到自定义模拟文件
如果需要更灵活的模拟,可以在jest.config.js里配置模块映射:
module.exports = { // 其他Jest配置... moduleNameMapper: { '@date-io/date-fns': '<rootDir>/__mocks__/date-fns-mock.js' } };
然后在项目根目录创建__mocks__/date-fns-mock.js文件,写上模拟类:
export default class MockDateFnsUtils { parse = (value, format) => new Date(value); format = (date, format) => date.toLocaleDateString(); // 根据你的测试场景,添加更多需要的方法 }
为什么会出现这个问题?
本质是浏览器和Node.js(Jest运行环境)对ES模块默认导出的处理逻辑不一样。@date-io/date-fns的导出方式在浏览器里能被正确识别为可实例化的类,但Jest解析时可能把默认导出当成了普通对象,导致new DateFnsUtils()的时候报错说"不是构造函数"。上面的方案都是通过消除这种环境差异来解决问题的。
内容的提问来源于stack exchange,提问作者Akhilesh Kumar
相关产品推荐
相关产品推荐

