React Native Expo中Jest测试i18n-js报错的解决方法求助
我在基于Expo的React Native项目里,用i18n-js结合Expo Localization实现了国际化,业务组件运行正常,但用Jest测试引入i18n模块的组件时,先触发「Jest encountered an unexpected token」错误,尝试mock i18n-js模块后又出现「TypeError: _i18nJs.I18n is not a constructor」错误,求解决办法。
一、初始报错信息
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.htmlDetails:
/
/node_modules/i18n-js/dist/import/index.js:1
({"Object.":function(module,exports,require,__dirname,__filename,global,jest){export { I18n } from "./I18n";
二、i18n 实现代码
import * as Localization from 'expo-localization'; import { I18n } from 'i18n-js'; import translations from './translations'; const i18n = new I18n(translations); i18n.locale = Localization.locale.split('-')[0]; i18n.defaultLocale = 'en'; i18n.enableFallback = true; export default i18n; export { Localization };
三、尝试的Mock配置及后续报错
jest.config.ts 配置
moduleNameMapper: { 'i18n-jss': '<rootDir>/src/__mocks__/i18n-jsMocked.ts' }
i18n-jsMocked.ts 代码
import * as origininalI18n from 'i18n-js'; const mocked = origininalI18n as jest.Mocked<typeof origininalI18n>; export const I18n = mocked.I18n; beforeEach(() => { I18n.mockClear(); }); const i18nMocked = jest.mock('i18n-js', () => { return { I18n }; }); export default i18nMocked;
触发的构造函数错误
● Test suite failed to run
TypeError: _i18nJs.I18n is not a constructor
import translations from './translations'; const i18n = new I18n(translations); ^ i18n.locale = Localization.locale.split('-')[0]; i18n.defaultLocale = 'en'; i18n.enableFallback = true; at Object.
(src/i18n/index.ts:6:14)
at Object.(src/components/otherFolder/MyComponent/index.tsx:17:1)
四、解决方案
方案1:修复Jest对ES模块的解析问题
初始报错是因为i18n-js发布包使用ES模块语法,Jest默认不对node_modules下的文件转译。修改jest.config.ts的transformIgnorePatterns,让Jest转译i18n-js:
transformIgnorePatterns: [ 'node_modules/(?!(i18n-js|expo-localization)/)' ],
同时确保你的Babel配置(如babel.config.js)支持转译ES模块,比如使用@babel/preset-env和@babel/preset-react。
方案2:正确Mock i18n-js模块
之前的Mock写法有误,需直接构造模拟的I18n类,而非依赖原模块:
- 先修正
jest.config.ts里的模块匹配错误(原配置写的i18n-jss应为i18n-js):
moduleNameMapper: { 'i18n-js': '<rootDir>/src/__mocks__/i18n-jsMocked.ts' }
- 重写
src/__mocks__/i18n-jsMocked.ts:
// 模拟I18n类,实现必要方法和属性 export class I18n { locale: string; defaultLocale: string; enableFallback: boolean; constructor(translations: Record<string, any>) { this.locale = 'en'; this.defaultLocale = 'en'; this.enableFallback = true; } // 模拟t方法,直接返回key或自定义值 t(key: string) { return key; } } export default { I18n };
或用Jest mock函数构造:
const mockI18n = jest.fn().mockImplementation(() => ({ locale: 'en', defaultLocale: 'en', enableFallback: true, t: (key: string) => key })); export const I18n = mockI18n; export default { I18n };
方案3:Mock整个项目的i18n实例
如果不想Mock底层i18n-js,可直接Mock项目导出的i18n实例,在测试文件顶部添加:
jest.mock('../../i18n', () => ({ default: { t: (key: string) => key }, Localization: { locale: 'en-US' } }));
内容的提问来源于stack exchange,提问作者Fabian Montoya

