Jest测试套件无法运行,导入模块时出现意外标记 – TypeScript

huangapple go评论69阅读模式
英文:

Jest - Test suite failed to run with unexpected token on import module - TypeScript

问题

我在Vite和TypeScript项目上有一个测试未能运行的问题。

我一直在尝试使用多种配置解决这个问题,但是到目前为止,我还没有能够解决它。

{
  "plugins": ["syntax-dynamic-import", "transform-runtime"],
  "presets": [
    ["es2015", {
      "modules": false
    }],
    "react",
    "stage-0"
  ],
  "env": {
    "start": {
      "presets": ["react-hmre"]
    },
    "test": {
      "presets": ["es2015", "react", "stage-0"]
    }
  }
}
{
  "moduleDirectories": ['node_modules'],
  "transform": {
    '\\.tsx?$': 'ts-jest',
    '\\.jsx?$': 'babel-jest'
  },
  "globals": {
    "ts-jest": {
      "tsConfig": '<rootDir>/tsconfig.json'
    }
  },
  "transformIgnorePatterns": ['[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$']
}
import 'whatwg-fetch';
{
  "name": "podtunes",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview",
    "test": "jest --watchAll"
  },
  "dependencies": {
    "localstorage-slim": "^2.4.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.11.1",
    "styled-components": "^5.3.10"
  },
  "devDependencies": {
    "@babel/core": "^7.21.8",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/plugin-transform-modules-commonjs": "^7.21.5",
    "@babel/plugin-transform-runtime": "^7.21.4",
    "@babel/preset-env": "^7.21.5",
    "@babel/preset-react": "^7.18.6",
    "@testing-library/react": "^14.0.0",
    "@types/jest": "^29.5.1",
    "@types/react": "^18.0.28",
    "@types/react-dom": "^18.0.11",
    "@types/styled-components": "^5.1.26",
    "@typescript-eslint/eslint-plugin": "^5.57.1",
    "@typescript-eslint/parser": "^5.57.1",
    "@vitejs/plugin-react": "^4.0.0",
    "babel-jest": "^29.5.0",
    "eslint": "^8.38.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.3.4",
    "jest": "^29.5.0",
    "ts-jest": "^29.1.0",
    "ts-node": "^10.9.1",
    "typescript": "^5.0.4",
    "vite": "^4.3.2",
    "whatwg-fetch": "^3.6.2"
  },
  "resolutions": {
    "styled-components": "^5"
  }
}
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true
  },
  "moduleDirectories": ["node_modules", "src"],
  "include": ["src"]
}
英文:

I have a test on a Vite & TypeScript project which fails to run.

I have been working on this issue trying to solve it with several configurations, however, I haven't been able to solve it.

