在 firebase/auth 中使用 createUserWithEmailAndPassword 时,Jest 在 Next.js 和 TypeScript 中遇到意外令牌

Att*_*s29 4 firebase typescript jestjs firebase-authentication next.js

我正在尝试在我的 Next.js 项目上设置 firebase 身份验证(使用 TypeScript),并且我相信我遇到了一些与使用 firebase 相关的配置问题,这些问题导致我的 Jest 测试失败。

以下是相关的配置文件:

笑话.config.js:

const nextJest = require("next/jest");

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: "./",
});

// Add any custom config to be passed to Jest
const customJestConfig = {
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
  moduleNameMapper: {
    // Handle module aliases (this will be automatically configured for you soon)
    "^@/components/(.*)$": "<rootDir>/components/$1",
    "^@/pages/(.*)$": "<rootDir>/pages/$1",
  },
  testEnvironment: "jest-environment-jsdom",
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
Run Code Online (Sandbox Code Playgroud)

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "firebase.js"],
  "exclude": ["node_modules"]
}
Run Code Online (Sandbox Code Playgroud)

包.json:

{
  "name": "video-annotator",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest --watch",
    "test:ci": "jest --ci"
  },
  "dependencies": {
    "@emotion/react": "^11.10.5",
    "@emotion/styled": "^11.10.5",
    "@mui/material": "^5.11.3",
    "@next/font": "13.1.1",
    "@types/node": "18.11.18",
    "@types/react": "18.0.26",
    "@types/react-dom": "18.0.10",
    "eslint-config-next": "13.1.1",
    "firebase": "^9.15.0",
    "next": "13.1.1",
    "react": "^18.2.0",
    "react-dom": "18.2.0",
    "react-intl": "^6.2.5",
    "typescript": "4.9.4"
  },
  "devDependencies": {
    "@jest/globals": "^29.3.1",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "eslint": "^8.31.0",
    "eslint-plugin-formatjs": "^4.3.9",
    "jest": "^29.3.1",
    "jest-environment-jsdom": "^29.3.1",
    "next-router-mock": "^0.9.1-beta.0",
    "ts-jest": "^29.0.5"
  }
}
Run Code Online (Sandbox Code Playgroud)

而且,在下面我尝试的一些解决方案中,您可能还需要查看:

tsconfig.jest.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "jsx": "react"
  }
}
Run Code Online (Sandbox Code Playgroud)

我注意到当我添加时我的测试套件开始失败

const userInfo = await createUserWithEmailAndPassword(
          auth,
          email,
          password
        );
Run Code Online (Sandbox Code Playgroud)

到 ln 周围的pages/create-account/index.tsx中的代码库。94.

显示的错误非常奇怪。测试套件失败,因为“Jest 遇到了意外的标记”。

此外,在测试输出的详细信息部分,我看到:

细节:

.../video-annotator/node_modules/firebase/auth/dist/esm/index.esm.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export * from '@firebase/auth';
                                                                                  ^^^^^^

SyntaxError: Unexpected token 'export'

  10 | import { Paper } from "@mui/material";
  11 | import { Button } from "@mui/material";
> 12 | import { AuthContext } from "../contexts/authContext";
     |               ^
  13 | import { useContext } from "react";
Run Code Online (Sandbox Code Playgroud)

我的终端中显示的错误

我确信该语句没有任何问题import { AuthContext } from "../contexts/authContext";,因为如果我将该行代码与上面的代码交换,我会看到以下内容:

语法错误:意外的标记“导出”

  10 | import { Paper } from "@mui/material";
  11 | import { AuthContext } from "../contexts/authContext";
> 12 | import { Button } from "@mui/material";
     |               ^
Run Code Online (Sandbox Code Playgroud)

鉴于我确信 Button 和我的 AuthContext 都不是问题,并且注意到测试中没有错误,直到我在通话中发表评论createUserWithEmailAndPassword

const userInfo = await createUserWithEmailAndPassword(
          auth,
          email,
          password
        );,
Run Code Online (Sandbox Code Playgroud)

,我必须得出结论

  1. 我不知何故滥用了上述陈述,
  2. firebase 导入中发生了其他事情,或者
  3. 我以某种方式错误地配置了 jest,导致它无法与 firebase 配合良好。

