Skip to content
Advertisement

Angular v13 Jest with nx test – SyntaxError: Cannot use import statement outside a module at Runtime.createScriptFromCode

I tried to follow every comment with a possible solution here to the letter. I relied on an example project on github as well which works perfectly.

This also started to happen to me after updating everything manually and when running the nx test command, occurrs this error.

My jest.config.js inside 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 in the project root:

const { getJestProjects } = require("@nrwl/jest");

module.exports = { projects: getJestProjects() };

jest.preset.js in the root project:

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"
        ]
    }
}

I still keep getting this error: :/

    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:Repostemp-reposmy-appnode_modules@angularcorefesm2015testing.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)

Thansk for your replies.

Advertisement

Answer

From what I’ve found online, this seems like a common issue to projects using Jest and upgrading to Angular 13. Our project doesn’t use nx but here are the updates to our Jest config:

// 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$': '$1',
  },
  transform: {
    '^.+\.(ts|js|mjs|html|svg)$': 'jest-preset-angular',
  },
  transformIgnorePatterns: [
    `<rootDir>/node_modules/(?!.*\.mjs$|${esModules.join('|')})`,
  ]
};

What solved my problem was this comment on a closed issue (jest-preset-angular). Ignoring the modules, in my case @angular and @ngrx, solved the error posted in your question. Specifically this line:

const esModules = ['@angular', '@ngrx', 'd3', [...] ];

Update: The transform ignore patterns merged into a single pattern for node_module files and modules to solve a different issue.

Advertisement