diff --git a/src/Cloud.js b/src/Cloud.js index 612cf02c8..0a5015e0d 100644 --- a/src/Cloud.js +++ b/src/Cloud.js @@ -57,6 +57,9 @@ export function run( if (options.sessionToken) { requestOptions.sessionToken = options.sessionToken; } + if (options.context && typeof options.context === 'object') { + requestOptions.context = options.context; + } return CoreManager.getCloudController().run(name, data, requestOptions); } diff --git a/src/ParseObject.js b/src/ParseObject.js index 5f78cb191..3ae07cc78 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -1084,6 +1084,7 @@ class ParseObject { * behalf of a specific user. *
  • include: The name(s) of the key(s) to include. Can be a string, an array of strings, * or an array of array of strings. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. * * @return {Promise} A promise that is fulfilled when the fetch * completes. @@ -1097,6 +1098,9 @@ class ParseObject { if (options.hasOwnProperty('sessionToken')) { fetchOptions.sessionToken = options.sessionToken; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + fetchOptions.context = options.context; + } if (options.hasOwnProperty('include')) { fetchOptions.include = []; if (Array.isArray(options.include)) { @@ -1273,6 +1277,7 @@ class ParseObject { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • context: A dictionary that is accessible in Cloud Code `beforeDelete` and `afterDelete` triggers. * * @return {Promise} A promise that is fulfilled when the destroy * completes. @@ -1286,6 +1291,9 @@ class ParseObject { if (options.hasOwnProperty('sessionToken')) { destroyOptions.sessionToken = options.sessionToken; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + destroyOptions.context = options.context; + } if (!this.id) { return Promise.resolve(); } @@ -1631,6 +1639,7 @@ class ParseObject { *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. *
  • batchSize: Number of objects to process per request + *
  • context: A dictionary that is accessible in Cloud Code `beforeDelete` and `afterDelete` triggers. * * @return {Promise} A promise that is fulfilled when the destroyAll * completes. @@ -1646,6 +1655,9 @@ class ParseObject { if (options.hasOwnProperty('batchSize') && typeof options.batchSize === 'number') { destroyOptions.batchSize = options.batchSize; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + destroyOptions.context = options.context; + } return CoreManager.getObjectController().destroy( list, destroyOptions @@ -1674,6 +1686,7 @@ class ParseObject { *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. *
  • batchSize: Number of objects to process per request + *
  • context: A dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers. * */ static saveAll(list: Array, options: RequestOptions = {}) { @@ -1687,6 +1700,9 @@ class ParseObject { if (options.hasOwnProperty('batchSize') && typeof options.batchSize === 'number') { saveOptions.batchSize = options.batchSize; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + saveOptions.context = options.context; + } return CoreManager.getObjectController().save( list, saveOptions diff --git a/src/ParseQuery.js b/src/ParseQuery.js index 10666034f..1e2be576a 100644 --- a/src/ParseQuery.js +++ b/src/ParseQuery.js @@ -564,6 +564,7 @@ class ParseQuery { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. * * * @return {Promise} A promise that is resolved with the result when @@ -579,6 +580,9 @@ class ParseQuery { if (options && options.hasOwnProperty('sessionToken')) { firstOptions.sessionToken = options.sessionToken; } + if (options && options.hasOwnProperty('context') && typeof options.context === 'object') { + firstOptions.context = options.context; + } return this.first(firstOptions).then((response) => { if (response) { @@ -604,6 +608,7 @@ class ParseQuery { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. * * * @return {Promise} A promise that is resolved with the results when @@ -619,6 +624,9 @@ class ParseQuery { if (options.hasOwnProperty('sessionToken')) { findOptions.sessionToken = options.sessionToken; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + findOptions.context = options.context; + } this._setRequestTask(findOptions); const controller = CoreManager.getQueryController(); @@ -799,6 +807,7 @@ class ParseQuery { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. * * * @return {Promise} A promise that is resolved with the object when @@ -814,6 +823,9 @@ class ParseQuery { if (options.hasOwnProperty('sessionToken')) { findOptions.sessionToken = options.sessionToken; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + findOptions.context = options.context; + } this._setRequestTask(findOptions); const controller = CoreManager.getQueryController(); @@ -871,6 +883,7 @@ class ParseQuery { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. * * @return {Promise} A promise that will be fulfilled once the * iteration has completed. @@ -921,6 +934,9 @@ class ParseQuery { if (options.hasOwnProperty('sessionToken')) { findOptions.sessionToken = options.sessionToken; } + if (options.hasOwnProperty('context') && typeof options.context === 'object') { + findOptions.context = options.context; + } let finished = false; let previousResults = []; diff --git a/src/__tests__/Cloud-test.js b/src/__tests__/Cloud-test.js index 2a5b9bfda..b6f7b98ab 100644 --- a/src/__tests__/Cloud-test.js +++ b/src/__tests__/Cloud-test.js @@ -205,4 +205,21 @@ describe('CloudController', () => { expect(CoreManager.getRESTController().request.mock.calls[0]) .toEqual(['GET', 'cloud_code/jobs/data', null, { useMasterKey: true }]); }); + + it('accepts context on cloud function call', async () => { + const request = jest.fn(); + request.mockReturnValue(Promise.resolve(undefined)); + + const ajax = jest.fn(); + CoreManager.setRESTController({ request: request, ajax: ajax }); + + // Spy on REST controller + const controller = CoreManager.getRESTController(); + jest.spyOn(controller, 'request'); + // Save object + const context = {a: "a"}; + await Cloud.run('myfunction', {}, { context: context }); + // Validate + expect(controller.request.mock.calls[0][3].context).toEqual(context); + }); }); diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index e055a9d0e..d487e9148 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -1566,6 +1566,49 @@ describe('ParseObject', () => { await result; }); + it('accepts context on saveAll', async () => { + // Mock XHR + CoreManager.getRESTController()._setXHR( + mockXHR([{ + status: 200, + response: [{}] + }]) + ); + // Spy on REST controller + const controller = CoreManager.getRESTController(); + jest.spyOn(controller, 'ajax'); + // Save object + const context = {a: "a"}; + const obj = new ParseObject('Item'); + obj.id = 'pid'; + obj.set('test', 'value'); + await ParseObject.saveAll([obj], {context}) + // Validate + const jsonBody = JSON.parse(controller.ajax.mock.calls[0][2]); + expect(jsonBody._context).toEqual(context); + }); + + it('accepts context on destroyAll', async () => { + // Mock XHR + CoreManager.getRESTController()._setXHR( + mockXHR([{ + status: 200, + response: [{}] + }]) + ); + // Spy on REST controller + const controller = CoreManager.getRESTController(); + jest.spyOn(controller, 'ajax'); + // Save object + const context = {a: "a"}; + const obj = new ParseObject('Item'); + obj.id = 'pid'; + await ParseObject.destroyAll([obj], { context: context }) + // Validate + const jsonBody = JSON.parse(controller.ajax.mock.calls[0][2]); + expect(jsonBody._context).toEqual(context); + }); + it('can save a chain of unsaved objects', async () => { const xhrs = []; RESTController._setXHR(function() { @@ -1734,6 +1777,27 @@ describe('ParseObject', () => { await result; }); + it('accepts context on destroy', async () => { + // Mock XHR + CoreManager.getRESTController()._setXHR( + mockXHR([{ + status: 200, + response: {} + }]) + ); + // Spy on REST controller + const controller = CoreManager.getRESTController(); + jest.spyOn(controller, 'ajax'); + // Save object + const context = {a: "a"}; + const obj = new ParseObject('Item'); + obj.id = 'pid'; + await obj.destroy({context}); + // Validate + const jsonBody = JSON.parse(controller.ajax.mock.calls[0][2]); + expect(jsonBody._context).toEqual(context); + }); + it('can save an array of objects', async (done) => { const xhr = { setRequestHeader: jest.fn(), @@ -1980,6 +2044,27 @@ describe('ObjectController', () => { jest.runAllTicks(); }); + it('accepts context on fetch', async () => { + // Mock XHR + CoreManager.getRESTController()._setXHR( + mockXHR([{ + status: 200, + response: {} + }]) + ); + // Spy on REST controller + const controller = CoreManager.getRESTController(); + jest.spyOn(controller, 'ajax'); + // Save object + const context = {a: "a"}; + const obj = new ParseObject('Item'); + obj.id = 'pid'; + await obj.fetch({context}); + // Validate + const jsonBody = JSON.parse(controller.ajax.mock.calls[0][2]); + expect(jsonBody._context).toEqual(context); + }); + it('can fetch an array of objects', (done) => { const objectController = CoreManager.getObjectController(); const objects = []; diff --git a/src/__tests__/ParseQuery-test.js b/src/__tests__/ParseQuery-test.js index 66c907785..abe148f4c 100644 --- a/src/__tests__/ParseQuery-test.js +++ b/src/__tests__/ParseQuery-test.js @@ -1295,6 +1295,7 @@ describe('ParseQuery', () => { }); it('can pass options to a get() query', (done) => { + const context = {a: "a"}; CoreManager.setQueryController({ aggregate() {}, find(className, params, options) { @@ -1307,6 +1308,7 @@ describe('ParseQuery', () => { }); expect(options.useMasterKey).toEqual(true); expect(options.sessionToken).toEqual('1234'); + expect(options.context).toEqual(context); return Promise.resolve({ results: [ { objectId: 'I27', size: 'large', name: 'Product 27' } @@ -1318,7 +1320,8 @@ describe('ParseQuery', () => { const q = new ParseQuery('Item'); q.get('I27', { useMasterKey: true, - sessionToken: '1234' + sessionToken: '1234', + context: context }).then(() => { done(); }); @@ -1437,6 +1440,7 @@ describe('ParseQuery', () => { }); it('can pass options to find()', (done) => { + const context = {a: "a"}; CoreManager.setQueryController({ aggregate() {}, find(className, params, options) { @@ -1450,6 +1454,7 @@ describe('ParseQuery', () => { }); expect(options.useMasterKey).toEqual(true); expect(options.sessionToken).toEqual('1234'); + expect(options.context).toEqual(context); return Promise.resolve({ results: [] }); @@ -1460,7 +1465,8 @@ describe('ParseQuery', () => { q.containedIn('size', ['small', 'medium']) .find({ useMasterKey: true, - sessionToken: '1234' + sessionToken: '1234', + context: context }) .then((objs) => { expect(objs).toEqual([]); @@ -1692,6 +1698,7 @@ describe('ParseQuery', () => { }); it('can pass options to each()', (done) => { + const context = {a: "a"}; CoreManager.setQueryController({ aggregate() {}, find(className, params, options) { @@ -1709,6 +1716,7 @@ describe('ParseQuery', () => { }); expect(options.useMasterKey).toEqual(true); expect(options.sessionToken).toEqual('1234'); + expect(options.context).toEqual(context); return Promise.resolve({ results: [ { objectId: 'I55', size: 'medium', name: 'Product 55' }, @@ -1729,7 +1737,8 @@ describe('ParseQuery', () => { calls++; }, { useMasterKey: true, - sessionToken: '1234' + sessionToken: '1234', + context: context }).then(() => { expect(calls).toBe(3); done(); @@ -1738,6 +1747,7 @@ describe('ParseQuery', () => { it('can pass options to each() with hint', (done) => { + const context = {a: "a"}; CoreManager.setQueryController({ aggregate() {}, find(className, params, options) { @@ -1756,6 +1766,7 @@ describe('ParseQuery', () => { }); expect(options.useMasterKey).toEqual(true); expect(options.sessionToken).toEqual('1234'); + expect(options.context).toEqual(context); return Promise.resolve({ results: [ { objectId: 'I55', size: 'medium', name: 'Product 55' }, @@ -1777,7 +1788,8 @@ describe('ParseQuery', () => { calls++; }, { useMasterKey: true, - sessionToken: '1234' + sessionToken: '1234', + context: context }).then(() => { expect(calls).toBe(3); done();