74

I have a Vue.js application where two files contain:

import axios from "axios"

These files are located in src/lib within the application and include the import statement on their first line.

Running tests on Github causes Axios 1.0.0 to be installed, no matter what the package.json says, and now any test involving these files fails with the above error.

Changing the statement to const axios = require("axios") fails also; node_modules/axios/index.js contains an import statement on line 1 and the exception is thrown there.

A suggestion I've seen quite often for such issues is to add "type": "module" to package.json (which is at the same level as src/). This causes all tests to fail with a demand to rename vue.config.js as vue.config.cjs. Doing that gets me: Error: You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously, which I do not understand.

Can anyone suggest what to do here?

knirirr
  • 1,860
  • 4
  • 23
  • 37

13 Answers13

186

I was able to fix this error by forcing jest to import the commonjs axios build by adding

  "jest": {
    "moduleNameMapper": {
      "axios": "axios/dist/node/axios.cjs"
    }
  },

to my package.json. Other solutions using transformIgnorePatterns didn't work for me.

rcbevans
  • 7,101
  • 4
  • 30
  • 46
  • 41
    Someone buy this man a beer, this is the only solution that worked for me. The `transformIgnorePatterns ` solution that is all over StackOverflow did not work, I spent hours on it. This is the only one that did. Thanks @rcbevans – Cheyne Nov 16 '22 at 04:00
  • True, same for me as well! – Kapil Raghuwanshi Dec 01 '22 at 04:48
  • 2
    Thank you so much: I was stuck with this error in a new test suite I was creating and adding axios to the `transformIgnorePatterns` was useless in this case. Your solution fixes my situation – amda Dec 16 '22 at 10:54
  • 3
    Thank you, this also worked for me, but I had to add it to my jest.config.js file. – spetry Jan 06 '23 at 07:51
  • @spetry this can be used anywhere you configure jest in your project. `package.json` under the jest key as in my answer, or a jest specific config file, like `jest.config.js`. – rcbevans Jan 09 '23 at 08:20
  • 8
    If you use react-scripts, this only works if you make changes to package.json. I tried this in jest.config.js, and it has no effect. – user926643 Jan 12 '23 at 20:48
  • 1
    Worked! The dist path may vary by version. For mine it was `axios/dist/axios.js` and I had to add a window global. But it seems to have worked! – isick Mar 20 '23 at 15:50
  • how does package.json look with this change? (where did you put it?) – Toni Michel Caubet Mar 22 '23 at 10:14
  • 1
    @ToniMichelCaubet anywhere at the top level of package.json ` { "name": "...", "version": "1.0.0", ... "jest": { "moduleNameMapper": { "axios": "axios/dist/node/axios.cjs", } }, } ` – rcbevans Mar 24 '23 at 17:28
  • 1
    @user926643 I think that's because you have two configuration locations. It's probably choosing the package.json in your case for some reason. For me it was the other way around and it didn't work until I added it into jest.config.js. I'm gonna merge my configurations now to avoid confusion. – ailish Mar 29 '23 at 15:06
  • 2
    Note that moduleNameMapper keys are regexes, so this answer will affect any file path containing "axios", even if it lives outside the `axios` module. You can scope it down with `"moduleNameMapper": { "^axios$": "axios/dist/node/axios.cjs" }` – this is a bit safer and avoids unintentional re-mappings. – mamacdon Apr 26 '23 at 20:25
  • 1
    This Solution worked for me after trying several combinations of transformIgnorePatterns – Javier May 18 '23 at 21:41
  • This worked for me. I tried many things suggested in many other answers. `package.json` entry as above resolved the issue the test script threw while testing a component that used `axios`. – Prasad Jun 26 '23 at 14:01
  • This works for me. Thanks! – Leon Huang Jul 23 '23 at 21:14
  • This! Thank you so much! – rufatZZ Aug 03 '23 at 15:02
34

The 1.x.x version of axios changed the module type from CommonJS to ECMAScript.

The 0.x.x version of axios index.js file
module.exports = require('./lib/axios');
The 1.x.x version of axiox index.js file
import axios from './lib/axios.js';
export default axios;

Basically, jest runs on Node.js environment, so it uses modules following the CommonJS. If you want to use axios up to 1.x.x, you have to transpile the JavaScript module from ECMAScript type to CommonJS type. Jest ignores /node_modules/ directory to transform basically.

So you have to override transformIgnorePatterns option. There are two ways to override transformIgnorePatterns option.

jest.config.js

If your vue project uses jest.config.js file, you add this option.

module.exports = {
  preset: "@vue/cli-plugin-unit-jest",
  transformIgnorePatterns: ["node_modules/(?!axios)"],
  ...other options
};

