You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vite Vue TS Three项目中Jest测试运行失败问题求助

解决Jest测试中的ES模块语法错误问题

问题场景

项目基于Vite+Vue3+TypeScript+Three.js开发,配置Jest进行单元测试时,多次尝试调整配置仍持续出现SyntaxError: Cannot use import statement outside a module错误,以下是详细的代码、配置及报错信息:

测试代码

import {Line} from "../src/modules/objs/line";
import {SceneWrapper} from "../src/modules/scene/sceneWrapper";
import * as THREE from "three";
import {DrawProfile} from "../src/modules/operations/draw/drawProfile";
import {snapIndicator} from "../src/modules/config/objs";

describe('snaps', () => {
    let sceneWrapper = new SceneWrapper(new HTMLCanvasElement());
    let lineStart = new THREE.Vector3(0, 0, 0);
    let cursorStart = sceneWrapper.getScreenCoordsFromSceneCoords(lineStart);
    let line = new Line(lineStart, new THREE.Vector3(10, 10, 10));
    sceneWrapper.scene.add(line);
    
    test('Box appear', () => {
        let operation = new DrawProfile(sceneWrapper);
        let startEvent = new PointerEvent('', {clientX: cursorStart.x, clientY: cursorStart.y});
        operation.searchSnapsHandler(startEvent);
        
        expect(operation.snap).toBeDefined();
        expect(sceneWrapper.scene).toContain(snapIndicator);
        expect(snapIndicator.position).toBe(lineStart);
    });
});

初始jest.config.cjs

module.exports = {
    preset: 'ts-jest/presets/js-with-ts-esm',
    testEnvironment: 'jsdom',
};

第一次报错

/Users/a/Programming/JavaScript/CAD/test/main.test.ts:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { Line } from "../src/modules/objs/line";
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

修改后的jest.config.cjs

module.exports = {
    preset: 'ts-jest/presets/js-with-ts-esm',
    testEnvironment: 'jsdom',
    moduleNameMapper: {
        '(\\.{1,2}/.*)\\.js$': '$1',
    },
};

第二次报错

/Users/a/Programming/JavaScript/CAD/node_modules/three/examples/jsm/controls/OrbitControls.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import {
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

       7 | import {SceneType} from "./sceneType";
       8 | import {Scene3DView} from "./scenes/scene3DView";
    >  9 | import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
         | ^
      10 | import {cameraFarPlane, cameraFov, cameraNearPlane} from "../config/dims";
      11 | import {Operation} from "../operations/operation";
      12 | import {defaultOrbitControlsMouseHandlers, startSceneType} from "../config/others";

使用NODE_OPTIONS=--experimental-vm-modules jest后的报错

/Users/a/Programming/JavaScript/CAD/node_modules/vue/dist/vue.runtime.esm-bundler.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { initCustomFormatter, warn } from '@vue/runtime-dom';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

tsconfig.json配置

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "noEmit": true,
    "sourceMap": true,
    "allowJs": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

package.json配置

{
  "name": "cad",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
    "dev": "vite",
    "test": "jest",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "pinia": "^2.0.33",
    "sass": "^1.58.3",
    "scss": "^0.2.4",
    "three": "^0.150.1",
    "vue": "^3.2.45"
  },
  "devDependencies": {
    "@types/jest": "^29.5.5",
    "@types/node": "^18.15.11",
    "@types/three": "^0.149.0",
    "@typescript-eslint/eslint-plugin": "^5.56.0",
    "@typescript-eslint/parser": "^5.56.0",
    "@vitejs/plugin-vue": "^4.0.0",
    "autoprefixer": "^10.4.14",
    "eslint": "^8.36.0",
    "eslint-plugin-vue": "^9.10.0",
    "esm": "^3.2.25",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "postcss": "^8.4.21",
    "tailwindcss": "^3.2.7",
    "ts-jest": "^29.1.1",
    "typescript": "^4.9.5",
    "vite": "^4.1.0",
    "vue-tsc": "^1.0.24"
  }
}

解决方案

针对项目"type": "module"的ESM模式,结合TypeScript、Vue、Three.js等依赖的特性,调整Jest配置如下:

1. 重新配置jest.config.cjs

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  extensionsToTreatAsEsm: ['.ts', '.tsx', '.vue'],
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
    '^three/examples/jsm/(.*)$': '<rootDir>/node_modules/three/examples/jsm/$1'
  },
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        useESM: true,
      },
    ],
    '^.+\\.vue$': '@vue/vue3-jest'
  },
  globals: {
    'ts-jest': {
      useESM: true
    }
  }
};

2. 更新package.json的测试脚本

{
  "scripts": {
    "test": "NODE_OPTIONS=--experimental-vm-modules jest"
  }
}

3. 补充安装Vue测试依赖

npm install -D @vue/vue3-jest

4. 调整tsconfig.json(可选)

确保TypeScript模块配置与Jest的ESM模式兼容:

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "NodeNext"
  }
}

验证

运行npm run test,Jest将正确识别所有ES模块导入,解决语法错误问题。

内容的提问来源于stack exchange,提问作者Intolighter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:14:55