Home > Software design >  Cannot find module '#node-web-compat' from aws-jwt-verify library in Next.js tests
Cannot find module '#node-web-compat' from aws-jwt-verify library in Next.js tests

Time:08-16

Issue description

I'm going to test the service in api used in Next.js app and using babel jest for that specific tests file. The problem that I struggle is issue regarding finding a module and the error that appears in terminal is as in the listing below.

    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)

The tested service is used by TypeScript decorator in middleware. It works as expected when I'm testing it manually but the issue appears only while running tests.

Goal

My goal is unit testing service that uses library aws-jwt-verify to verify JWT accessToken. I would like to mock it and use in my jest unit tests.

tried methods

I've tried to copy dependency to devDependencies and reinstall packages but it didn't help

dependencies in 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"
  },
...
}

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

jest.config.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);

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);
    }
  }
}

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();
    });
  });
});

CodePudding user response:

issue with mock library After trying to downgrade library version to 2.1.3 it helped. I was inspired by issue

Issue with mocking I decided to use spyOn

import { CognitoJwtVerifier } from 'aws-jwt-verify';
...
jest.mock('aws-jwt-verify');

test('my test', () => {
 jest.spyOn(CognitoJwtVerifier, 'create').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'
       })
     };
  });
})

CodePudding user response:

I faced this issue using typescript, jest, and ts-jest. For me this gitHub issue provided the answer. https://github.com/facebook/jest/issues/12619

needed to add this to my jest.config

  moduleNameMapper: {
    '#node-web-compat': "./node-web-compat-node.js",
  }
  • Related