package.json

If your vue project uses package.json file for jest, you add this option.

{
  ...other options
  "jest": {
    "preset": "@vue/cli-plugin-unit-jest",
    "transformIgnorePatterns": ["node_modules\/(?!axios)"]
  }
}

This regex can help you to transform axios module and ignore others under node_modules directory.

Junhyunny
  • 717
  • 4
  • 12
18

Updating the version of jest to v29 fixed this in my project. It could be the case that you have an incompatible jest version.

dpopp07
  • 561
  • 5
  • 10
  • 4
    Bingo! This FINALLY got it working for me. Went from v27 to v29 – James Jan 09 '23 at 13:32
  • 1
    Nope, I have the last version and it does not work. – SalahAdDin Jan 26 '23 at 15:02
  • 1
    Thanks! [jest 28.0.0](https://github.com/facebook/jest/blob/main/CHANGELOG.md#2800): “Add support for package.json exports” solved the SyntaxError when my code is `"type": "commonjs"` and the default export of axios 1.0 is `"type": "module"`. – yonran Apr 17 '23 at 23:00
10

Quick fix

Update the npm run test script from

 "test": "react-scripts test",

to

 "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"",
mabdullahse
  • 3,474
  • 25
  • 23
8

This works for me:

Add moduleNameMapper in your jest.config.js

moduleNameMapper: {
    axios: 'axios/dist/node/axios.cjs',
},
Ger Lucio
  • 116
  • 1
  • 2
3

I had the same issues and was able to solve this by using jest-mock-axios library

Gerd Torf
  • 41
  • 4
3

With NestJs if you are facing this issue, then upgrade your package.json with following package versions.

 "jest": "^29.0.0" 

 "ts-jest": "^29.0.0"
2

In my case I had to add the following line to the moduleNameMapper object in the jest config:

axios: '<rootDir>/node_modules/axios/dist/node/axios.cjs',
Luis Breuer
  • 45
  • 1
  • 8
1

I experience similar problem but the error is caused by jest. All the tests trying to import axios fail and throw the same exception:

Test suite failed to run
    Jest encountered an unexpected token
    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • 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/en/configuration.html
    Details:
    /monorepo/node_modules/axios/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import axios from './lib/axios.js';
                                                                                             ^^^^^^
    SyntaxError: Cannot use import statement outside a module
      1 | import { describe, expect, it } from '@jest/globals'
    > 2 | import axios from 'axios'

The solution is simply tell jest that axios should be transformed with babel:

const esModules = ['lodash-es', 'axios'].join('|')

# add these entries in module.exports
transform: {
  [`^(${esModules}).+\\.js$`]: 'babel-jest',
},
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],

Note: I'm using Quasar Vue and this is their implementation.

Covik
  • 746
  • 6
  • 15
1

I faced with the same problem. And firstly used variant (inside package.json file):

"jest": {
    "moduleNameMapper": {
      "axios": "axios/dist/node/axios.cjs"
    }
  },

But for mocking I use axios-mock-adapter. And I got the error:

TypeError: mock.onGet is not a function

I changed code to:

"jest": {
       "transformIgnorePatterns": [
          "/node_modules/(?!(axios)/)"
        ]
     }

And this solution works. The versions:

  • "axios": "^1.4.0"

  • "axios-mock-adapter": "^1.21.5"

  • "@types/axios-mock-adapter": "^1.10.0"

0

As an alternative approach when working with Jest and Typescript, you can mock the individual functions you require for your test:

import axios from 'axios'

jest.mock('axios', () => ({
  post: jest.fn(),
  get: jest.fn()
}))

const mockedAxios = axios as jest.Mocked<typeof axios>

mockedAxios.post.mockResolvedValue({})

Although this approach worked for me, asking babel to transpile axios also did the trick:

// jest.config.js
module.exports = {
  transformIgnorePatterns: [
   '/node_modules/(?!(axios)/).*'
  ],
}
David
  • 97
  • 9
0

For Axios, add the following code to your package.json;

    "jest": {
       "transformIgnorePatterns": [
          "/node_modules/(?!(axios)/)"
        ]
     }
Calvin Odira
  • 61
  • 1
  • 3
-2

I had the same issue, it works fine when changing axios to fetch.

axios (Fail)

 try {
        const response = await axios("api/fruit/all");
        return response.data;
      } catch (error) {
        return error;
  }

Fetch (Works fine)

  try {
    const response = await fetch("api/fruit/all",{method:"GET"});
    const data = await response.json();
    return data;
  } catch (error) {
    return error;
  }