Angular v13 Jest with nx test - SyntaxError: Cannot use import statement outside a module at Runtime.createScriptFromCode
Angular v13 Jest with nx test - SyntaxError: Cannot use import statement outside a module at Runtime.createScriptFromCode
我试着在每条评论后面加上可能的解决方案 here。我也依赖于 github 上的一个示例项目,它工作得很好。
在手动更新所有内容后,当 运行 nx 测试命令发生此错误时,这也开始发生在我身上。
我的jest.config.js里面apps/my-app:
module.exports = {
preset: "../../jest.preset.js",
coverageDirectory: "../../coverage/apps/my-app",
moduleFileExtensions: ["ts", "html", "js", "json", "mjs"],
extensionsToTreatAsEsm: [".ts"],
resolver: "jest-preset-angular/build/resolvers/ng-jest-resolver.js",
setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\.(html|svg)$",
useESM: true
}
},
transform: {
"^.+\.(ts|js|mjs|html|svg)$": "jest-preset-angular",
},
displayName: "my-app",
snapshotSerializers: [
"jest-preset-angular/build/serializers/no-ng-attributes",
"jest-preset-angular/build/serializers/ng-snapshot",
"jest-preset-angular/build/serializers/html-comment",
],
transformIgnorePatterns: [
"node_modules/(?!.*\.mjs$)",
"node_modules/(?!lodash-es)",
"node_modules/(?!@ngrx|@ionic-native|@ionic)"
]
};
jest.config.js 在项目根目录:
const { getJestProjects } = require("@nrwl/jest");
module.exports = { projects: getJestProjects() };
jest.preset.js 在根项目中:
const nxPreset = require("@nrwl/jest/preset");
module.exports = {
...nxPreset,
testMatch: ["**/+(*.)+(spec|test).+(ts|js)?(x)"],
transform: {
"^.+\.(ts|js|html)$": "ts-jest",
},
resolver: "@nrwl/jest/plugins/resolver",
moduleFileExtensions: ["ts", "js", "html"],
coverageReporters: ["html"],
};
package.json:
{
"name": "my-app",
"version": "1.1.10",
"license": "MIT",
"scripts": {
...
},
"private": true,
"dependencies": {
"@angular-devkit/architect": "0.1301.2",
"@angular/animations": "13.1.0",
"@angular/common": "13.1.0",
"@angular/compiler": "13.1.0",
"@angular/core": "13.1.0",
"@angular/forms": "13.1.0",
"@angular/platform-browser": "13.1.0",
"@angular/platform-browser-dynamic": "13.1.0",
"@angular/router": "13.1.0",
"@angular/service-worker": "13.1.0",
"@awesome-cordova-plugins/device": "5.37.2",
"@ionic-enterprise/cordova": "9.0.3",
"@ionic-native/app-version": "5.36.0",
"@ionic-native/clipboard": "5.36.0",
"@ionic-native/core": "5.36.0",
"@ionic-native/fingerprint-aio": "5.36.0",
"@ionic-native/in-app-browser": "5.36.0",
"@ionic-native/ionic-webview": "5.36.0",
"@ionic-native/secure-storage": "5.36.0",
"@ionic-native/social-sharing": "5.36.0",
"@ionic-native/splash-screen": "5.36.0",
"@ionic-native/status-bar": "5.36.0",
"@ionic-native/unique-device-id": "5.36.0",
"@ionic/angular": "6.0.0",
"@ionic/storage-angular": "3.0.6",
"@ng-idle/core": "11.1.0",
"@ng-idle/keepalive": "11.0.3",
"@ngx-translate/core": "14.0.0",
"@ngx-translate/http-loader": "7.0.0",
"@sentry/angular": "6.16.1",
"@sentry/tracing": "6.16.1",
"cordova-android": "8.1.0",
"cordova-plugin-device": "2.0.3",
"cordova-plugin-inappbrowser": "5.0.0",
"cordova-plugin-ionic-keyboard": "2.2.0",
"cordova-plugin-ionic-webview": "5.0.0",
"cordova-plugin-splashscreen": "6.0.0",
"cordova-plugin-statusbar": "3.0.0",
"cordova-plugin-whitelist": "1.3.5",
"core-js": "3.19.3",
"crypto-es": "1.2.7",
"document-register-element": "1.14.10",
"dom-to-image": "2.6.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"native-run": "1.5.0",
"ng-circle-progress": "1.6.0",
"node-forge": "0.10.0",
"npm": "8.3.0",
"reflect-metadata": "0.1.13",
"rxjs": "7.4.0",
"sass": "1.45.0",
"tslib": "2.3.1",
"uuid": "8.3.2",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-architects/ddd": "1.5.1",
"@angular-devkit/build-angular": "13.1.0",
"@angular-eslint/builder": "13.0.1",
"@angular-eslint/eslint-plugin": "13.0.1",
"@angular-eslint/eslint-plugin-template": "13.0.1",
"@angular-eslint/schematics": "13.0.1",
"@angular-eslint/template-parser": "13.0.1",
"@angular/cli": "13.1.0",
"@angular/compiler-cli": "13.1.0",
"@angular/language-service": "13.1.0",
"@angularclass/hmr": "3.0.0",
"@ionic/angular-toolkit": "5.0.3",
"@ionic/cli": "6.18.1",
"@nrwl/angular": "13.3.2",
"@nrwl/cli": "13.3.1",
"@nrwl/cypress": "13.3.1",
"@nrwl/eslint-plugin-nx": "13.3.1",
"@nrwl/jest": "13.3.1",
"@nrwl/linter": "13.3.1",
"@nrwl/node": "13.3.1",
"@nrwl/workspace": "13.3.1",
"@schematics/angular": "13.1.0",
"@types/dom-to-image": "2.6.4",
"@types/jest": "27.0.3",
"@types/lodash-es": "4.17.5",
"@types/node": "16.11.12",
"@types/node-forge": "0.10.10",
"@types/uuid": "8.3.3",
"@typescript-eslint/eslint-plugin": "5.3.1",
"@typescript-eslint/parser": "5.3.1",
"codelyzer": "6.0.2",
"compare-func": "2.0.0",
"cordova": "10.0.0",
"cordova-browser": "6.0.0",
"cordova-clipboard": "1.3.0",
"cordova-ios": "6.2.0",
"cordova-plugin-add-swift-support": "2.0.2",
"cordova-plugin-androidx": "3.0.0",
"cordova-plugin-androidx-adapter": "1.1.3",
"cordova-plugin-app-version": "0.1.12",
"cordova-plugin-fingerprint-aio": "5.0.0",
"cordova-plugin-iroot": " 3.1.0",
"cordova-plugin-proguard": "2.2.0",
"cordova-plugin-secure-storage-echo": " 5.1.1",
"cordova-plugin-x-socialsharing": "6.0.3",
"cordova-res": "0.15.4",
"cordova-sqlite-storage": "6.0.0",
"cordova-unique-device-id": "1.3.2",
"cypress": "8.7.0",
"dotenv": "10.0.0",
"dtslint": "4.2.1",
"es6-promise-plugin": "4.2.2",
"eslint": "8.4.1",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-prettier": "4.0.0",
"fuzzy": "0.1.3",
"inquirer": "8.2.0",
"inquirer-autocomplete-prompt": "1.4.0",
"jest": "27.4.5",
"jest-preset-angular": "11.0.1",
"ncu": "0.2.1",
"ng-packagr": "13.1.0",
"ngx-unused-css": "3.0.0",
"npm-check-updates": "12.0.3",
"npx": "10.2.2",
"open": "8.4.0",
"prettier": "2.5.1",
"stylelint": "14.1.0",
"stylelint-config-standard": "24.0.0",
"ts-jest": "27.0.5",
"ts-node": "9.1.1",
"typescript": "^4.4.4",
"webpack": "5.30.0",
"xml2js": "0.4.23"
},
"description": "An ionic project",
"browser": {
"crypto": false,
"stream": false
},
"cordova": {
"plugins": {
"cordova-plugin-ionic-keyboard": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-whitelist": {},
"cordova-plugin-ionic-webview": {},
"cordova-plugin-inappbrowser": {},
"cordova-plugin-x-socialsharing": {
"PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION": "La aplicación requiere acceso a la biblioteca de fotos para funcionar apropiadamente.",
"PHOTO_LIBRARY_USAGE_DESCRIPTION": "La aplicación requiere acceso a la biblioteca de fotos para funcionar apropiadamente."
},
"cordova-plugin-androidx": {},
"cordova-plugin-androidx-adapter": {},
"cordova-plugin-proguard": {},
"cordova-sqlite-storage": {},
"cordova-unique-device-id": {},
"cordova-plugin-app-version": {},
"cordova-plugin-fingerprint-aio": {
"FACEID_USAGE_DESCRIPTION": " "
},
"cordova-plugin-secure-storage-echo": {},
"cordova-plugin-iroot": {},
"cordova-clipboard": {},
"cordova-plugin-add-swift-support": {},
"cordova-plugin-device": {}
},
"platforms": [
"browser",
"ios",
"android"
]
}
}
我仍然不断收到此错误: :/
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
C:\Repos\temp-repos\my-app\node_modules\@angular\core\fesm2015\testing.mjs:7
import { getDebugNode, RendererFactory2, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ModuleWithComponentFactories, InjectionToken, Injector, InjectFlags, ɵresetCompiledComponents, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1728:14)
感谢您的回复。
从我在网上发现的情况来看,这似乎是使用 Jest 并升级到 Angular 13 的项目的常见问题。我们的项目不使用 nx
,但更新我们的笑话配置:
// jest.config.js
const esModules = ['@angular', '@ngrx', 'd3', [...] ];
module.exports = {
// [...]
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true,
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\.html$',
},
},
moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'],
moduleNameMapper: {
'^(\.{1,2}/.*)\.js$': '',
},
transform: {
'^.+\.(ts|js|mjs|html|svg)$': 'jest-preset-angular',
},
transformIgnorePatterns: [
`<rootDir>/node_modules/(?!.*\.mjs$|${esModules.join('|')})`,
]
};
解决我的问题的是 this comment 一个已关闭的问题 (jest-preset-angular)。忽略模块,在我的例子中 @angular
和 @ngrx
,解决了您问题中发布的错误。具体这一行:
const esModules = ['@angular', '@ngrx', 'd3', [...] ];
更新:转换忽略模式合并为 node_module 个文件和模块的单一模式以解决不同的问题。
我试着在每条评论后面加上可能的解决方案 here。我也依赖于 github 上的一个示例项目,它工作得很好。
在手动更新所有内容后,当 运行 nx 测试命令发生此错误时,这也开始发生在我身上。
我的jest.config.js里面apps/my-app:
module.exports = {
preset: "../../jest.preset.js",
coverageDirectory: "../../coverage/apps/my-app",
moduleFileExtensions: ["ts", "html", "js", "json", "mjs"],
extensionsToTreatAsEsm: [".ts"],
resolver: "jest-preset-angular/build/resolvers/ng-jest-resolver.js",
setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\.(html|svg)$",
useESM: true
}
},
transform: {
"^.+\.(ts|js|mjs|html|svg)$": "jest-preset-angular",
},
displayName: "my-app",
snapshotSerializers: [
"jest-preset-angular/build/serializers/no-ng-attributes",
"jest-preset-angular/build/serializers/ng-snapshot",
"jest-preset-angular/build/serializers/html-comment",
],
transformIgnorePatterns: [
"node_modules/(?!.*\.mjs$)",
"node_modules/(?!lodash-es)",
"node_modules/(?!@ngrx|@ionic-native|@ionic)"
]
};
jest.config.js 在项目根目录:
const { getJestProjects } = require("@nrwl/jest");
module.exports = { projects: getJestProjects() };
jest.preset.js 在根项目中:
const nxPreset = require("@nrwl/jest/preset");
module.exports = {
...nxPreset,
testMatch: ["**/+(*.)+(spec|test).+(ts|js)?(x)"],
transform: {
"^.+\.(ts|js|html)$": "ts-jest",
},
resolver: "@nrwl/jest/plugins/resolver",
moduleFileExtensions: ["ts", "js", "html"],
coverageReporters: ["html"],
};
package.json:
{
"name": "my-app",
"version": "1.1.10",
"license": "MIT",
"scripts": {
...
},
"private": true,
"dependencies": {
"@angular-devkit/architect": "0.1301.2",
"@angular/animations": "13.1.0",
"@angular/common": "13.1.0",
"@angular/compiler": "13.1.0",
"@angular/core": "13.1.0",
"@angular/forms": "13.1.0",
"@angular/platform-browser": "13.1.0",
"@angular/platform-browser-dynamic": "13.1.0",
"@angular/router": "13.1.0",
"@angular/service-worker": "13.1.0",
"@awesome-cordova-plugins/device": "5.37.2",
"@ionic-enterprise/cordova": "9.0.3",
"@ionic-native/app-version": "5.36.0",
"@ionic-native/clipboard": "5.36.0",
"@ionic-native/core": "5.36.0",
"@ionic-native/fingerprint-aio": "5.36.0",
"@ionic-native/in-app-browser": "5.36.0",
"@ionic-native/ionic-webview": "5.36.0",
"@ionic-native/secure-storage": "5.36.0",
"@ionic-native/social-sharing": "5.36.0",
"@ionic-native/splash-screen": "5.36.0",
"@ionic-native/status-bar": "5.36.0",
"@ionic-native/unique-device-id": "5.36.0",
"@ionic/angular": "6.0.0",
"@ionic/storage-angular": "3.0.6",
"@ng-idle/core": "11.1.0",
"@ng-idle/keepalive": "11.0.3",
"@ngx-translate/core": "14.0.0",
"@ngx-translate/http-loader": "7.0.0",
"@sentry/angular": "6.16.1",
"@sentry/tracing": "6.16.1",
"cordova-android": "8.1.0",
"cordova-plugin-device": "2.0.3",
"cordova-plugin-inappbrowser": "5.0.0",
"cordova-plugin-ionic-keyboard": "2.2.0",
"cordova-plugin-ionic-webview": "5.0.0",
"cordova-plugin-splashscreen": "6.0.0",
"cordova-plugin-statusbar": "3.0.0",
"cordova-plugin-whitelist": "1.3.5",
"core-js": "3.19.3",
"crypto-es": "1.2.7",
"document-register-element": "1.14.10",
"dom-to-image": "2.6.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"native-run": "1.5.0",
"ng-circle-progress": "1.6.0",
"node-forge": "0.10.0",
"npm": "8.3.0",
"reflect-metadata": "0.1.13",
"rxjs": "7.4.0",
"sass": "1.45.0",
"tslib": "2.3.1",
"uuid": "8.3.2",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-architects/ddd": "1.5.1",
"@angular-devkit/build-angular": "13.1.0",
"@angular-eslint/builder": "13.0.1",
"@angular-eslint/eslint-plugin": "13.0.1",
"@angular-eslint/eslint-plugin-template": "13.0.1",
"@angular-eslint/schematics": "13.0.1",
"@angular-eslint/template-parser": "13.0.1",
"@angular/cli": "13.1.0",
"@angular/compiler-cli": "13.1.0",
"@angular/language-service": "13.1.0",
"@angularclass/hmr": "3.0.0",
"@ionic/angular-toolkit": "5.0.3",
"@ionic/cli": "6.18.1",
"@nrwl/angular": "13.3.2",
"@nrwl/cli": "13.3.1",
"@nrwl/cypress": "13.3.1",
"@nrwl/eslint-plugin-nx": "13.3.1",
"@nrwl/jest": "13.3.1",
"@nrwl/linter": "13.3.1",
"@nrwl/node": "13.3.1",
"@nrwl/workspace": "13.3.1",
"@schematics/angular": "13.1.0",
"@types/dom-to-image": "2.6.4",
"@types/jest": "27.0.3",
"@types/lodash-es": "4.17.5",
"@types/node": "16.11.12",
"@types/node-forge": "0.10.10",
"@types/uuid": "8.3.3",
"@typescript-eslint/eslint-plugin": "5.3.1",
"@typescript-eslint/parser": "5.3.1",
"codelyzer": "6.0.2",
"compare-func": "2.0.0",
"cordova": "10.0.0",
"cordova-browser": "6.0.0",
"cordova-clipboard": "1.3.0",
"cordova-ios": "6.2.0",
"cordova-plugin-add-swift-support": "2.0.2",
"cordova-plugin-androidx": "3.0.0",
"cordova-plugin-androidx-adapter": "1.1.3",
"cordova-plugin-app-version": "0.1.12",
"cordova-plugin-fingerprint-aio": "5.0.0",
"cordova-plugin-iroot": " 3.1.0",
"cordova-plugin-proguard": "2.2.0",
"cordova-plugin-secure-storage-echo": " 5.1.1",
"cordova-plugin-x-socialsharing": "6.0.3",
"cordova-res": "0.15.4",
"cordova-sqlite-storage": "6.0.0",
"cordova-unique-device-id": "1.3.2",
"cypress": "8.7.0",
"dotenv": "10.0.0",
"dtslint": "4.2.1",
"es6-promise-plugin": "4.2.2",
"eslint": "8.4.1",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-prettier": "4.0.0",
"fuzzy": "0.1.3",
"inquirer": "8.2.0",
"inquirer-autocomplete-prompt": "1.4.0",
"jest": "27.4.5",
"jest-preset-angular": "11.0.1",
"ncu": "0.2.1",
"ng-packagr": "13.1.0",
"ngx-unused-css": "3.0.0",
"npm-check-updates": "12.0.3",
"npx": "10.2.2",
"open": "8.4.0",
"prettier": "2.5.1",
"stylelint": "14.1.0",
"stylelint-config-standard": "24.0.0",
"ts-jest": "27.0.5",
"ts-node": "9.1.1",
"typescript": "^4.4.4",
"webpack": "5.30.0",
"xml2js": "0.4.23"
},
"description": "An ionic project",
"browser": {
"crypto": false,
"stream": false
},
"cordova": {
"plugins": {
"cordova-plugin-ionic-keyboard": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-whitelist": {},
"cordova-plugin-ionic-webview": {},
"cordova-plugin-inappbrowser": {},
"cordova-plugin-x-socialsharing": {
"PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION": "La aplicación requiere acceso a la biblioteca de fotos para funcionar apropiadamente.",
"PHOTO_LIBRARY_USAGE_DESCRIPTION": "La aplicación requiere acceso a la biblioteca de fotos para funcionar apropiadamente."
},
"cordova-plugin-androidx": {},
"cordova-plugin-androidx-adapter": {},
"cordova-plugin-proguard": {},
"cordova-sqlite-storage": {},
"cordova-unique-device-id": {},
"cordova-plugin-app-version": {},
"cordova-plugin-fingerprint-aio": {
"FACEID_USAGE_DESCRIPTION": " "
},
"cordova-plugin-secure-storage-echo": {},
"cordova-plugin-iroot": {},
"cordova-clipboard": {},
"cordova-plugin-add-swift-support": {},
"cordova-plugin-device": {}
},
"platforms": [
"browser",
"ios",
"android"
]
}
}
我仍然不断收到此错误: :/
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
C:\Repos\temp-repos\my-app\node_modules\@angular\core\fesm2015\testing.mjs:7
import { getDebugNode, RendererFactory2, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ModuleWithComponentFactories, InjectionToken, Injector, InjectFlags, ɵresetCompiledComponents, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1728:14)
感谢您的回复。
从我在网上发现的情况来看,这似乎是使用 Jest 并升级到 Angular 13 的项目的常见问题。我们的项目不使用 nx
,但更新我们的笑话配置:
// jest.config.js
const esModules = ['@angular', '@ngrx', 'd3', [...] ];
module.exports = {
// [...]
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true,
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\.html$',
},
},
moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'],
moduleNameMapper: {
'^(\.{1,2}/.*)\.js$': '',
},
transform: {
'^.+\.(ts|js|mjs|html|svg)$': 'jest-preset-angular',
},
transformIgnorePatterns: [
`<rootDir>/node_modules/(?!.*\.mjs$|${esModules.join('|')})`,
]
};
解决我的问题的是 this comment 一个已关闭的问题 (jest-preset-angular)。忽略模块,在我的例子中 @angular
和 @ngrx
,解决了您问题中发布的错误。具体这一行:
const esModules = ['@angular', '@ngrx', 'd3', [...] ];
更新:转换忽略模式合并为 node_module 个文件和模块的单一模式以解决不同的问题。