Jest测试含动态import的Svelte组件时ES Module报错如何解决
Svelte组件动态导入场景的Jest测试解决方案
问题复现
场景说明
使用Jest为包含动态导入逻辑的Svelte组件编写测试,动态导入代码如下:
async function importComponent() { if (!dynamicComponent) { dynamicComponent= (await import('../Component')).Component; } }
package.json中Jest配置如下:
"jest": { "globals": { "ts-jest": { "isolatedModules": true, "tsConfig": "./tsconfig.json", } }, "testEnvironment": "jsdom", "verbose": true, "transform": { "^.+\\.svelte$": [ "svelte-jester", { "preprocess": true } ], "^.+\\.ts$": "ts-jest", "^.+\\.js$": "babel-jest" }, "setupFilesAfterEnv": [ "<rootDir>/setupTests.ts" ], "moduleFileExtensions": [ "js", "ts", "svelte" ] }
触发报错的测试用例:
it('should open on click', async () => { const { getByRole } = render(ComponentUnderTest, { ...dummyProps }); const loadComponentButton = getByRole('button'); await fireEvent(loadComponentButton, new MouseEvent('click', { bubbles: true, cancelable: true, })); });
报错信息
触发的报错如下:
Error: You need to run with a version of node that supports ES Modules in the VM API.
使用的Node版本为v16.4.2,尝试过Jest官方ESM兼容方案后所有测试均报错,尝试过dynamic-import-node、@babel/plugin-syntax-dynamic-import、jest-next-dynamic库、直接Mock import语句等方案均无效。
报错原因
即使配置了jsdom测试环境,Jest本身仍运行在Node进程中,动态导入语法的解析依赖Node VM模块,低版本Jest对ESM动态导入的兼容存在缺陷,因此会触发该报错。
解决方案
将懒加载导入逻辑抽离到单独的中间代理文件中,通过Mock代理文件的方式避开原生import语句的兼容问题,同时还可以为加载逻辑编写独立测试用例,具体操作步骤如下:
- 新建独立的加载逻辑代理文件,例如
src/utils/component-loader.ts,将动态导入逻辑迁移到该文件:
// component-loader.ts export async function importTargetComponent() { return (await import('../Component')).Component; }
- 修改原业务组件的引用逻辑,改为调用代理文件导出的方法:
import { importTargetComponent } from './utils/component-loader'; let dynamicComponent; async function importComponent() { if (!dynamicComponent) { dynamicComponent = await importTargetComponent(); } }
- 在测试文件中直接Mock代理文件的导出方法,自定义返回值即可:
// 测试文件顶部添加Mock逻辑 jest.mock('./utils/component-loader', () => ({ // 可根据测试需要返回真实组件或Mock组件 importTargetComponent: jest.fn().mockResolvedValue(jest.fn(() => ({ default: {} }))) })); // 原有测试逻辑无需修改 it('should open on click', async () => { const { getByRole } = render(ComponentUnderTest, { ...dummyProps }); const loadComponentButton = getByRole('button'); await fireEvent(loadComponentButton, new MouseEvent('click', { bubbles: true, cancelable: true, })); });
这个方案对业务代码侵入性极低,同时完全避开了Jest ESM动态导入的兼容问题,测试可以正常运行。
内容的提问来源于stack exchange,提问作者Apfelbox
相关产品推荐
相关产品推荐

