NodeNext模块系统的TS项目中,如何用Jest正确Mock import.meta.url?
NodeNext模块系统下Jest中Mock import.meta.url的TypeScript错误处理
问题背景
在使用NodeNext模块系统的TypeScript项目中,尝试在Jest配置里Mock import.meta.url以设置全局__filename和__dirname,但尽管tsconfig.json已配置"module": "NodeNext",仍触发TypeScript错误:
jest.setup.ts:7:12 - error TS1343: The 'import.meta' meta-property is only allowed when the '--module' option is 'es2020', 'es2022', 'esnext', 'system', 'node16', or 'nodenext'.
相关代码与配置
业务代码(src/index.ts)
import { promises as fs } from 'fs' import { dirname, join } from 'path' import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) /** * Returns documentation specific to the provided filename * @param {string} filename - The name of the markdown file * @returns A promise that resolves to the documentation string */ async function getDocumentation(filename: string): Promise<string> { const filePath = join(__dirname, filename) try { const data = await fs.readFile(filePath, 'utf-8') return data } catch (error) { console.error('Error reading documentation file:', error) throw new Error('Failed to read documentation file') } } export { getDocumentation }
tsconfig.json配置
{ "compilerOptions": { "lib": ["dom", "ESNext"], "module": "NodeNext", "target": "esnext", "moduleResolution": "NodeNext", "moduleDetection": "force", "rootDir": "./", "baseUrl": "./", "outDir": "./dist", "strict": true, "isolatedModules": true, "strictNullChecks": true, "downlevelIteration": false, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "incremental": true, "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "resolveJsonModule": true, "esModuleInterop": true }, "files": ["src/index.ts", "src/types.d.ts"], "include": ["src", "knexfile.ts", "src/types.d.ts"], "exclude": ["dist", "*/**/__tests"] }
jest.config.js配置
module.exports = { preset: 'ts-jest', testEnvironment: 'node', setupFilesAfterEnv: ['./jest.setup.ts'], globals: { 'ts-jest': { tsconfig: 'tsconfig.json' } } }
当前jest.setup.ts
import { URL } from 'url'; import path from 'path'; const metaUrl = new URL('', import.meta.url).toString(); (global as any).__filename = path.resolve(new URL(metaUrl).pathname); (global as any).__dirname = path.dirname((global as any).__filename); jest.mock('url', () => ({ ...jest.requireActual('url'), fileURLToPath: jest.fn((url: string) => { if (url === 'file://' + (global as any).__filename) { return (global as any).__filename; } return url; }), }));
解决方案
1. 为测试目录单独配置tsconfig
主tsconfig.json排除了__tests目录,导致Jest处理jest.setup.ts时未应用正确的模块配置。创建tsconfig.test.json:
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext" }, "include": ["src", "__tests__", "jest.setup.ts"] }
修改jest.config.js中的ts-jest配置,指定测试用的tsconfig:
module.exports = { preset: 'ts-jest', testEnvironment: 'node', setupFilesAfterEnv: ['./jest.setup.ts'], globals: { 'ts-jest': { tsconfig: 'tsconfig.test.json' } } }
2. 简化Mock逻辑,避免在setup中直接使用import.meta.url
直接通过Jest的mockImplementation处理fileURLToPath,无需手动计算路径:
import { fileURLToPath } from 'url'; import path from 'path'; jest.mock('url', () => ({ ...jest.requireActual('url'), fileURLToPath: jest.fn((url: string) => { if (url.startsWith('file://')) { return path.resolve(url.replace('file://', '')); } return url; }), })); // 直接为全局注入__filename和__dirname Object.defineProperty(global, '__filename', { value: path.resolve(__filename), }); Object.defineProperty(global, '__dirname', { value: path.dirname(__filename), });
3. 升级依赖确保兼容性
旧版本的ts-jest和jest对NodeNext模块支持不完善,升级到最新稳定版:
npm install -D jest@latest ts-jest@latest typescript@latest
内容的提问来源于stack exchange,提问作者Brayden Langley
相关产品推荐
相关产品推荐

