在 Next.js 测试中无法从 aws-jwt-verify 库中找到模块“#node-web-compat”

Kam*_*erz 6 unit-testing jwt typescript jestjs next.js

问题描述

我将在 Next.js 应用程序中使用的 api 中测试该服务,并针对该特定测试文件使用 babel jest。我遇到的问题是有关查找模块的问题,终端中出现的错误如下列表所示。

    Cannot find module '#node-web-compat' from 'node_modules/aws-jwt-verify/dist/cjs/https.js'

    Require stack:
      node_modules/aws-jwt-verify/dist/cjs/https.js
      node_modules/aws-jwt-verify/dist/cjs/jwk.js
      node_modules/aws-jwt-verify/dist/cjs/jwt-rsa.js
      node_modules/aws-jwt-verify/dist/cjs/index.js
      pages/api/auth/auth.service.ts
      __tests__/sign-up/api/auth/auth-service.test.ts

      at Resolver._throwModNotFoundError (node_modules/jest-resolve/build/resolver.js:491:11)
      at Object.<anonymous> (node_modules/aws-jwt-verify/dist/cjs/https.js:9:28)
Run Code Online (Sandbox Code Playgroud)

测试的服务由中间件中的 TypeScript 装饰器使用。当我手动测试它时,它按预期工作,但仅在运行测试时才会出现问题。

目标

我的目标是使用库aws-jwt-verify来验证 JWT accessToken 的单元测试服务。我想模拟它并在我的jest单元测试中使用。

尝试过的方法

我尝试将依赖项复制到devDependencies并重新安装软件包,但没有帮助

package.json 中的依赖项

{
...
  "dependencies": {
    "@aws-sdk/client-cognito-identity-provider": "^3.137.0",
    "@chakra-ui/react": "^2.2.3",
    "@emotion/react": "^11",
    "@emotion/styled": "^11",
    "@hookform/resolvers": "^2.9.7",
    "@storyofams/next-api-decorators": "^1.8.2",
    "@tanstack/react-query": "^4.0.10",
    "@tanstack/react-query-devtools": "^4.0.10",
    "aws-jwt-verify": "^3.1.0",
    "axios": "^0.27.2",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.13.2",
    "cookie": "^0.5.0",
    "framer-motion": "^6",
    "next": "latest",
    "react": "^18.2.0",
    "react-cookie": "^4.1.1",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.34.0",
    "react-icons": "^4.4.0",
    "storybook-addon-next-router": "^4.0.0",
    "zod": "^3.17.10"
  },
...
}
Run Code Online (Sandbox Code Playgroud)

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

Run Code Online (Sandbox Code Playgroud)

笑话配置.js

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

const createJestConfig = nextJest({
 test environment
  dir: './'
});

const customJestConfig = {for alias' to work
  moduleDirectories: ['node_modules', '<rootDir>/']
};

module.exports = createJestConfig(customJestConfig);
Run Code Online (Sandbox Code Playgroud)

auth.service.ts

// auth.service.ts
import { CognitoJwtVerifier } from 'aws-jwt-verify';
import { BadRequestException } from '@storyofams/next-api-decorators';
import { CognitoAccessTokenPayload } from 'aws-jwt-verify/jwt-model';

export class AuthService {
  async verifyToken(token: string): Promise<boolean> {
    const verifier = CognitoJwtVerifier.create({
      userPoolId: process.env.COGNITO_USER_POOL_ID,
      tokenUse: 'access',
      clientId: process.env.COGNITO_WEB_CLIENT_ID
    });

    try {
      const verifyResult: CognitoAccessTokenPayload = await verifier.verify(token);

      const isNotExpired = verifyResult.exp > Math.floor(Date.now() / 1000);
      const isCorrectClient = verifyResult.client_id === process.env.COGNITO_WEB_CLIENT_ID;
      const isCorrectUserPool =
        verifyResult.iss ===
        `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`;
      const isTokenUseValid = verifyResult.token_use === 'access';

      return isNotExpired && isCorrectClient && isCorrectUserPool && isTokenUseValid;
    } catch (e) {
      throw new BadRequestException(e.message);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

auth-service.test.ts

// auth-service.test.ts
describe('Auth Service', () => {
  describe('verifyToken', () => {
    beforeEach(() => {
      jest.clearAllMocks();
    });

    it('should verify token successfully', async () => {
      jest.mock('aws-jwt-verify', () => {
        return {
          CognitoJwtVerifier: jest.fn().mockImplementation(() => {
            return {
              verify: jest.fn().mockResolvedValue({
                exp: Math.floor(Date.now() / 1000) + 3600,
                client_id: process.env.COGNITO_WEB_CLIENT_ID,
                iss: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`,
                token_use: 'access'
              })
            };
          })
        };
      });
      const authService = new AuthService();
      const result = await authService.verifyToken('token');
      expect(result).toBeTruthy();
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

小智 10

我使用 typescript、jest 和 ts-jest 遇到了这个问题。对我来说,这个 gitHub 问题提供了答案。 https://github.com/facebook/jest/issues/12619

需要将其添加到我的 jest.config 中

  moduleNameMapper: {
    '#node-web-compat': "./node-web-compat-node.js",
  }
Run Code Online (Sandbox Code Playgroud)