diff --git a/integration/test/ParseCloudTest.js b/integration/test/ParseCloudTest.js index ca5a4ae7f..c4704d00c 100644 --- a/integration/test/ParseCloudTest.js +++ b/integration/test/ParseCloudTest.js @@ -96,6 +96,7 @@ describe('Parse Cloud', () => { it('run job', async () => { const params = { startedBy: 'Monty Python' }; const jobStatusId = await Parse.Cloud.startJob('CloudJob1', params); + expect(jobStatusId).toBeDefined(); await waitForJobStatus(jobStatusId, 'succeeded'); const jobStatus = await Parse.Cloud.getJobStatus(jobStatusId); diff --git a/integration/test/ParsePushTest.js b/integration/test/ParsePushTest.js index e34913cad..0fad863ef 100644 --- a/integration/test/ParsePushTest.js +++ b/integration/test/ParsePushTest.js @@ -9,6 +9,7 @@ describe('Parse Push', () => { where: { deviceType: { $eq: 'random' } }, }; const pushStatusId = await Parse.Push.send(payload, { useMasterKey: true }); + expect(pushStatusId).toBeDefined(); const pushStatus = await Parse.Push.getPushStatus(pushStatusId, { useMasterKey: true }); expect(pushStatus.id).toBe(pushStatusId); }); diff --git a/src/Cloud.js b/src/Cloud.js index 4bf748d3a..0d218843c 100644 --- a/src/Cloud.js +++ b/src/Cloud.js @@ -131,12 +131,14 @@ const DefaultController = { return RESTController.request('GET', 'cloud_code/jobs/data', null, options); }, - startJob(name, data, options: RequestOptions) { + async startJob(name, data, options: RequestOptions) { const RESTController = CoreManager.getRESTController(); const payload = encode(data, true); + options.returnStatus = true; - return RESTController.request('POST', 'jobs/' + name, payload, options); + const response = await RESTController.request('POST', 'jobs/' + name, payload, options); + return response._headers?.['X-Parse-Job-Status-Id']; }, }; diff --git a/src/ParseObject.js b/src/ParseObject.js index 94c30b9c1..f324f6c28 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -2455,6 +2455,8 @@ const DefaultController = { const objectId = responses[index].success.objectId; const status = responses[index]._status; delete responses[index]._status; + delete responses[index]._headers; + delete responses[index]._xhr; mapIdForPin[objectId] = obj._localId; obj._handleSaveResponse(responses[index].success, status); } else { @@ -2523,6 +2525,8 @@ const DefaultController = { response => { const status = response._status; delete response._status; + delete response._headers; + delete response._xhr; targetCopy._handleSaveResponse(response, status); }, error => { diff --git a/src/Push.js b/src/Push.js index e0d0d9567..a565396be 100644 --- a/src/Push.js +++ b/src/Push.js @@ -99,8 +99,10 @@ export function getPushStatus(pushStatusId: string, options?: FullOptions = {}): } const DefaultController = { - send(data: PushData, options?: FullOptions) { - return CoreManager.getRESTController().request('POST', 'push', data, options); + async send(data: PushData, options?: FullOptions) { + options.returnStatus = true; + const response = await CoreManager.getRESTController().request('POST', 'push', data, options); + return response._headers?.['X-Parse-Push-Status-Id']; }, }; diff --git a/src/RESTController.js b/src/RESTController.js index 5e0c42d0f..75b30a759 100644 --- a/src/RESTController.js +++ b/src/RESTController.js @@ -110,20 +110,18 @@ const RESTController = { let response; try { response = JSON.parse(xhr.responseText); - - if (typeof xhr.getResponseHeader === 'function') { - if ((xhr.getAllResponseHeaders() || '').includes('x-parse-job-status-id: ')) { - response = xhr.getResponseHeader('x-parse-job-status-id'); - } - if ((xhr.getAllResponseHeaders() || '').includes('x-parse-push-status-id: ')) { - response = xhr.getResponseHeader('x-parse-push-status-id'); - } + headers = {}; + if (typeof xhr.getResponseHeader === 'function' && xhr.getResponseHeader('access-control-expose-headers')) { + const responseHeaders = xhr.getResponseHeader('access-control-expose-headers').split(', '); + responseHeaders.forEach(header => { + headers[header] = xhr.getResponseHeader(header.toLowerCase()); + }); } } catch (e) { promise.reject(e.toString()); } if (response) { - promise.resolve({ response, status: xhr.status, xhr }); + promise.resolve({ response, headers, status: xhr.status, xhr }); } } else if (xhr.status >= 500 || xhr.status === 0) { // retry on 5XX or node-xmlhttprequest error @@ -287,9 +285,9 @@ const RESTController = { const payloadString = JSON.stringify(payload); return RESTController.ajax(method, url, payloadString, {}, options).then( - ({ response, status }) => { + ({ response, status, headers, xhr }) => { if (options.returnStatus) { - return { ...response, _status: status }; + return { ...response, _status: status, _headers: headers, _xhr: xhr }; } else { return response; } diff --git a/src/__tests__/Cloud-test.js b/src/__tests__/Cloud-test.js index 48243b635..143f1da9a 100644 --- a/src/__tests__/Cloud-test.js +++ b/src/__tests__/Cloud-test.js @@ -229,7 +229,7 @@ describe('CloudController', () => { value: 12, when: { __type: 'Date', iso: '2015-01-01T00:00:00.000Z' }, }, - { useMasterKey: true }, + { returnStatus: true, useMasterKey: true }, ]); }); @@ -242,7 +242,7 @@ describe('CloudController', () => { { value: 12, }, - { useMasterKey: true }, + { returnStatus: true, useMasterKey: true }, ]); }); diff --git a/src/__tests__/Push-test.js b/src/__tests__/Push-test.js index 6ec1833ca..70affe624 100644 --- a/src/__tests__/Push-test.js +++ b/src/__tests__/Push-test.js @@ -87,13 +87,7 @@ describe('Push', () => { describe('PushController', () => { it('forwards data along', () => { CoreManager.setPushController(defaultController); - const request = jest.fn().mockReturnValue({ - _thenRunCallbacks() { - return { - _thenRunCallbacks() {}, - }; - }, - }); + const request = jest.fn().mockReturnValue({ _headers: {} }); CoreManager.setRESTController({ request: request, ajax: function () {}, @@ -111,7 +105,7 @@ describe('PushController', () => { 'POST', 'push', { push_time: '2015-02-01T00:00:00.000Z' }, - { useMasterKey: true }, + { returnStatus: true, useMasterKey: true }, ]); }); }); diff --git a/src/__tests__/RESTController-test.js b/src/__tests__/RESTController-test.js index 7beb64f3d..02d72e94d 100644 --- a/src/__tests__/RESTController-test.js +++ b/src/__tests__/RESTController-test.js @@ -22,6 +22,12 @@ CoreManager.set('APPLICATION_ID', 'A'); CoreManager.set('JAVASCRIPT_KEY', 'B'); CoreManager.set('VERSION', 'V'); +const headers = { + 'x-parse-job-status-id': '1234', + 'x-parse-push-status-id': '5678', + 'access-control-expose-headers': 'X-Parse-Job-Status-Id, X-Parse-Push-Status-Id', +}; + describe('RESTController', () => { it('throws if there is no XHR implementation', () => { RESTController._setXHR(null); @@ -212,8 +218,8 @@ describe('RESTController', () => { XHR.prototype = { open: function () {}, setRequestHeader: function () {}, - getResponseHeader: function () { - return 1234; + getResponseHeader: function (header) { + return headers[header]; }, send: function () { this.status = 200; @@ -221,13 +227,10 @@ describe('RESTController', () => { this.readyState = 4; this.onreadystatechange(); }, - getAllResponseHeaders: function () { - return 'x-parse-job-status-id: 1234'; - }, }; RESTController._setXHR(XHR); - const response = await RESTController.request('GET', 'classes/MyObject', {}, {}); - expect(response).toBe(1234); + const response = await RESTController.request('GET', 'classes/MyObject', {}, { returnStatus: true }); + expect(response._headers['X-Parse-Job-Status-Id']).toBe('1234'); }); it('handles x-parse-push-status-id header', async () => { @@ -235,8 +238,8 @@ describe('RESTController', () => { XHR.prototype = { open: function () {}, setRequestHeader: function () {}, - getResponseHeader: function () { - return 1234; + getResponseHeader: function (header) { + return headers[header]; }, send: function () { this.status = 200; @@ -244,13 +247,10 @@ describe('RESTController', () => { this.readyState = 4; this.onreadystatechange(); }, - getAllResponseHeaders: function () { - return 'x-parse-push-status-id: 1234'; - }, }; RESTController._setXHR(XHR); - const response = await RESTController.request('POST', 'push', {}, {}); - expect(response).toBe(1234); + const response = await RESTController.request('POST', 'push', {}, { returnStatus: true }); + expect(response._headers['X-Parse-Push-Status-Id']).toBe('5678'); }); it('handles invalid header', async () => {