Skip to content

Commit 7c772c4

Browse files
blastoydplewis
authored andcommitted
Properly handle return values in beforeSave (parse-community#5228)
* added failing test case to CloudCode.spec.js a possible bug found where beforeSave does not apply changes to request object if the beforeSave hook ends with 'true' returned * moddified triggers to return null when beforeSave also changed test cases to be more descriptive + added extra test case that returns promise in the beforeSave * address original issue * Revert "address original issue" This reverts commit e01c57d. * fix promises and tests * Add a test to verify that a failed beforeChange hook will prevent updating the object.
1 parent 118e80f commit 7c772c4

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

spec/CloudCode.spec.js

+60
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,27 @@ describe('Cloud Code', () => {
162162
);
163163
});
164164

165+
it("test beforeSave changed object fail doesn't change object", async function() {
166+
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
167+
if (req.object.has('fail')) {
168+
return Promise.reject(new Error('something went wrong'));
169+
}
170+
171+
return Promise.resolve();
172+
});
173+
174+
const obj = new Parse.Object('BeforeSaveChanged');
175+
obj.set('foo', 'bar');
176+
await obj.save();
177+
obj.set('foo', 'baz').set('fail', true);
178+
try {
179+
await obj.save();
180+
} catch (e) {
181+
await obj.fetch();
182+
expect(obj.get('foo')).toBe('bar');
183+
}
184+
});
185+
165186
it('test beforeSave returns value on create and update', done => {
166187
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
167188
req.object.set('foo', 'baz');
@@ -179,6 +200,45 @@ describe('Cloud Code', () => {
179200
});
180201
});
181202

203+
it('test beforeSave applies changes when beforeSave returns true', done => {
204+
Parse.Cloud.beforeSave('Insurance', function(req) {
205+
req.object.set('rate', '$49.99/Month');
206+
return true;
207+
});
208+
209+
const insurance = new Parse.Object('Insurance');
210+
insurance.set('rate', '$5.00/Month');
211+
insurance.save().then(insurance => {
212+
expect(insurance.get('rate')).toEqual('$49.99/Month');
213+
done();
214+
});
215+
});
216+
217+
it('test beforeSave applies changes and resolves returned promise', done => {
218+
Parse.Cloud.beforeSave('Insurance', function(req) {
219+
req.object.set('rate', '$49.99/Month');
220+
return new Parse.Query('Pet').get(req.object.get('pet').id).then(pet => {
221+
pet.set('healthy', true);
222+
return pet.save();
223+
});
224+
});
225+
226+
const pet = new Parse.Object('Pet');
227+
pet.set('healthy', false);
228+
pet.save().then(pet => {
229+
const insurance = new Parse.Object('Insurance');
230+
insurance.set('pet', pet);
231+
insurance.set('rate', '$5.00/Month');
232+
insurance.save().then(insurance => {
233+
expect(insurance.get('rate')).toEqual('$49.99/Month');
234+
new Parse.Query('Pet').get(insurance.get('pet').id).then(pet => {
235+
expect(pet.get('healthy')).toEqual(true);
236+
done();
237+
});
238+
});
239+
});
240+
});
241+
182242
it('test afterSave ran and created an object', function(done) {
183243
Parse.Cloud.afterSave('AfterSaveTest', function(req) {
184244
const obj = new Parse.Object('AfterSaveProof');

spec/CloudCodeLogger.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ describe('Cloud Code Logger', () => {
101101
expect(cloudTriggerMessage[0]).toBe('info');
102102
expect(cloudTriggerMessage[2].triggerType).toEqual('beforeSave');
103103
expect(cloudTriggerMessage[1]).toMatch(
104-
/beforeSave triggered for MyObject for user [^ ]*\n {2}Input: {}\n {2}Result: {}/
104+
/beforeSave triggered for MyObject for user [^ ]*\n {2}Input: {}\n {2}Result: {"object":{}}/
105105
);
106106
expect(cloudTriggerMessage[2].user).toBe(user.id);
107107
expect(errorMessage[0]).toBe('error');

src/triggers.js

+15
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export function getResponseObject(request, resolve, reject) {
254254
// Use the JSON response
255255
if (
256256
response &&
257+
typeof response === 'object' &&
257258
!request.object.equals(response) &&
258259
request.triggerName === Types.beforeSave
259260
) {
@@ -573,6 +574,20 @@ export function maybeRunTrigger(
573574
auth
574575
);
575576
}
577+
// beforeSave is expected to return null (nothing)
578+
if (triggerType === Types.beforeSave) {
579+
if (promise && typeof promise.then === 'function') {
580+
return promise.then(response => {
581+
// response.object may come from express routing before hook
582+
if (response && response.object) {
583+
return response;
584+
}
585+
return null;
586+
});
587+
}
588+
return null;
589+
}
590+
576591
return promise;
577592
})
578593
.then(success, error);

0 commit comments

Comments
 (0)