axios: axios 0.19.1 breaks jest tests that use nock

Describe the bug After upgrading axios from 0.19.0 to 0.19.1 all tests that use nock got broken. They now produce the following error:

Error: Cross origin http://localhost forbidden

To Reproduce Repo with minimal test case that reproduces the issue: https://github.com/EvgenyOrekhov/js-framework/tree/axios-bug.

Note that previous commit (which has axios 0.19.0) works fine, the test passes.

import axios from "axios";
import nock from "nock";

it("makes HTTP requests", async done => {
  const scope = nock("https://example.com/foo/")
    .get("/bar")
    .reply(200, { foo: "bar" });

  await axios.get("https://example.com/foo/bar");

  scope.done();
  done();
});

Expected behavior The test should pass.

Environment:

  • Axios Version: 0.19.1
  • OS: Ubuntu 19.10
  • Browser: n/a
  • Browser Version: n/a
  • Additional Library Versions: nock 11.7.2

Additional context/Screenshots Jest error with stack trace:

 FAIL  src/http.test.js
  ✕ makes HTTP requests (34ms)

  ● makes HTTP requests

    Network Error

      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at XMLHttpRequest.handleError (node_modules/axios/lib/adapters/xhr.js:83:14)
      at XMLHttpRequest.<anonymous> (node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js:33:32)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
      at XMLHttpRequestEventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
      at XMLHttpRequestEventTargetImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
      at XMLHttpRequest.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
      at requestErrorSteps (node_modules/jsdom/lib/jsdom/living/xhr-utils.js:132:7)
      at dispatchError (node_modules/jsdom/lib/jsdom/living/xhr-utils.js:62:3)
      at Object.validCORSHeaders (node_modules/jsdom/lib/jsdom/living/xhr-utils.js:77:5)
      at receiveResponse (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:847:21)
      at Request.<anonymous> (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:679:38)
      at Request.onRequestResponse (node_modules/request/request.js:1066:10)
      at respond (node_modules/nock/lib/playback_interceptor.js:299:11)
      at respondUsingInterceptor (node_modules/nock/lib/playback_interceptor.js:341:7)
      at node_modules/nock/lib/playback_interceptor.js:281:7

  console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Cross origin http://localhost forbidden
        at dispatchError (/home/user/my-app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
        at Object.validCORSHeaders (/home/user/my-app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:77:5)
        at receiveResponse (/home/user/my-app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:847:21)
        at Request.<anonymous> (/home/user/my-app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:679:38)
        at Request.emit (events.js:321:20)
        at Request.onRequestResponse (/home/user/my-app/node_modules/request/request.js:1066:10)
        at OverriddenClientRequest.emit (events.js:321:20)
        at respond (/home/user/my-app/node_modules/nock/lib/playback_interceptor.js:299:11)
        at respondUsingInterceptor (/home/user/my-app/node_modules/nock/lib/playback_interceptor.js:341:7)
        at /home/user/my-app/node_modules/nock/lib/playback_interceptor.js:281:7 undefined

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 12
  • Comments: 16 (1 by maintainers)

Most upvoted comments

Here’s how you can solve this. (If you don’t test for CORS).

Have nock include Access-Control-Allow-Origin in the response.

.reply(200, 'hello world', {'Access-Control-Allow-Origin': '*'})

Or use it with nocks’s default reply headers option

Hmm… switching the test environment to “node”, does not help when you test a react app. jsdom is needed for the tests to work that rely on browser environment.

This seems to be related to using jsdom’s XHR, as a workaround you can switch the test environment to "node". This has the advantage that you then don’t have to explicitly configure Axios to use the Node adapter, as mentioned in Nock’s docs.

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

I ended up having to setup a persistent OPTIONS handler as well. My final code looked like this:

// Your configuration of headers and target url
//
const allowedHeaders = [
  'ClientName',
  'ClientVersion',
  'Content-Type',
  'Authorization',
];
const nockHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': allowedHeaders.join(',') };
const url = 'https://example.com';

// Persistent OPTIONS handler
//
nock(url).intercept(/./, 'OPTIONS').reply(200, undefined, nockHeaders).persist();

// Actual mock call
//
nock(url).defaultReplyHeaders(nockHeaders).post(path).reply(200, mockResponse);

I also did not have the option of switching to the node environment for Jest.

The alternative is setting the axios default adapter as @textbook said:

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

If you checkout the Jest docs for test environment you can add a docblock in the specific test file to change the envrironment e.g. changing the .ts file to node would be:

Docblock:

/**
 * @jest-environment node || jsdom
 */

My test file.ts:

/**
 * @jest-environment node 
 */

describe('api-client', () => {
  it('should intercept a 401 status code', (done) => {
    const statusCode = 401
    const testError = [
      { code: 'AUTHENTICATION_FAILURE', message: 'Authentication Failure' },
    ]
    const scope = nock(apiUrl!).get('/products').reply(statusCode, testError)

    fetchProducts()
      .then()
      .catch((error) => {
        expect(error.response.status).toBe(statusCode)
        expect(sessionStorage.removeItem).toHaveBeenCalledTimes(1)
        scope.done()
        done()
      })
  })
});

If you are making node application (backend etc) set Jest testEnvironment to node so Axios won’t act like browser client when doing requests. More info here: https://jestjs.io/docs/configuration#testenvironment-string

In your spec file @DanJClarke

Where would I add the axios.defaults.adapter = require('axios/lib/adapters/http'); in the jest.config.js or the actual spec?

I confirm that zWingz’s workaround works. Feel free to close this issue.

I was also getting the same error with node+jest in axios post and was getting error Error: Response for preflight has invalid HTTP status code 400 and got resolved by axios.defaults.adapter = require(‘axios/lib/adapters/http’);

Thank you everyone.

I’ve had this bug but not with “nock” (I’ll be honest, I don’t even know what nock is!)

I want to continue using browser-style testing… what has changed in the patch* release that’s causing such issues?

*(realising that axios is still pre v1.0.0)