ts-jest[ts-jest-transformer] (WARN) Define `ts-jest` config under `globals` is deprecated. Please do
transform: {
    &lt;transform_regex&gt;: [&#39;ts-jest&#39;, { /* ts-jest config goes here in Jest */ }],
},
ts-jest[backports] (WARN) &quot;[jest-config].globals.ts-jest.tsConfig&quot; is deprecated, use &quot;[jest-config].globals.ts-jest.tsconfig&quot; instead.
ts-jest[backports] (WARN) Your Jest configuration is outdated. Use the CLI to help migrating it: ts-jest config:migrate &lt;config-file&gt;.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
 FAIL  __tests__/components/Header.test.tsx
  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default &quot;node_modules&quot; folder is ignored by transformers.

    Here&#39;s what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your &quot;node_modules&quot; files transformed, you can specify a custom &quot;transformIgnorePatterns&quot; in your config.
     • If you need a custom transformation specify a &quot;transform&quot; option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the &quot;moduleNameMapper&quot; config option.

    You&#39;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:

    /Users/xxxx/Code/xxxx/xxxxx/src/assets/fonts/ABCMonumentGrotesk-Regular.woff2:1
    ({&quot;Object.&lt;anonymous&gt;&quot;:function(module,exports,require,__dirname,__filename,jest){wOF2


    SyntaxError: Invalid or unexpected token

      1 | import { createGlobalStyle } from &#39;styled-components&#39;;
      2 |
    &gt; 3 | import ABCWoff2Regular from &#39;../assets/fonts/ABCMonumentGrotesk-Regular.woff2&#39;;
        | ^
      4 | import ABCWoffRegular from &#39;../assets/fonts/ABCMonumentGrotesk-Regular.woff&#39;;
      5 | import ABCWoff2Medium from &#39;../assets/fonts/ABCMonumentGrotesk-Medium.woff2&#39;;
      6 | import ABCWoffMedium from &#39;../assets/fonts/ABCMonumentGrotesk-Medium.woff&#39;;

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1495:14)
      at Object.&lt;anonymous&gt; (src/styles/FontFamily.ts:3:1)
      at Object.&lt;anonymous&gt; (src/styles/index.ts:2:1)
      at Object.&lt;anonymous&gt; (src/components/Logo.tsx:3:1)
      at Object.&lt;anonymous&gt; (src/components/index.ts:2:1)
      at Object.&lt;anonymous&gt; (__tests__/components/Header.test.tsx:4:1)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.555 s  

The above error has the following configuration:

Notice that __tests__ folder is on the same level that src folder.

Jest测试套件无法运行,导入模块时出现意外标记 – TypeScript

This is my .babelrc

{
  &quot;plugins&quot;: [&quot;syntax-dynamic-import&quot;, &quot;transform-runtime&quot;],
  &quot;presets&quot;: [
    [
      &quot;es2015&quot;,
      {
        &quot;modules&quot;: false
      }
    ],
    &quot;react&quot;,
    &quot;stage-0&quot;
  ],
  &quot;env&quot;: {
    &quot;start&quot;: {
      &quot;presets&quot;: [&quot;react-hmre&quot;]
    },
    &quot;test&quot;: {
      &quot;presets&quot;: [&quot;es2015&quot;, &quot;react&quot;, &quot;stage-0&quot;]
    }
  }
}

And my jest.config.js

export default {
  moduleDirectories: [&#39;node_modules&#39;],
  transform: {
    &#39;\\.tsx?$&#39;: &#39;ts-jest&#39;,
    &#39;\\.jsx?$&#39;: &#39;babel-jest&#39;, // if you have jsx tests too
  },
  globals: {
    &#39;ts-jest&#39;: {
      tsConfig: &#39;&lt;rootDir&gt;/tsconfig.json&#39;,
    },
  },
  transformIgnorePatterns: [&#39;[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$&#39;],
};

My jest.setup.js

import &#39;whatwg-fetch&#39;;

My package.json

{
  &quot;name&quot;: &quot;podtunes&quot;,
  &quot;private&quot;: true,
  &quot;version&quot;: &quot;0.0.0&quot;,
  &quot;type&quot;: &quot;module&quot;,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;vite&quot;,
    &quot;build&quot;: &quot;tsc &amp;&amp; vite build&quot;,
    &quot;lint&quot;: &quot;eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0&quot;,
    &quot;preview&quot;: &quot;vite preview&quot;,
    &quot;test&quot;: &quot;jest --watchAll&quot;
  },
  &quot;dependencies&quot;: {
    &quot;localstorage-slim&quot;: &quot;^2.4.0&quot;,
    &quot;react&quot;: &quot;^18.2.0&quot;,
    &quot;react-dom&quot;: &quot;^18.2.0&quot;,
    &quot;react-router-dom&quot;: &quot;^6.11.1&quot;,
    &quot;styled-components&quot;: &quot;^5.3.10&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.21.8&quot;,
    &quot;@babel/plugin-syntax-dynamic-import&quot;: &quot;^7.8.3&quot;,
    &quot;@babel/plugin-transform-modules-commonjs&quot;: &quot;^7.21.5&quot;,
    &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.21.4&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.21.5&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.18.6&quot;,
    &quot;@testing-library/react&quot;: &quot;^14.0.0&quot;,
    &quot;@types/jest&quot;: &quot;^29.5.1&quot;,
    &quot;@types/react&quot;: &quot;^18.0.28&quot;,
    &quot;@types/react-dom&quot;: &quot;^18.0.11&quot;,
    &quot;@types/styled-components&quot;: &quot;^5.1.26&quot;,
    &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^5.57.1&quot;,
    &quot;@typescript-eslint/parser&quot;: &quot;^5.57.1&quot;,
    &quot;@vitejs/plugin-react&quot;: &quot;^4.0.0&quot;,
    &quot;babel-jest&quot;: &quot;^29.5.0&quot;,
    &quot;eslint&quot;: &quot;^8.38.0&quot;,
    &quot;eslint-plugin-react-hooks&quot;: &quot;^4.6.0&quot;,
    &quot;eslint-plugin-react-refresh&quot;: &quot;^0.3.4&quot;,
    &quot;jest&quot;: &quot;^29.5.0&quot;,
    &quot;ts-jest&quot;: &quot;^29.1.0&quot;,
    &quot;ts-node&quot;: &quot;^10.9.1&quot;,
    &quot;typescript&quot;: &quot;^5.0.4&quot;,
    &quot;vite&quot;: &quot;^4.3.2&quot;,
    &quot;whatwg-fetch&quot;: &quot;^3.6.2&quot;
  },
  &quot;resolutions&quot;: {
    &quot;styled-components&quot;: &quot;^5&quot;
  }
}

Also, tsconfig.json

{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,
    &quot;lib&quot;: [&quot;DOM&quot;, &quot;DOM.Iterable&quot;, &quot;ESNext&quot;],
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;skipLibCheck&quot;: true,

    /* Bundler mode */
    &quot;moduleResolution&quot;: &quot;bundler&quot;,
    &quot;allowImportingTsExtensions&quot;: true,
    &quot;resolveJsonModule&quot;: true,
    &quot;isolatedModules&quot;: true,
    &quot;noEmit&quot;: true,
    &quot;jsx&quot;: &quot;react-jsx&quot;,

    /* Linting */
    &quot;strict&quot;: true,
    &quot;noUnusedLocals&quot;: false,
    &quot;noUnusedParameters&quot;: false,
    &quot;noFallthroughCasesInSwitch&quot;: true
  },
  &quot;moduleDirectories&quot;: [&quot;node_modules&quot;, &quot;src&quot;],
  &quot;include&quot;: [&quot;src&quot;]
}

Any help will be greatly appreciated it!

答案1

得分: 1

开始解决你的原始问题——Jest试图将你的字体(woff、woff2)文件解析为JavaScript,并且失败了。

这是Jest的默认行为,我们必须给它一个提示,告诉它不应该这样做。在你的 jest.config.js 中添加:

moduleNameMapper: { '.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js' }

这样,每当Jest遇到woff|woff2文件时,它将导入fileMock.js,它是纯JS,因此不会有解析问题。到目前为止还好。

但是你在这里犯的错误是如何定义你的 fileMock.js

export default 'test-file-stub';

乍一看没问题,但它会产生以下错误 SyntaxError: Unexpected token 'export',这意味着Jest无法处理映射文件中的ES6。

幸运的是,将 fileMock.js 切换到CommonJS格式就可以解决:

module.exports = {};

现在最后的问题是你没有为你的测试使用TypeScript预设。没有它,TS既不能被转译也不能进行类型检查。这导致了 SyntaxError: Cannot use import statement outside a module

为了解决这个问题,我决定在你的测试中使用 ts-jest,因为与babel预设不同,它在运行测试时执行类型检查。有了这个和一些清理,这是你现在的 jest.config.js

export default {
  preset: "ts-jest",
  testEnvironment: "jsdom",
  moduleNameMapper: {
    '.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js',
  },
};

而且,这将使你的测试转译工作!


超出范围,但是让我们让它工作

请注意,我添加了:

testEnvironment: "jsdom"

这是因为你正在进行UI测试,它们需要某种DOM实现。Jest的默认环境是 node,所以我将其更改为 jsdom,它提供了你的UI测试所需的DOM。

你必须运行 yarn add -D jest-environment-jsdom 来完成它。

还要注意,你可以根据需要向 moduleNameMapper 添加尽可能多的扩展名,我只提供了一个以保持简洁。

英文:

Let's start with your original issue - Jest was trying to parse your font (woff, woff2) files as JavaScript and it failed.

This is what Jest does by default, and we have to give it a hint that it shouldn't. Add to your jest.config.js:

moduleNameMapper: { &#39;.*\\.woff.?&#39;: &#39;&lt;rootDir&gt;/__mocks__/fileMock.js&#39; }

This way, whenever Jest encounters a woff|woff2 file, it will import the fileMock.js instead, which is pure JS so there is no problem with parsing. So far so good.

The mistake you have made here however is in how you defined your fileMock.js:

export default &#39;test-file-stub&#39;;

On the first glance ok, but it produces the following SyntaxError: Unexpected token &#39;export&#39;, which means Jest is not handling ES6 in mapped files well.

Fortunately, switching fileMock.js to CommonJS format fixes it:

module.exports = {};

Now the last issue was that you were not using a TypeScript preset for your tests. Without it TS can't be transpiled nor type-checked. This gave you SyntaxError: Cannot use import statement outside a module.

In order to fix that, I decided to use ts-jest in your tests since unlike the babel preset, it performs type-checking while running your tests. With that and some clean up, this is your jest.config.js now:

export default {
  preset: &quot;ts-jest&quot;,
  testEnvironment: &quot;jsdom&quot;,
  moduleNameMapper: {
    &#39;.*\\.woff.?&#39;: &#39;&lt;rootDir&gt;/__mocks__/fileMock.js&#39;,
  },
};

And voila, this will make your test transpilation work!


Out of scope, but hell, let's make it work

Notice that I added:

testEnvironment: &quot;jsdom&quot;

This is because you are doing UI tests and they require some kind of DOM implementation. The default environment for Jest is node, so I changed it to jsdom which provides the DOM needed for your UI testing.

You have to yarn add -D jest-environment-jsdom to round it up.

Also note that you can add as many extensions to moduleNameMapper as you need, I provided only one to keep it concise.

huangapple
  • 本文由 发表于 2023年5月10日 16:43:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76216490.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定