JustinBeckwith / retry-axios

🦖 A super flexible interceptor for Axios that makes it easy to retry requests.
Apache License 2.0
487 stars 62 forks source link

Import fails after Jest v28 update (Cannot use import statement outside a module) #198

Open AKhalil609 opened 2 years ago

AKhalil609 commented 2 years ago

I've been having trouble with imports failing when running tests on the file that has retry-axios imported. This error only appears when running tests with jest ever since jest v28 update. I get no errors when building or running the project.

` FAIL tests/core/HttpClient.spec.ts ● 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 "node_modules" folder is ignored by transformers.

Here'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 "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
 • If you need a custom transformation specify a "transform" 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 "moduleNameMapper" config option.

You'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:

/home/user/monorepo/node_modules/retry-axios/build/src/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import axios from 'axios';
                                                                                  ^^^^^^

SyntaxError: Cannot use import statement outside a module

  1 | import { AxiosInstance } from "axios";
  2 |
> 3 | import { attach } from "retry-axios";
    | ^
  4 |
  5 | import { HttpClientConfig, InterceptorConfig } from "./apiConfig";
  6 |

  at Runtime.createScriptFromCode (../../node_modules/jest-cli/node_modules/jest-runtime/build/index.js:1796:14)
  at Object.<anonymous> (src/core/HttpInterceptorManager.ts:3:1)

Test Suites: 1 failed, 3 passed, 4 total Tests: 9 passed, 9 total Snapshots: 0 total Time: 9.129 s Ran all test suites. error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.`

I tried using a resolver similar to the one used here https://github.com/microsoft/accessibility-insights-web/pull/5421/commits/9ad4e618019298d82732d49d00aafb846fb6bac7 but it didn't work.

jest.config.json file

{
  "clearMocks": true,
  "collectCoverageFrom": [
    "src/**/*.{js,jsx,ts,tsx}",
    "!src/**/*.{test,spec}.{js,jsx}",
    "!**/*.stories.*",
    "!**/node_modules/**",
    "src/**/*.{ts,tsx}",
    "!src/**/*.{test,spec}.{js,ts,tsx}",
    "!src/**/*-interface.ts"
  ],
  "coverageDirectory": "coverage",
  "coverageReporters": [
    "json",
    "lcov",
    "text",
    "clover",
    "cobertura"
  ],
  "coverageThreshold": {
    "global": {
      "branches": 0,
      "functions": 0,
      "lines": 0,
      "statements": 0
    }
  },
  "testEnvironment": "node",
  "preset": "ts-jest",
  "testMatch": [
    "<rootDir>tests/**/*.{test,spec}.{ts,tsx}"
  ],
  "globals": {
    "ts-jest": {
      "tsconfig": "./tests/tsconfig.spec.json"
    }
  }
}

babel.config.ts file

module.exports = {
    presets: [
        [
            "@babel/preset-env",
            {
                targets: {
                    node: "current",
                },
            },
        ],
    ],
};

tsconfig.spec.json

{
  "compilerOptions": {
    "noEmit": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "target": "ES6",
    "esModuleInterop": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "noImplicitAny": true
  },
  "include": [
    "./",
  ],
}
finbargp commented 7 months ago

I hit the same issue. I believe something like https://github.com/JustinBeckwith/retry-axios/pull/243 would fix the root cause but has been closed.

As a workaround (not ideal) you can mock out retry-axios package in your jest tests by adding a mock retry-axios.ts file like this:

export function attach() {}

Then in your jest.config.js add a section like:

moduleNameMapper: { '^retry-axios$': '<rootDir>/path-to-my-mock-file/retry-axios.ts' },

Note this means that retry-axios functionality is totally overridden in your tests. If your tests depend on this they will no longer work. You can either add what you need to the mock file above or find another way to do this.

I think there may be a better way to fix this like transformIgnorePatterns and transform in https://jestjs.io/docs/configuration#transformignorepatterns-arraystring but I spent a bit of time trying things and couldn't get it to work - if anyone does please add it below 😄

Ideally retry-axios wouldn't require us to jump through these hoops - I suspect this will end up driving people away from this package.

JustinBeckwith commented 7 months ago

Yeah I mean if folks want to submit a PR to better support jest, I'm all for it! I just don't really use this package or jest at this point, so it's unlikely something that I'll dig into.

finbargp commented 7 months ago

Hi @JustinBeckwith - thank you for your response and for your work on this package.

From what I understand, the linked PR https://github.com/JustinBeckwith/retry-axios/pull/243 would fix this for jest, as by default jest assumes that packages in node_modules are CommonJS.

JustinBeckwith commented 7 months ago

by default jest assumes that packages in node_modules are CommonJS.

.... seriously!? I obviously want to make sure folks can test with this library, but again - CommonJS is a step backwards and not something we should be trying to support (in the general) sense. I won't go an ESM rant here, but I find it super hard to believe Jest wouldn't be able to support ESM 😆

finbargp commented 7 months ago

I believe there's a way to override the default Jest behaviour with transformIgnorePatterns but I couldn't get it to work.

orgads commented 4 months ago

jest support for ESM is experimental, and you must run node with --experimental-vm-modules for it to work.

See https://jestjs.io/docs/ecmascript-modules