typescript - Jest ne transformera pas le module - SyntaxError : Impossible d'utiliser l'instruction import en dehors d'un module


Je n'ai pas pu me débarrasser de cette erreur SyntaxError: Cannot use import statement outside a module peu importe ce que j'ai essayé et c'était tellement frustrant. Y a-t-il quelqu'un ici qui a résolu ce problème ? J'ai lu des millions de fils de discussion sur Stack Overflow et GitHub. Aucune solution claire.

Ceci est un projet React, Typescript, Webpack. J'essaie de tester un module. Mais Jest ne transforme pas le module en javascript simple d'une manière ou d'une autre.

L'erreur que je reçois est

/Users/me/dev/Project/project/node_modules/variables/src/variables.js:12
    import './main.js';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      17 | 
      18 | */
    > 19 | import { GlobalVars } from 'variables'
         | ^
      20 | 
      21 | export const Vars = new GlobalVars()
      22 | 

Ce que j'ai essayé pour résoudre cela (et qui n'a pas fonctionné) :

  • Utilisation de la configuration env dans babel.config : env.test.preset : ['@babel/plugin-transform-modules-commonjs']

  • modifier la configuration transform dans Jest comme '^.+\\.jsx?': 'babel-jest', '^.+\\.tsx?': 'ts-jest' et toutes les autres possibilités autour de cela.

  • Dans la configuration de Jest, testPathIgnorePatterns, transformIgnorePatterns

  • Utiliser .babel.config.js au lieu de .babelrc.js

...et plus.

J'ai cette configuration :

package.json

  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node"
  }

.babelrc.js

module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-react',
    '@babel/preset-typescript',
  ],
  plugins: [
    '@babel/plugin-transform-runtime',
    '@babel/proposal-class-properties',
    '@babel/transform-regenerator',
    '@babel/plugin-transform-template-literals',
    'react-hot-loader/babel',
  ],
}

variables.ts

import { GlobalVars } from 'variables'

export const Vars = new GlobalVars()

variables.spec.ts

import { Vars } from './variables.ts'

describe('Test The Package', () => {
  it('Should accept new variables', () => {
    Vars.newVariable = 'new variable'
    expect(Vars.newVariable).toEqual('new variable')
  })
})

Une idée sur la façon de résoudre ce problème ?

Réponse #1

Même si je les ai essayés séparément, je ne les ai pas essayés ensemble (transform et transformIgnorePatterns). Donc, cette configuration de jest a résolu mon problème :

  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node",
    "transform": {
      "node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"
    },
    "transformIgnorePatterns": [
      "node_modules/(?!variables/.*)"
    ]
  },

Mes erreurs étaient :

  1. Ne pas utiliser transform et transformIgnorePatterns ensemble.
  2. Et définir babel-jest comme transformateur au lieu de ts-jest (je suppose que c’est un problème lorsque le pré-réglage de jest est défini comme ts-jest. Parce que si je le change pour babel-jest, cela renvoie à nouveau la même erreur.)
--- "node_modules/variables/.+\\.(j|t)sx?$": "babel-jest"
+++ "node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"

Réponse #2

Utilisez Vitest.

J'ai essayé la plupart des suggestions faites ici. J'ai trouvé que Jest était assez difficile à installer correctement, tandis que Vitest fonctionne immédiatement sans aucune configuration. C'est mon expérience personnelle. Il m'a fallu des jours pour que Jest fonctionne un peu. J'ai eu Vitest qui fonctionnait immédiatement après l'installation.

Je ne veux pas critiquer Jest, je pense en fait que c'est un outil de test merveilleux et intuitif. Mais en fin de compte, Vitest « fonctionne simplement » (tm), et vous pouvez utiliser la même API simple de style Jest que nous avons tous appris à aimer.

Étapes (j'utilise pnpm, mais bien sûr vous pourriez faire la même chose avec yarn ou npm) :

pnpm remove jest ts-jest @types/jest
pnpm add -D vite vitest

Supprimez jest.config.js et créez vite.config.ts :

/// <reference types="vitest" />

import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    /* for example, use global to avoid globals imports (describe, test, expect): */
    // globals: true,
  },
})

Ajouter à vos tests :

import { assert, expect, test } from 'vitest'

Mettez à jour votre package.json :

"test": "vitest",

Réponse #3

Mon problème était différent d’une manière que jest échouait sur les fichiers .js de l’une des dépendances dans node_modules avec SyntaxError: Cannot use import statement outside a module.

Je devais m'assurer que ts-jest n'ignore pas (lors de la transformation) les fichiers .js dans la dépendance problématique.

Après avoir lu attentivement à propos des presets, j'ai réalisé que cela les laisse « tels quels » avec preset: 'ts-jest'. Je l'ai changé en preset: 'ts-jest/presets/js-with-ts' et j'ai défini "allowJs": true dans tsconfig.json.

Pour ne pas gâcher le tsconfig.json de mon projet, j'en ai un séparé pour jest.

Finalement, mon jest.config.js ressemble principalement à ceci :

module.exports = {
    preset: 'ts-jest/presets/js-with-ts',
    testEnvironment: "node",
    globals: {
        'ts-jest': {
            tsconfig: '<rootDir>/test/tsconfig.json',
        },
    },
    transformIgnorePatterns: [
        "node_modules/(?!troublesome-dependency/.*)",
    ],
}

P.S. Je n'avais pas besoin d'un champ transform, puisque le préréglage est déjà dessus.

P.P.S. Je n'ai pas eu besoin d'ajouter de configuration babel

Réponse #4

Puisque Jest ne fonctionne pas bien avec les esmodules, vous devez ajouter ces configurations dans jest.config.js pour indiquer à Jest d'utiliser les builds commonJS à la place

moduleNameMapper: {
  '^variables$': 'variables/dist/cjs',
  '^[NAME OF MODULE YOU WANT TO IMPORT]$': '[NAME OF MODULE YOU WANT TO IMPORT]/dist/cjs'
}