36

This seems a bit weird to me. I'm trying to test an actual (ie. real network) request with Jest.

These are the tested scenarios:

  • Test an external API (fixer.io) with no headers <--- This works
  • Test a local API server with headers <--- This does NOT work
  • Test same local API with headers from node terminal <--- This works

What could be the reason behind this behavior? And what is the solution?

//This WORKS
test('testing no headers', () => {
  return axios.get('http://api.fixer.io/latest')
        .then( res => console.log(res) )
});

//This DOES NOT work
test('testing no headers', () => {
  return axios.get('http://localhost:3000/users/4/profile', 
                      {headers:{authorization:`Bearer ${mytoken}`}})
        .then( res => console.log(res) )
});

//...

//Node Terminal
//This WORKS
> axios.get('http://localhost:3000/users/4/profile', 
                   {headers:{authorization:`Bearer ${mytoken}`}})
        .then( res => console.log(res) )
Brian Adams
  • 43,011
  • 9
  • 113
  • 111
lllllll
  • 4,715
  • 6
  • 29
  • 42
  • Here is a similar case: https://stackoverflow.com/questions/58785617/cors-error-error-cross-origin-http-localhost-forbidden-in-reactjs-jest-te/76718461. See my answer using `supertest` library – Michael Rovinsky Jul 19 '23 at 06:22

5 Answers5

50

It can be a Jest configuration issue. I solved forcing "node" as jest environment in package.json:

"jest": { "testEnvironment": "node" }

see docs: https://facebook.github.io/jest/docs/configuration.html#testenvironment-string

Daniele Dellafiore
  • 1,867
  • 1
  • 15
  • 19
  • 2
    This helped me to make get requests. But I still get the error on the post request. Any clue? – sbkl Aug 19 '17 at 01:01
  • Great solution! – Gompro Feb 20 '18 at 11:52
  • @sbkl got [Reference error: fetch is not defined] when using node environment for POST and PUTs. Node environment doesn't have access to window.fetch like jsdom does, so you'll have to use a fetch library thats friendly to both browser and server like this [one](https://www.npmjs.com/package/isomorphic-fetch) – devonj Feb 21 '18 at 21:00
  • You might also want to up the timeout if you're making a lot of calls... jest.setTimeout(600000) – Max Phillips Jan 07 '21 at 18:41
34

That is funny,that the axios used XMLHttpRequest by primary,and ajax request can't access across domain,so your test failed ,so you can let your code pass by set the axios adapter.

The Reason by axios/defaults.js

 function getDefaultAdapter() {
    var adapter;
    if (typeof XMLHttpRequest !== 'undefined') {
        // For browsers use XHR adapter
        adapter = require('./adapters/xhr');
    } else if (typeof process !== 'undefined') {
        // For node use HTTP adapter
        adapter = require('./adapters/http');   
    }
    return adapter;
 }

Solution change axios adapter to http

import axios from 'axios';
//This WORKS
test('testing with headers', (done) => {
    var path=require('path');
    var lib=path.join(path.dirname(require.resolve('axios')),'lib/adapters/http');
    var http=require(lib);
    axios.get('http://192.168.1.253', {
        adapter: http,
        headers: {
            Authorization: "Basic YWRtaW46bHVveGlueGlhbjkx"
        }
    }).then((res) => {
        expect(res.status).toBe(200);
        done();
    }).catch(done.fail);
});

Solution change jest testURL in package.json

"jest": {
   "testURL":"http://192.168.1.253"
}

then the test can be access http via ajax

import axios from 'axios';
    //This WORKS
    test('testing with headers', (done) => {
        axios.get('http://192.168.1.253', {
            headers: {
                Authorization: "Basic YWRtaW46bHVveGlueGlhbjkx"
            }
        }).then((res) => {
            expect(res.status).toBe(200);
            done();
        }).catch(done.fail);
    });
holi-java
  • 29,655
  • 7
  • 72
  • 83
  • Thanks for the reply. I suspected it had to do with with the adapter. I'm now quite puzzled about the `testURL` parameter in the package.json. I did have an old setting `localhost:8080` which I forgot about, now changing to `localhost:3000` *does* make it work. I'll try to figure out how `Jest` uses this conflictive `testURL` param... – lllllll Mar 08 '17 at 19:23
  • 2
    the problem is ajax access cross domain,because jsdom default url in jest is `about:blank`,I have tried to change the `document.url` but not successful,only via `testURL` option can change the ajax `origin` url. – holi-java Mar 08 '17 at 19:25
  • 1
    But shouldn't Jest pay attention to whether something (ie. axios in this case) is specifying another domain? What if different tests make requests to different domains in the same app? – lllllll Mar 08 '17 at 19:28
  • I found no solutions to solve this problem,only to change axios adapers. – holi-java Mar 08 '17 at 19:30
  • 1
    @holi-java changing to http affects api response type or any other side effect on existing api call made previously ?? – Ashish Sharma Jun 18 '19 at 10:26
  • This helped me resolve an issue i had with using axios inside wallaby.js test runner. Thank you – Pablo Jomer Jul 01 '19 at 04:44
  • @holi-java I'm having strange problem and can't identify the issue may you please take a look at https://stackoverflow.com/questions/62591323/how-to-reproduce-jest-network-error-floating-bug-locally ? – Arseniy-II Jun 26 '20 at 11:04
  • 1
    @Arseniy-II Unfortunately, I come from China and can't see the image of your question on SO. My answer here assume the OP that has started a local resource server listening on the port `3000` before run the test, so you should ensure your own resource server started first. – holi-java Jun 27 '20 at 15:11
32

Jest allows you to set a setup script file. This file will be required before everything else and gives you a chance to modify the environment in which the tests will run. This way you can unset XMLHttpRequest before axios is loaded and the adapter type evaluated since imports are hoisted. https://facebook.github.io/jest/docs/configuration.html#setuptestframeworkscriptfile-string

This worked for me:

package.json

{
  ...,
  "jest": {
    ...,
    "setupTestFrameworkScriptFile": "./__tests__/setup.js",
    ...
  },
  ...
}

__tests__/setup.js

global.XMLHttpRequest = undefined;
chris
  • 6,653
  • 6
  • 41
  • 54
  • nice solution but `setup.js` needs to be moved out the `__tests__` folder otherwise you will get error that test failed in `setup.js` file – Ilya G Feb 19 '19 at 21:25
16

I resolved it by adding

axios.defaults.adapter = require('axios/lib/adapters/http');

for a specific test case file, as setting global.XMLHttpRequest = undefined or env=node was causing my other test cases to fail.

Ashish Sharma
  • 669
  • 6
  • 13
0

I work on Next.js projects where I have both frontend and backend tests and setting testEnvironment to 'node' does not work.

So I configure jest.config.js as

testEnvironment: 'jest-environment-jsdom',

and add

/**
 * @jest-environment node
 */

to all backend tests.

Ruslan Kazakov
  • 433
  • 5
  • 4