diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js new file mode 100644 index 00000000..2218a257 --- /dev/null +++ b/spec/CloudCode.spec.js @@ -0,0 +1,470 @@ +"use strict" +const Parse = require("parse/node"); + +describe('Cloud Code', () => { + it('can load absolute cloud code file', done => { + setServerConfiguration({ + serverURL: 'http://localhost:8378/1', + appId: 'test', + masterKey: 'test', + cloud: __dirname + '/cloud/cloudCodeRelativeFile.js' + }); + Parse.Cloud.run('cloudCodeInFile', {}, result => { + expect(result).toEqual('It is possible to define cloud code in a file.'); + done(); + }); + }); + + it('can load relative cloud code file', done => { + setServerConfiguration({ + serverURL: 'http://localhost:8378/1', + appId: 'test', + masterKey: 'test', + cloud: './spec/cloud/cloudCodeAbsoluteFile.js' + }); + Parse.Cloud.run('cloudCodeInFile', {}, result => { + expect(result).toEqual('It is possible to define cloud code in a file.'); + done(); + }); + }); + + it('can create functions', done => { + Parse.Cloud.define('hello', (req, res) => { + res.success('Hello world!'); + }); + + Parse.Cloud.run('hello', {}, result => { + expect(result).toEqual('Hello world!'); + done(); + }); + }); + + it('is cleared cleared after the previous test', done => { + Parse.Cloud.run('hello', {}) + .catch(error => { + expect(error.code).toEqual(141); + done(); + }); + }); + + it('basic beforeSave rejection', function(done) { + Parse.Cloud.beforeSave('BeforeSaveFail', function(req, res) { + res.error('You shall not pass!'); + }); + + var obj = new Parse.Object('BeforeSaveFail'); + obj.set('foo', 'bar'); + obj.save().then(() => { + fail('Should not have been able to save BeforeSaveFailure class.'); + done(); + }, () => { + done(); + }) + }); + + it('basic beforeSave rejection via promise', function(done) { + Parse.Cloud.beforeSave('BeforeSaveFailWithPromise', function (req, res) { + var query = new Parse.Query('Yolo'); + query.find().then(() => { + res.error('Nope'); + }, () => { + res.success(); + }); + }); + + var obj = new Parse.Object('BeforeSaveFailWithPromise'); + obj.set('foo', 'bar'); + obj.save().then(function() { + fail('Should not have been able to save BeforeSaveFailure class.'); + done(); + }, function(error) { + expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); + expect(error.message).toEqual('Nope'); + done(); + }) + }); + + it('test beforeSave changed object success', function(done) { + Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) { + req.object.set('foo', 'baz'); + res.success(); + }); + + var obj = new Parse.Object('BeforeSaveChanged'); + obj.set('foo', 'bar'); + obj.save().then(function() { + var query = new Parse.Query('BeforeSaveChanged'); + query.get(obj.id).then(function(objAgain) { + expect(objAgain.get('foo')).toEqual('baz'); + done(); + }, function(error) { + fail(error); + done(); + }); + }, function(error) { + fail(error); + done(); + }); + }); + + it('test beforeSave returns value on create and update', (done) => { + Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) { + req.object.set('foo', 'baz'); + res.success(); + }); + + var obj = new Parse.Object('BeforeSaveChanged'); + obj.set('foo', 'bing'); + obj.save().then(() => { + expect(obj.get('foo')).toEqual('baz'); + obj.set('foo', 'bar'); + return obj.save().then(() => { + expect(obj.get('foo')).toEqual('baz'); + done(); + }) + }) + }); + + it('test afterSave ran and created an object', function(done) { + Parse.Cloud.afterSave('AfterSaveTest', function(req) { + var obj = new Parse.Object('AfterSaveProof'); + obj.set('proof', req.object.id); + obj.save(); + }); + + var obj = new Parse.Object('AfterSaveTest'); + obj.save(); + + setTimeout(function() { + var query = new Parse.Query('AfterSaveProof'); + query.equalTo('proof', obj.id); + query.find().then(function(results) { + expect(results.length).toEqual(1); + done(); + }, function(error) { + fail(error); + done(); + }); + }, 500); + }); + + it('test beforeSave happens on update', function(done) { + Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) { + req.object.set('foo', 'baz'); + res.success(); + }); + + var obj = new Parse.Object('BeforeSaveChanged'); + obj.set('foo', 'bar'); + obj.save().then(function() { + obj.set('foo', 'bar'); + return obj.save(); + }).then(function() { + var query = new Parse.Query('BeforeSaveChanged'); + return query.get(obj.id).then(function(objAgain) { + expect(objAgain.get('foo')).toEqual('baz'); + done(); + }); + }, function(error) { + fail(error); + done(); + }); + }); + + it('test beforeDelete failure', function(done) { + Parse.Cloud.beforeDelete('BeforeDeleteFail', function(req, res) { + res.error('Nope'); + }); + + var obj = new Parse.Object('BeforeDeleteFail'); + var id; + obj.set('foo', 'bar'); + obj.save().then(() => { + id = obj.id; + return obj.destroy(); + }).then(() => { + fail('obj.destroy() should have failed, but it succeeded'); + done(); + }, (error) => { + expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); + expect(error.message).toEqual('Nope'); + + var objAgain = new Parse.Object('BeforeDeleteFail', {objectId: id}); + return objAgain.fetch(); + }).then((objAgain) => { + if (objAgain) { + expect(objAgain.get('foo')).toEqual('bar'); + } else { + fail("unable to fetch the object ", id); + } + done(); + }, (error) => { + // We should have been able to fetch the object again + fail(error); + }); + }); + + it('basic beforeDelete rejection via promise', function(done) { + Parse.Cloud.beforeSave('BeforeDeleteFailWithPromise', function (req, res) { + var query = new Parse.Query('Yolo'); + query.find().then(() => { + res.error('Nope'); + }, () => { + res.success(); + }); + }); + + var obj = new Parse.Object('BeforeDeleteFailWithPromise'); + obj.set('foo', 'bar'); + obj.save().then(function() { + fail('Should not have been able to save BeforeSaveFailure class.'); + done(); + }, function(error) { + expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); + expect(error.message).toEqual('Nope'); + + done(); + }) + }); + + it('test afterDelete ran and created an object', function(done) { + Parse.Cloud.afterDelete('AfterDeleteTest', function(req) { + var obj = new Parse.Object('AfterDeleteProof'); + obj.set('proof', req.object.id); + obj.save(); + }); + + var obj = new Parse.Object('AfterDeleteTest'); + obj.save().then(function() { + obj.destroy(); + }); + + setTimeout(function() { + var query = new Parse.Query('AfterDeleteProof'); + query.equalTo('proof', obj.id); + query.find().then(function(results) { + expect(results.length).toEqual(1); + done(); + }, function(error) { + fail(error); + done(); + }); + }, 500); + }); + + it('test cloud function return types', function(done) { + Parse.Cloud.define('foo', function(req, res) { + res.success({ + object: { + __type: 'Object', + className: 'Foo', + objectId: '123', + x: 2, + relation: { + __type: 'Object', + className: 'Bar', + objectId: '234', + x: 3 + } + }, + array: [{ + __type: 'Object', + className: 'Bar', + objectId: '345', + x: 2 + }], + a: 2 + }); + }); + + Parse.Cloud.run('foo').then((result) => { + expect(result.object instanceof Parse.Object).toBeTruthy(); + if (!result.object) { + fail("Unable to run foo"); + done(); + return; + } + expect(result.object.className).toEqual('Foo'); + expect(result.object.get('x')).toEqual(2); + var bar = result.object.get('relation'); + expect(bar instanceof Parse.Object).toBeTruthy(); + expect(bar.className).toEqual('Bar'); + expect(bar.get('x')).toEqual(3); + expect(Array.isArray(result.array)).toEqual(true); + expect(result.array[0] instanceof Parse.Object).toBeTruthy(); + expect(result.array[0].get('x')).toEqual(2); + done(); + }); + }); + + it('test cloud function should echo keys', function(done) { + Parse.Cloud.define('echoKeys', function(req, res){ + return res.success({ + applicationId: Parse.applicationId, + masterKey: Parse.masterKey, + javascriptKey: Parse.javascriptKey + }) + }); + + Parse.Cloud.run('echoKeys').then((result) => { + expect(result.applicationId).toEqual(Parse.applicationId); + expect(result.masterKey).toEqual(Parse.masterKey); + expect(result.javascriptKey).toEqual(Parse.javascriptKey); + done(); + }); + }); + + it('should properly create an object in before save', done => { + Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) { + req.object.set('foo', 'baz'); + res.success(); + }); + + Parse.Cloud.define('createBeforeSaveChangedObject', function(req, res){ + var obj = new Parse.Object('BeforeSaveChanged'); + obj.save().then(() => { + res.success(obj); + }) + }) + + Parse.Cloud.run('createBeforeSaveChangedObject').then((res) => { + expect(res.get('foo')).toEqual('baz'); + done(); + }); + }); + + it('dirtyKeys are set on update', done => { + let triggerTime = 0; + // Register a mock beforeSave hook + Parse.Cloud.beforeSave('GameScore', (req, res) => { + var object = req.object; + expect(object instanceof Parse.Object).toBeTruthy(); + expect(object.get('fooAgain')).toEqual('barAgain'); + if (triggerTime == 0) { + // Create + expect(object.get('foo')).toEqual('bar'); + } else if (triggerTime == 1) { + // Update + expect(object.dirtyKeys()).toEqual(['foo']); + expect(object.dirty('foo')).toBeTruthy(); + expect(object.get('foo')).toEqual('baz'); + } else { + res.error(); + } + triggerTime++; + res.success(); + }); + + let obj = new Parse.Object('GameScore'); + obj.set('foo', 'bar'); + obj.set('fooAgain', 'barAgain'); + obj.save().then(() => { + // We only update foo + obj.set('foo', 'baz'); + return obj.save(); + }).then(() => { + // Make sure the checking has been triggered + expect(triggerTime).toBe(2); + done(); + }, function(error) { + fail(error); + done(); + }); + }); + + it('test beforeSave unchanged success', function(done) { + Parse.Cloud.beforeSave('BeforeSaveUnchanged', function(req, res) { + res.success(); + }); + + var obj = new Parse.Object('BeforeSaveUnchanged'); + obj.set('foo', 'bar'); + obj.save().then(function() { + done(); + }, function(error) { + fail(error); + done(); + }); + }); + + it('test beforeDelete success', function(done) { + Parse.Cloud.beforeDelete('BeforeDeleteTest', function(req, res) { + res.success(); + }); + + var obj = new Parse.Object('BeforeDeleteTest'); + obj.set('foo', 'bar'); + obj.save().then(function() { + return obj.destroy(); + }).then(function() { + var objAgain = new Parse.Object('BeforeDeleteTest', obj.id); + return objAgain.fetch().then(fail, done); + }, function(error) { + fail(error); + done(); + }); + }); + + it('test save triggers get user', function(done) { + Parse.Cloud.beforeSave('SaveTriggerUser', function(req, res) { + if (req.user && req.user.id) { + res.success(); + } else { + res.error('No user present on request object for beforeSave.'); + } + }); + + Parse.Cloud.afterSave('SaveTriggerUser', function(req) { + if (!req.user || !req.user.id) { + console.log('No user present on request object for afterSave.'); + } + }); + + var user = new Parse.User(); + user.set("password", "asdf"); + user.set("email", "asdf@example.com"); + user.set("username", "zxcv"); + user.signUp(null, { + success: function() { + var obj = new Parse.Object('SaveTriggerUser'); + obj.save().then(function() { + done(); + }, function(error) { + fail(error); + done(); + }); + } + }); + }); + + it('beforeSave change propagates through the save response', (done) => { + Parse.Cloud.beforeSave('ChangingObject', function(request, response) { + request.object.set('foo', 'baz'); + response.success(); + }); + let obj = new Parse.Object('ChangingObject'); + obj.save({ foo: 'bar' }).then((objAgain) => { + expect(objAgain.get('foo')).toEqual('baz'); + done(); + }, (e) => { + fail('Should not have failed to save.'); + done(); + }); + }); + + it('test cloud function parameter validation success', (done) => { + // Register a function with validation + Parse.Cloud.define('functionWithParameterValidation', (req, res) => { + res.success('works'); + }, (request) => { + return request.params.success === 100; + }); + + Parse.Cloud.run('functionWithParameterValidation', {"success":100}).then((s) => { + done(); + }, (e) => { + fail('Validation should not have failed.'); + done(); + }); + }); +}); diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index 23fc967e..a556762a 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -14,7 +14,6 @@ describe("Cloud Code Logger", () => { }); Parse.Cloud.run('loggerTest').then(() => { - Parse.Cloud._removeHook('Functions', 'logTest'); return logController.getLogs({from: Date.now() - 500, size: 1000}); }).then((res) => { expect(res.length).not.toBe(0); @@ -42,7 +41,6 @@ describe("Cloud Code Logger", () => { let obj = new Parse.Object('MyObject'); obj.save().then(() => { - Parse.Cloud._removeHook('Triggers', 'beforeSave', 'MyObject'); return logController.getLogs({from: Date.now() - 500, size: 1000}) }).then((res) => { expect(res.length).not.toBe(0); diff --git a/spec/ParseACL.spec.js b/spec/ParseACL.spec.js index 79364b0c..ac25793b 100644 --- a/spec/ParseACL.spec.js +++ b/spec/ParseACL.spec.js @@ -1182,7 +1182,6 @@ describe('Parse.ACL', () => { done(); }, error => { expect(error.code).toEqual(Parse.Error.OBJECT_NOT_FOUND); - Parse.Cloud._removeHook('Triggers', 'afterSave', Parse.User.className); done(); }); }); diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 5f44dca7..21603a09 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -164,67 +164,6 @@ describe('miscellaneous', function() { }); }); - it('test cloud function', function(done) { - Parse.Cloud.run('hello', {}, function(result) { - expect(result).toEqual('Hello world!'); - done(); - }); - }); - - it('basic beforeSave rejection', function(done) { - var obj = new Parse.Object('BeforeSaveFail'); - obj.set('foo', 'bar'); - obj.save().then(() => { - fail('Should not have been able to save BeforeSaveFailure class.'); - done(); - }, () => { - done(); - }) - }); - - it('basic beforeSave rejection via promise', function(done) { - var obj = new Parse.Object('BeforeSaveFailWithPromise'); - obj.set('foo', 'bar'); - obj.save().then(function() { - fail('Should not have been able to save BeforeSaveFailure class.'); - done(); - }, function(error) { - expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); - expect(error.message).toEqual('Nope'); - - done(); - }) - }); - - it('test beforeSave unchanged success', function(done) { - var obj = new Parse.Object('BeforeSaveUnchanged'); - obj.set('foo', 'bar'); - obj.save().then(function() { - done(); - }, function(error) { - fail(error); - done(); - }); - }); - - it('test beforeSave changed object success', function(done) { - var obj = new Parse.Object('BeforeSaveChanged'); - obj.set('foo', 'bar'); - obj.save().then(function() { - var query = new Parse.Query('BeforeSaveChanged'); - query.get(obj.id).then(function(objAgain) { - expect(objAgain.get('foo')).toEqual('baz'); - done(); - }, function(error) { - fail(error); - done(); - }); - }, function(error) { - fail(error); - done(); - }); - }); - it('test beforeSave set object acl success', function(done) { var acl = new Parse.ACL({ '*': { read: true, write: false } @@ -237,7 +176,6 @@ describe('miscellaneous', function() { var obj = new Parse.Object('BeforeSaveAddACL'); obj.set('lol', true); obj.save().then(function() { - Parse.Cloud._removeHook('Triggers', 'beforeSave', 'BeforeSaveAddACL'); var query = new Parse.Query('BeforeSaveAddACL'); query.get(obj.id).then(function(objAgain) { expect(objAgain.get('lol')).toBeTruthy(); @@ -253,185 +191,6 @@ describe('miscellaneous', function() { }); }); - it('test beforeSave returns value on create and update', (done) => { - var obj = new Parse.Object('BeforeSaveChanged'); - obj.set('foo', 'bing'); - obj.save().then(() => { - expect(obj.get('foo')).toEqual('baz'); - obj.set('foo', 'bar'); - return obj.save().then(() => { - expect(obj.get('foo')).toEqual('baz'); - done(); - }) - }) - }); - - it('test afterSave ran and created an object', function(done) { - var obj = new Parse.Object('AfterSaveTest'); - obj.save(); - - setTimeout(function() { - var query = new Parse.Query('AfterSaveProof'); - query.equalTo('proof', obj.id); - query.find().then(function(results) { - expect(results.length).toEqual(1); - done(); - }, function(error) { - fail(error); - done(); - }); - }, 500); - }); - - it('test beforeSave happens on update', function(done) { - var obj = new Parse.Object('BeforeSaveChanged'); - obj.set('foo', 'bar'); - obj.save().then(function() { - obj.set('foo', 'bar'); - return obj.save(); - }).then(function() { - var query = new Parse.Query('BeforeSaveChanged'); - return query.get(obj.id).then(function(objAgain) { - expect(objAgain.get('foo')).toEqual('baz'); - done(); - }); - }, function(error) { - fail(error); - done(); - }); - }); - - it('test beforeDelete failure', function(done) { - var obj = new Parse.Object('BeforeDeleteFail'); - var id; - obj.set('foo', 'bar'); - obj.save().then(() => { - id = obj.id; - return obj.destroy(); - }).then(() => { - fail('obj.destroy() should have failed, but it succeeded'); - done(); - }, (error) => { - expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); - expect(error.message).toEqual('Nope'); - - var objAgain = new Parse.Object('BeforeDeleteFail', {objectId: id}); - return objAgain.fetch(); - }).then((objAgain) => { - if (objAgain) { - expect(objAgain.get('foo')).toEqual('bar'); - } else { - fail("unable to fetch the object ", id); - } - done(); - }, (error) => { - // We should have been able to fetch the object again - fail(error); - }); - }); - - it('basic beforeDelete rejection via promise', function(done) { - var obj = new Parse.Object('BeforeDeleteFailWithPromise'); - obj.set('foo', 'bar'); - obj.save().then(function() { - fail('Should not have been able to save BeforeSaveFailure class.'); - done(); - }, function(error) { - expect(error.code).toEqual(Parse.Error.SCRIPT_FAILED); - expect(error.message).toEqual('Nope'); - - done(); - }) - }); - - it('test beforeDelete success', function(done) { - var obj = new Parse.Object('BeforeDeleteTest'); - obj.set('foo', 'bar'); - obj.save().then(function() { - return obj.destroy(); - }).then(function() { - var objAgain = new Parse.Object('BeforeDeleteTest', obj.id); - return objAgain.fetch().then(fail, done); - }, function(error) { - fail(error); - done(); - }); - }); - - it('test afterDelete ran and created an object', function(done) { - var obj = new Parse.Object('AfterDeleteTest'); - obj.save().then(function() { - obj.destroy(); - }); - - setTimeout(function() { - var query = new Parse.Query('AfterDeleteProof'); - query.equalTo('proof', obj.id); - query.find().then(function(results) { - expect(results.length).toEqual(1); - done(); - }, function(error) { - fail(error); - done(); - }); - }, 500); - }); - - it('test save triggers get user', function(done) { - var user = new Parse.User(); - user.set("password", "asdf"); - user.set("email", "asdf@example.com"); - user.set("username", "zxcv"); - user.signUp(null, { - success: function() { - var obj = new Parse.Object('SaveTriggerUser'); - obj.save().then(function() { - done(); - }, function(error) { - fail(error); - done(); - }); - } - }); - }); - - it('test cloud function return types', function(done) { - Parse.Cloud.run('foo').then((result) => { - expect(result.object instanceof Parse.Object).toBeTruthy(); - if (!result.object) { - fail("Unable to run foo"); - done(); - return; - } - expect(result.object.className).toEqual('Foo'); - expect(result.object.get('x')).toEqual(2); - var bar = result.object.get('relation'); - expect(bar instanceof Parse.Object).toBeTruthy(); - expect(bar.className).toEqual('Bar'); - expect(bar.get('x')).toEqual(3); - expect(Array.isArray(result.array)).toEqual(true); - expect(result.array[0] instanceof Parse.Object).toBeTruthy(); - expect(result.array[0].get('x')).toEqual(2); - done(); - }); - }); - - it('test cloud function should echo keys', function(done) { - Parse.Cloud.run('echoKeys').then((result) => { - expect(result.applicationId).toEqual(Parse.applicationId); - expect(result.masterKey).toEqual(Parse.masterKey); - expect(result.javascriptKey).toEqual(Parse.javascriptKey); - done(); - }); - }); - - it('should properly create an object in before save', (done) => { - Parse.Cloud.run('createBeforeSaveChangedObject').then((res) => { - expect(res.get('foo')).toEqual('baz'); - done(); - }); - }) - it('test rest_create_app', function(done) { var appId; Parse._request('POST', 'rest_create_app').then((res) => { @@ -456,17 +215,6 @@ describe('miscellaneous', function() { }); describe('beforeSave', () => { - beforeEach(done => { - // Make sure the required mock for all tests is unset. - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); - done(); - }); - afterEach(done => { - // Make sure the required mock for all tests is unset. - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); - done(); - }); - it('object is set on create and update', done => { let triggerTime = 0; // Register a mock beforeSave hook @@ -511,45 +259,6 @@ describe('miscellaneous', function() { }); }); - it('dirtyKeys are set on update', done => { - let triggerTime = 0; - // Register a mock beforeSave hook - Parse.Cloud.beforeSave('GameScore', (req, res) => { - var object = req.object; - expect(object instanceof Parse.Object).toBeTruthy(); - expect(object.get('fooAgain')).toEqual('barAgain'); - if (triggerTime == 0) { - // Create - expect(object.get('foo')).toEqual('bar'); - } else if (triggerTime == 1) { - // Update - expect(object.dirtyKeys()).toEqual(['foo']); - expect(object.dirty('foo')).toBeTruthy(); - expect(object.get('foo')).toEqual('baz'); - } else { - res.error(); - } - triggerTime++; - res.success(); - }); - - let obj = new Parse.Object('GameScore'); - obj.set('foo', 'bar'); - obj.set('fooAgain', 'barAgain'); - obj.save().then(() => { - // We only update foo - obj.set('foo', 'baz'); - return obj.save(); - }).then(() => { - // Make sure the checking has been triggered - expect(triggerTime).toBe(2); - done(); - }, function(error) { - fail(error); - done(); - }); - }); - it('original object is set on update', done => { let triggerTime = 0; // Register a mock beforeSave hook @@ -673,7 +382,6 @@ describe('miscellaneous', function() { return obj.save(); }).then((obj) => { expect(obj.get('point').id).toEqual(pointId); - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); done(); }) }); @@ -711,8 +419,6 @@ describe('miscellaneous', function() { }).then(function() { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock beforeSave - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); done(); }, function(error) { fail(error); @@ -764,8 +470,6 @@ describe('miscellaneous', function() { }).then(function() { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }, function(error) { console.error(error); @@ -814,8 +518,6 @@ describe('miscellaneous', function() { }).then(function() { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }, function(error) { console.error(error); @@ -854,8 +556,6 @@ describe('miscellaneous', function() { }).then(() => { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }, error => { console.error(error); @@ -896,8 +596,6 @@ describe('miscellaneous', function() { }).then(() => { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); done(); }, error => { console.error(error); @@ -938,8 +636,6 @@ describe('miscellaneous', function() { }).then(() => { // Make sure the checking has been triggered expect(triggerTime).toBe(2); - // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }, error => { console.error(error); @@ -999,12 +695,10 @@ describe('miscellaneous', function() { }); Parse.Cloud.run('willFail').then((s) => { fail('Should not have succeeded.'); - Parse.Cloud._removeHook("Functions", "willFail"); done(); }, (e) => { expect(e.code).toEqual(141); expect(e.message).toEqual('noway'); - Parse.Cloud._removeHook("Functions", "willFail"); done(); }); }); @@ -1036,9 +730,6 @@ describe('miscellaneous', function() { }, (error, response, body) => { expect(error).toBe(null); expect(triggerTime).toEqual(2); - - Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }); }); @@ -1075,9 +766,6 @@ describe('miscellaneous', function() { }, (error, response, body) => { expect(error).toBe(null); expect(triggerTime).toEqual(2); - - Parse.Cloud._removeHook("Triggers", "beforeDelete", "GameScore"); - Parse.Cloud._removeHook("Triggers", "afterDelete", "GameScore"); done(); }); }); @@ -1107,24 +795,6 @@ describe('miscellaneous', function() { // Make sure query string params override body params expect(res.other).toEqual('2'); expect(res.foo).toEqual("bar"); - Parse.Cloud._removeHook("Functions",'echoParams'); - done(); - }); - }); - - it('test cloud function parameter validation success', (done) => { - // Register a function with validation - Parse.Cloud.define('functionWithParameterValidation', (req, res) => { - res.success('works'); - }, (request) => { - return request.params.success === 100; - }); - - Parse.Cloud.run('functionWithParameterValidation', {"success":100}).then((s) => { - Parse.Cloud._removeHook("Functions", "functionWithParameterValidation"); - done(); - }, (e) => { - fail('Validation should not have failed.'); done(); }); }); @@ -1139,7 +809,6 @@ describe('miscellaneous', function() { Parse.Cloud.run('functionWithParameterValidationFailure', {"success":500}).then((s) => { fail('Validation should not have succeeded'); - Parse.Cloud._removeHook("Functions", "functionWithParameterValidationFailure"); done(); }, (e) => { expect(e.code).toEqual(141); @@ -1156,7 +825,6 @@ describe('miscellaneous', function() { Parse.Cloud.run('func', {nullParam: null}) .then(() => { - Parse.Cloud._removeHook('Functions', 'func'); done() }, e => { fail('cloud code call failed'); @@ -1243,23 +911,6 @@ describe('miscellaneous', function() { }); }); - it('beforeSave change propagates through the save response', (done) => { - Parse.Cloud.beforeSave('ChangingObject', function(request, response) { - request.object.set('foo', 'baz'); - response.success(); - }); - let obj = new Parse.Object('ChangingObject'); - obj.save({ foo: 'bar' }).then((objAgain) => { - expect(objAgain.get('foo')).toEqual('baz'); - Parse.Cloud._removeHook("Triggers", "beforeSave", "ChangingObject"); - done(); - }, (e) => { - Parse.Cloud._removeHook("Triggers", "beforeSave", "ChangingObject"); - fail('Should not have failed to save.'); - done(); - }); - }); - it('dedupes an installation properly and returns updatedAt', (done) => { let headers = { 'Content-Type': 'application/json', diff --git a/spec/ParseRelation.spec.js b/spec/ParseRelation.spec.js index 8ff6c6c3..6b79743b 100644 --- a/spec/ParseRelation.spec.js +++ b/spec/ParseRelation.spec.js @@ -696,20 +696,16 @@ describe('Parse.Relation testing', () => { admins.first({ useMasterKey: true }) .then(user => { if (user) { - Parse.Cloud._removeHook('Functions', 'isAdmin'); done(); } else { - Parse.Cloud._removeHook('Functions', 'isAdmin'); fail('Should have found admin user, found nothing instead'); done(); } }, error => { - Parse.Cloud._removeHook('Functions', 'isAdmin'); fail('User not admin'); done(); }) }, error => { - Parse.Cloud._removeHook('Functions', 'isAdmin'); fail('Should have found admin user, errored instead'); fail(error); done(); diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index ce9763af..f333a714 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -1156,12 +1156,10 @@ describe('Parse.User testing', () => { Parse.User._logInWith("facebook", { success: function(innerModel) { - Parse.Cloud._removeHook('Triggers', 'beforeSave', Parse.User.className); done(); }, error: function(model, error) { ok(undefined, error); - Parse.Cloud._removeHook('Triggers', 'beforeSave', Parse.User.className); done(); } }); @@ -1584,8 +1582,6 @@ describe('Parse.User testing', () => { Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { success: function(model) { - Parse.Cloud._removeHook('Triggers', 'beforeSave', Parse.User.className); - Parse.Cloud._removeHook('Triggers', 'afterSave', Parse.User.className); done(); } }); @@ -2213,11 +2209,9 @@ describe('Parse.User testing', () => { }).then((user) => { expect(typeof user).toEqual('object'); expect(user.authData).toBeUndefined(); - Parse.Cloud._removeHook('Triggers', 'beforeSave', '_User'); done(); }).catch((err) => { fail('no request should fail: ' + JSON.stringify(err)); - Parse.Cloud._removeHook('Triggers', 'beforeSave', '_User'); done(); }); }); @@ -2237,7 +2231,6 @@ describe('Parse.User testing', () => { user.set('hello', 'world'); return user.save(); }).then(() => { - Parse.Cloud._removeHook('Triggers', 'afterSave', '_User'); done(); }); }); @@ -2395,7 +2388,6 @@ describe('Parse.User testing', () => { serverURL: 'http://localhost:8378/1', appId: 'test', masterKey: 'test', - cloud: './spec/cloud/main.js', revokeSessionOnPasswordReset: false, }) request.post({ diff --git a/spec/cloud/cloudCodeAbsoluteFile.js b/spec/cloud/cloudCodeAbsoluteFile.js new file mode 100644 index 00000000..f5fcf2b8 --- /dev/null +++ b/spec/cloud/cloudCodeAbsoluteFile.js @@ -0,0 +1,3 @@ +Parse.Cloud.define('cloudCodeInFile', (req, res) => { + res.success('It is possible to define cloud code in a file.'); +}); diff --git a/spec/cloud/cloudCodeRelativeFile.js b/spec/cloud/cloudCodeRelativeFile.js new file mode 100644 index 00000000..f5fcf2b8 --- /dev/null +++ b/spec/cloud/cloudCodeRelativeFile.js @@ -0,0 +1,3 @@ +Parse.Cloud.define('cloudCodeInFile', (req, res) => { + res.success('It is possible to define cloud code in a file.'); +}); diff --git a/spec/cloud/main.js b/spec/cloud/main.js deleted file mode 100644 index 0785c0a6..00000000 --- a/spec/cloud/main.js +++ /dev/null @@ -1,117 +0,0 @@ -Parse.Cloud.define('hello', function(req, res) { - res.success('Hello world!'); -}); - -Parse.Cloud.beforeSave('BeforeSaveFail', function(req, res) { - res.error('You shall not pass!'); -}); - -Parse.Cloud.beforeSave('BeforeSaveFailWithPromise', function (req, res) { - var query = new Parse.Query('Yolo'); - query.find().then(() => { - res.error('Nope'); - }, () => { - res.success(); - }); -}); - -Parse.Cloud.beforeSave('BeforeSaveUnchanged', function(req, res) { - res.success(); -}); - -Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) { - req.object.set('foo', 'baz'); - res.success(); -}); - -Parse.Cloud.afterSave('AfterSaveTest', function(req) { - var obj = new Parse.Object('AfterSaveProof'); - obj.set('proof', req.object.id); - obj.save(); -}); - -Parse.Cloud.beforeDelete('BeforeDeleteFail', function(req, res) { - res.error('Nope'); -}); - -Parse.Cloud.beforeSave('BeforeDeleteFailWithPromise', function (req, res) { - var query = new Parse.Query('Yolo'); - query.find().then(() => { - res.error('Nope'); - }, () => { - res.success(); - }); -}); - -Parse.Cloud.beforeDelete('BeforeDeleteTest', function(req, res) { - res.success(); -}); - -Parse.Cloud.afterDelete('AfterDeleteTest', function(req) { - var obj = new Parse.Object('AfterDeleteProof'); - obj.set('proof', req.object.id); - obj.save(); -}); - -Parse.Cloud.beforeSave('SaveTriggerUser', function(req, res) { - if (req.user && req.user.id) { - res.success(); - } else { - res.error('No user present on request object for beforeSave.'); - } -}); - -Parse.Cloud.afterSave('SaveTriggerUser', function(req) { - if (!req.user || !req.user.id) { - console.log('No user present on request object for afterSave.'); - } -}); - -Parse.Cloud.define('foo', function(req, res) { - res.success({ - object: { - __type: 'Object', - className: 'Foo', - objectId: '123', - x: 2, - relation: { - __type: 'Object', - className: 'Bar', - objectId: '234', - x: 3 - } - }, - array: [{ - __type: 'Object', - className: 'Bar', - objectId: '345', - x: 2 - }], - a: 2 - }); -}); - -Parse.Cloud.define('bar', function(req, res) { - res.error('baz'); -}); - -Parse.Cloud.define('requiredParameterCheck', function(req, res) { - res.success(); -}, function(params) { - return params.name; -}); - -Parse.Cloud.define('echoKeys', function(req, res){ - return res.success({ - applicationId: Parse.applicationId, - masterKey: Parse.masterKey, - javascriptKey: Parse.javascriptKey - }) -}); - -Parse.Cloud.define('createBeforeSaveChangedObject', function(req, res){ - var obj = new Parse.Object('BeforeSaveChanged'); - obj.save().then(() => { - res.success(obj); - }) -}) diff --git a/spec/helper.js b/spec/helper.js index aa63ff0f..049c9664 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -12,13 +12,11 @@ var TestUtils = require('../src/index').TestUtils; var MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter'); var databaseURI = process.env.DATABASE_URI; -var cloudMain = process.env.CLOUD_CODE_MAIN || './spec/cloud/main.js'; var port = 8378; // Default server configuration for tests. var defaultConfiguration = { databaseURI: databaseURI, - cloud: cloudMain, serverURL: 'http://localhost:' + port + '/1', appId: 'test', javascriptKey: 'test', @@ -94,6 +92,7 @@ var mongoAdapter = new MongoStorageAdapter({ }) afterEach(function(done) { + Parse.Cloud._removeAllHooks(); mongoAdapter.getAllSchemas() .then(allSchemas => { allSchemas.forEach((schema) => { diff --git a/spec/index.spec.js b/spec/index.spec.js index f76e809e..6ea64842 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -12,7 +12,7 @@ describe('server', () => { expect(setServerConfiguration.bind(undefined, { appId: 'myId', masterKey: 'mk' })).toThrow('You must provide a serverURL!'); done(); }); - + it('support http basic authentication with masterkey', done => { request.get({ url: 'http://localhost:8378/1/classes/TestObject', @@ -24,7 +24,7 @@ describe('server', () => { done(); }); }); - + it('support http basic authentication with javascriptKey', done => { request.get({ url: 'http://localhost:8378/1/classes/TestObject', @@ -199,26 +199,6 @@ describe('server', () => { }) }); - it('can load absolute cloud code file', done => { - setServerConfiguration({ - serverURL: 'http://localhost:8378/1', - appId: 'test', - masterKey: 'test', - cloud: __dirname + '/cloud/main.js' - }); - done(); - }); - - it('can load relative cloud code file', done => { - setServerConfiguration({ - serverURL: 'http://localhost:8378/1', - appId: 'test', - masterKey: 'test', - cloud: './spec/cloud/main.js' - }); - done(); - }); - it('can create a parse-server', done => { var parseServer = new ParseServer.default({ appId: "aTestApp", diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index e1b9ec3a..ca323f0a 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -1,4 +1,4 @@ -import { Parse } from 'parse/node'; +import { Parse } from 'parse/node'; import * as triggers from '../triggers'; function validateClassNameForTriggers(className) { @@ -40,12 +40,16 @@ ParseCloud.afterDelete = function(parseClass, handler) { var className = getClassName(parseClass); triggers.addTrigger(triggers.Types.afterDelete, className, handler, Parse.applicationId); }; - + ParseCloud._removeHook = function(category, name, type, applicationId) { applicationId = applicationId || Parse.applicationId; triggers._unregister(applicationId, category, name, type); }; +ParseCloud._removeAllHooks = () => { + triggers._unregisterAll(); +} + ParseCloud.httpRequest = require("./httpRequest"); module.exports = ParseCloud; diff --git a/src/triggers.js b/src/triggers.js index c7c9ba2c..0827de7a 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -1,6 +1,6 @@ // triggers.js -import Parse from 'parse/node'; -import AppCache from './cache'; +import Parse from 'parse/node'; +import AppCache from './cache'; export const Types = { beforeSave: 'beforeSave', @@ -49,15 +49,19 @@ export function removeTrigger(type, className, applicationId) { delete _triggerStore[applicationId].Triggers[type][className] } -export function _unregister(a,b,c,d) { - if (d) { - removeTrigger(c,d,a); - delete _triggerStore[a][b][c][d]; +export function _unregister(appId,category,className,type) { + if (type) { + removeTrigger(className,type,appId); + delete _triggerStore[appId][category][className][type]; } else { - delete _triggerStore[a][b][c]; + delete _triggerStore[appId][category][className]; } } +export function _unregisterAll() { + Object.keys(_triggerStore).forEach(appId => delete _triggerStore[appId]); +} + export function getTrigger(className, triggerType, applicationId) { if (!applicationId) { throw "Missing ApplicationID";