我还探讨了错误的“Jest 遇到意外标记”部分:

  1. 我尝试将 "^firebase/auth$": "/node_modules/firebase/auth/dist/esm/index.esm.js" 添加到 moduleNameMapper 中的 jest.config.js 中并重新运行测试。不用找了。

  2. 我在设置过程中使用了 ts-jest 和Rust 编译器而不是 Babel,所以我认为提供的https://jestjs.io/docs/getting-started#using-typescript链接不适用于我的情况。

我确实这样做了,但是尝试将上面看到的原始 jest.config.js 替换为:

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
};
Run Code Online (Sandbox Code Playgroud)

这给了我“Jest遇到意外令牌”错误的新变体:

细节:

/Users/mf/Desktop/video-annotator/__tests__/login.test.tsx:39
    return (0, react_1.render)(<react_intl_1.IntlProvider locale={locale} messages={messages}>
                               ^

SyntaxError: Unexpected token '<'

  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1449:14). 
Run Code Online (Sandbox Code Playgroud)

此错误又与此处报告的问题类似,他们建议将配置文件分成几个部分,以防止从“react”自动更改为“preserve”:

这个问题是因为 jsx 没有被转换而 jest 不知道如何解析它。修复非常简单,在 tsconfig.json 中,您需要将“jsx”键设置为“react”而不是“preserve”。不幸的是,下一个构建期望它是“保留”并自动在 tsconfig.json 中将其更改回 :( 我解决这个问题的方法是创建一个单独的 tsconfig.jest.json。以下是步骤:

创建一个包含以下内容的文件 tsconfig.jest.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "jsx": "react"
  }
}
Run Code Online (Sandbox Code Playgroud)

... 2) 配置 jest.config.js 以使用新的 tsconfig.jest.json。

我也尝试过这个,并没有解决我的问题。

我也在相关的 SO 帖子中尝试了一些其他建议,但似乎没有一个对我的特定情况有帮助。

我主要是在寻找下一步要尝试什么的指导,除非有人立即想到解决方案或错误。我认为我尝试了所有这些不同的解决方案,把事情弄得一团糟。

我应该改用 Babel 吗?Babel 似乎比 ts-jest 拥有更大的社区和历史。

我的存储库(以及我当前所在的创建帐户分支)可以在这里找到。npm install您可以通过克隆存储库、签出 create-account 分支、运行、然后运行 ​​来在本地重现错误npm test。您可能还需要创建一个“./key.ts”文件并用以下内容填充它:

export const secrets = {
  apiKey: "TODO",
  authDomain: "TODO",
  projectId: "TODO",
  storageBucket: "TODO",
  messagingSenderId: "TODO",
  appId: "TODO",
  measurementId: "TODO",
};
Run Code Online (Sandbox Code Playgroud)

另一方面,身份验证确实是该项目的第一个主要功能,因此我认为遵循存储库中的逻辑可能相对简单。无需下载到本地。

预先非常感谢您!

Fcm*_*am5 8

我没有太多使用 NexTJS,所以如果我遗漏了什么,请原谅我。

由于这个答案,我只需添加以下内容就可以运行测试:

module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: [
    '/node_modules/(?!(firebase|@firebase)/)',
  ]
});
Run Code Online (Sandbox Code Playgroud)

然后完整的jest.config.js文件是这样的:

const nextJest = require("next/jest");

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: "./",
});

// Add any custom config to be passed to Jest
const customJestConfig = {
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
  moduleNameMapper: {
    // Handle module aliases (this will be automatically configured for you soon)
    "^@/components/(.*)$": "<rootDir>/components/$1",
    "^@/pages/(.*)$": "<rootDir>/pages/$1",
  },
  testEnvironment: "jest-environment-jsdom",
  
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: [
    '/node_modules/(?!(firebase|@firebase)/)',
  ]
})
Run Code Online (Sandbox Code Playgroud)

我发现测试都是绿色的:)

Test Suites: 2 passed, 2 total
Tests:       13 passed, 13 total
Snapshots:   0 total
Time:        6.104 s
Ran all test suites.
Run Code Online (Sandbox Code Playgroud)

奇怪的是,他们文档中的示例表明我们可以在您的对象中添加相同的模式customJestConfig


旁注:请使您的 Firebase 应用程序的机密无效,并确保将它们从您的存储库中删除。