apify-client-js icon indicating copy to clipboard operation
apify-client-js copied to clipboard

CORS error is not handled properly

Open mtrunkat opened this issue 4 years ago • 0 comments

I have a simple jest test that uses Apify client:

const { getApifyClient } = require('./helper');

const ACTOR = {
    name: `my-name`,
    versions: [
        {
            versionNumber: '0.1',
            envVars: [],
            sourceType: 'SOURCE_CODE',
            baseDockerImage: 'apify/actor-node-basic',
            sourceCode: '...',
        },
    ],
};

describe('test', () => {
    it('case', async () => {
        console.log(await getApifyClient().actors().create(ACTOR));
    });
});

Which fails with the following error

    Expected response object with a "data" property, but received: undefined

      18 | describe('test', () => {
      19 |     it('case', async () => {
    > 20 |         console.log(await client.actors().create(ACTOR));
         |                     ^
      21 |     });
      22 | });
      23 | 

      at pluckData (node_modules/apify-client/src/utils.js:21:11)
      at ActorCollectionClient._create (node_modules/apify-client/src/base/resource_collection_client.js:39:32)
      at Object.<anonymous> (src/test.js:20:21)

After doing some experiments I found out that it works when the test is executed in a Node environment with

--testEnvironment=node

So I updated test to simply do an Axios request as Axios is used in the client

const axios = require('axios');

describe('test', () => {
    it('case', async () => {
        console.log(await axios('http://example.com'));
    });
});

and it returned a following error

   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:32:32)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:318:25)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
     ...

  console.error
    Error: Cross origin http://localhost forbidden
        at dispatchError (/Users/marek/Workspace/apify-status-page/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:62:19)
        at Object.validCORSHeaders (/Users/marek/Workspace/apify-status-page/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:74:5)
        at receiveResponse (/Users/marek/Workspace/apify-status-page/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js:796:19)
        ...

which is not probably handled properly in Apify Client. The problem happens here https://github.com/apify/apify-client-js/blob/master/src/http_client.js#L116 where the response has an empty body but doesn't contain an error so it gets returned:

    {
      data: undefined,
      status: 201,
      statusText: 'Created',
      headers: {
        'content-type': 'application/json; charset=utf-8',
        'cache-control': 'no-cache, no-store, must-revalidate',
        pragma: 'no-cache',
        expires: '0'
      },
      config: {
        url: 'https://api.apify.com/v2/acts',
        method: 'post',
        data: '{"name":"my-name-5","versions":[{"versionNumber":"0.1","envVars":[],"sourceType":"SOURCE_CODE","baseDockerImage":"apify/actor-node-basic","sourceCode":"..."}]}',
        headers: {
          'User-Agent': 'ApifyClient/1.0.1 (Darwin; Node/v12.14.1); isAtHome/false',
          'Content-Type': 'application/json;charset=utf-8'
        },
        params: { token: 'xxxx' },
        transformRequest: null,
        transformResponse: null,
        paramsSerializer: [Function: paramsSerializer],
        timeout: 360000,
        adapter: [Function: xhrAdapter],
        responseType: 'arraybuffer',
        xsrfCookieName: 'XSRF-TOKEN',
        xsrfHeaderName: 'X-XSRF-TOKEN',
        maxContentLength: -1,
        maxBodyLength: -1,
        httpAgent: Agent {
          _events: [Object: null prototype],
          _eventsCount: 1,
          _maxListeners: undefined,
          defaultPort: 80,
          protocol: 'http:',
          options: [Object],
          requests: {},
          sockets: {},
          freeSockets: {},
          keepAliveMsecs: 1000,
          keepAlive: true,
          maxSockets: Infinity,
          maxFreeSockets: 256,
          createSocketCount: 0,
          createSocketCountLastCheck: 0,
          createSocketErrorCount: 0,
          createSocketErrorCountLastCheck: 0,
          closeSocketCount: 0,
          closeSocketCountLastCheck: 0,
          errorSocketCount: 0,
          errorSocketCountLastCheck: 0,
          requestCount: 0,
          requestCountLastCheck: 0,
          timeoutSocketCount: 0,
          timeoutSocketCountLastCheck: 0,
          [Symbol(agentkeepalive#currentId)]: 0
        },
        httpsAgent: HttpsAgent {
          _events: [Object: null prototype],
          _eventsCount: 1,
          _maxListeners: undefined,
          defaultPort: 443,
          protocol: 'https:',
          options: [Object],
          requests: {},
          sockets: {},
          freeSockets: {},
          keepAliveMsecs: 1000,
          keepAlive: true,
          maxSockets: Infinity,
          maxFreeSockets: 256,
          createSocketCount: 0,
          createSocketCountLastCheck: 0,
          createSocketErrorCount: 0,
          createSocketErrorCountLastCheck: 0,
          closeSocketCount: 0,
          closeSocketCountLastCheck: 0,
          errorSocketCount: 0,
          errorSocketCountLastCheck: 0,
          requestCount: 0,
          requestCountLastCheck: 0,
          timeoutSocketCount: 0,
          timeoutSocketCountLastCheck: 0,
          maxCachedSessions: 100,
          _sessionCache: [Object],
          [Symbol(agentkeepalive#currentId)]: 0
        },
        validateStatus: null
      },
      request: XMLHttpRequest {}
    }

mtrunkat avatar Jan 05 '21 13:01 mtrunkat