Jest doesn’t work in a NestJS/TypeScript/ESModules app

I am trying to enable Jest to work in my NestJS application, which I have configured to work in an ESModules package. However, when I run the tests, I get an error:

    <path>/server/src/common/http-exception/http-exception.filter.spec.ts:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { HttpExceptionFilter } from './http-exception.filter.js';                                                                                   
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1495:14)

How to get it to work? I want to continue using ESModules since it works fine in the non-test files.


Here’s my setup (briefly):

  • package.json

    {
      "name": "server",
      "type": "module",
      "scripts": {
        "test": "jest"
      }
    }
    
  • tsconfig.json (some of the shown options are derived from a parent tsconfig; an effective result is shown below)

    {
      "compilerOptions": {
        "noEmit": true, // this is set to 'false' in tsconfig.build.json
        "target": "es2020",
        "module": "esnext",
        "moduleResolution": "NodeNext",
        "sourceMap": true,
    
        "strict": true,
        "allowImportingTsExtensions": false, // this seems to be important; see the note below 👇
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "skipLibCheck": true
      }
    }
    
    • A note about allowImportingTsExtensions. The project is a monorepo, and what’s shown in this question is its server part/package. There’s also a client package. In the client/tsconfig.json, the allowImportingTsExtensions option is set to true. And it works fine: if a component is defined in component.tsx, then the test can import { Component } from './component.tsx' just fine (note: using .tsx extension). Moreover, if I change import … from '….tsx' to import … from '….js' (which should be allowed), it doesn’t work anymore ("the file component.js is not found"). I am perfectly fine with importing .tsx but this behavior requires "moduleResolution": "bundler" and "noEmit": true, which isn’t compatible with how NestJS works (it seems to work with dist/**/*.js files; if there are no files in dist, it’ll fail). Therefore, I set allowImportingTsExtensions to false and use .js extensions in test files. But (I think) if I could set allowImportingTsExtensions to true somehow, and use .ts extensions in imports in test files, this might fix the whole thing. So far, I’m not sure how to do it, and whether this is possible at all with NestJS (and whether it would be the fix).
  • jest.config.ts

    export default {
      preset: 'ts-jest',
      rootDir: '.',
      projects: [
        {
          displayName: 'unit',
          testMatch: ['<rootDir>/src/**/*.spec.ts'],
        },
      ],
    }
    
  • src/common/http-exception/http-exception.filter.ts

    import { BaseExceptionFilter } from '@nestjs/core'
    
    @Catch()
    export class HttpExceptionFilter extends BaseExceptionFilter {
      // implementation
    }
    
  • src/common/http-exception/http-exception.filter.spec.ts

    import { HttpExceptionFilter } from './http-exception.filter.js'
    
    describe('HttpExceptionFilter', () => {
      // tests
    })
    

Leave a Reply

Your email address will not be published.