2016-05-19 13:38:16 -07:00
|
|
|
"use strict"
|
|
|
|
|
const Parse = require("parse/node");
|
2016-06-10 20:27:21 -07:00
|
|
|
const rp = require('request-promise');
|
2016-05-22 09:59:36 -07:00
|
|
|
const InMemoryCacheAdapter = require('../src/Adapters/Cache/InMemoryCacheAdapter').InMemoryCacheAdapter;
|
2016-05-19 13:38:16 -07:00
|
|
|
|
|
|
|
|
describe('Cloud Code', () => {
|
|
|
|
|
it('can load absolute cloud code file', done => {
|
2016-06-10 20:27:21 -07:00
|
|
|
reconfigureServer({ cloud: __dirname + '/cloud/cloudCodeRelativeFile.js' })
|
|
|
|
|
.then(() => {
|
|
|
|
|
Parse.Cloud.run('cloudCodeInFile', {}, result => {
|
|
|
|
|
expect(result).toEqual('It is possible to define cloud code in a file.');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
})
|
2016-05-19 13:38:16 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('can load relative cloud code file', done => {
|
2016-06-10 20:27:21 -07:00
|
|
|
reconfigureServer({ cloud: './spec/cloud/cloudCodeAbsoluteFile.js' })
|
|
|
|
|
.then(() => {
|
|
|
|
|
Parse.Cloud.run('cloudCodeInFile', {}, result => {
|
|
|
|
|
expect(result).toEqual('It is possible to define cloud code in a file.');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
})
|
2016-05-19 13:38:16 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
Make parse-server cloud code logging closer parse.com legacy (#2550)
* Make parse-server cloud code logging much to parse.com legacy. (fixes #2501)
1. More closely mimic the wording. Include the user id.
2. Truncate input and result at 1k char.
3. Use more sensible metadata that would makes sense to index. The guideline I used was: if it makes sense to filter on, put it in metadata. If it makes sense to "free text" search on, then put it in the message.
- file and console output, logging an object does not do what on might expect. For example, logging a function's "params":
```
expected:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, params= { foo: "bar", "bar": baz }, user=qWHLVEsbEe
what you actually get:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, foo=bar, bar=baz, user=qWHLVEsbEe
```
- logging highly variable metadata is pretty useless for indexing when logs are sent to a logging repository like elastic search. In that use case, you want to index stuff you expect to filter on like user, hook type.
- finally, putting the same input and result data in both the metadata and the message makes each message much larger with no additional value (that I know of anyway :).
4. Change some of the naming of functions in trigger.js to make future work easier. I was confused about why there were three logging functions in trigger and it took me awhile to get that before hooks and after hooks are logged differently. I just changed the names to make it obvious at first glance.
5. Add some try/catches to help any future futzers see syntax errors, etc instead of just hanging.
Some log examples from unit test output:
```
info: Ran cloud function loggerTest for user YUD2os1i5B with:
Input: {}
Result: {} functionName=loggerTest, user=YUD2os1i5B
info: beforeSave triggered for MyObject for user nssehQ3wtz:
Input: {}
Result: {} className=MyObject, triggerType=beforeSave, user=nssehQ3wtz
info: afterSave triggered for MyObject for user XdznQgTD0p:
Input: {"createdAt":"2016-08-19T01:11:31.249Z","updatedAt":"2016-08-19T01:11:31.249Z","objectId":"POoOOLL89U"} className=MyObject, triggerType=afterSave, user=XdznQgTD0p
error: beforeSave failed for MyObject for user 7JHqCZgnhf:
Input: {}
Error: {"code":141,"message":"uh oh!"} className=MyObject, triggerType=beforeSave, code=141, message=uh oh!, user=7JHqCZgnhf
info: Ran cloud function aFunction for user YR3nOoT3r9 with:
Input: {"foo":"bar"}
Result: "it worked!" functionName=aFunction, user=YR3nOoT3r9
error: Failed running cloud function aFunction for user Xm6NpOyuMC with:
Input: {"foo":"bar"}
Error: {"code":141,"message":"it failed!"} functionName=aFunction, code=141, message=it failed!, user=Xm6NpOyuMC
info: Ran cloud function aFunction for user CK1lvkmaLg with:
Input: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated)
Result: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) functionName=aFunction, user=CK1lvkmaLg
```
* Implement PR comments:
- add back params to metadata and add back to the test
- use screaming snake case for conts
* fix typo
2016-08-19 13:39:51 -07:00
|
|
|
it('returns an error', (done) => {
|
|
|
|
|
Parse.Cloud.define('cloudCodeWithError', (req, res) => {
|
2016-11-24 15:47:41 -05:00
|
|
|
/* eslint-disable no-undef */
|
Make parse-server cloud code logging closer parse.com legacy (#2550)
* Make parse-server cloud code logging much to parse.com legacy. (fixes #2501)
1. More closely mimic the wording. Include the user id.
2. Truncate input and result at 1k char.
3. Use more sensible metadata that would makes sense to index. The guideline I used was: if it makes sense to filter on, put it in metadata. If it makes sense to "free text" search on, then put it in the message.
- file and console output, logging an object does not do what on might expect. For example, logging a function's "params":
```
expected:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, params= { foo: "bar", "bar": baz }, user=qWHLVEsbEe
what you actually get:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, foo=bar, bar=baz, user=qWHLVEsbEe
```
- logging highly variable metadata is pretty useless for indexing when logs are sent to a logging repository like elastic search. In that use case, you want to index stuff you expect to filter on like user, hook type.
- finally, putting the same input and result data in both the metadata and the message makes each message much larger with no additional value (that I know of anyway :).
4. Change some of the naming of functions in trigger.js to make future work easier. I was confused about why there were three logging functions in trigger and it took me awhile to get that before hooks and after hooks are logged differently. I just changed the names to make it obvious at first glance.
5. Add some try/catches to help any future futzers see syntax errors, etc instead of just hanging.
Some log examples from unit test output:
```
info: Ran cloud function loggerTest for user YUD2os1i5B with:
Input: {}
Result: {} functionName=loggerTest, user=YUD2os1i5B
info: beforeSave triggered for MyObject for user nssehQ3wtz:
Input: {}
Result: {} className=MyObject, triggerType=beforeSave, user=nssehQ3wtz
info: afterSave triggered for MyObject for user XdznQgTD0p:
Input: {"createdAt":"2016-08-19T01:11:31.249Z","updatedAt":"2016-08-19T01:11:31.249Z","objectId":"POoOOLL89U"} className=MyObject, triggerType=afterSave, user=XdznQgTD0p
error: beforeSave failed for MyObject for user 7JHqCZgnhf:
Input: {}
Error: {"code":141,"message":"uh oh!"} className=MyObject, triggerType=beforeSave, code=141, message=uh oh!, user=7JHqCZgnhf
info: Ran cloud function aFunction for user YR3nOoT3r9 with:
Input: {"foo":"bar"}
Result: "it worked!" functionName=aFunction, user=YR3nOoT3r9
error: Failed running cloud function aFunction for user Xm6NpOyuMC with:
Input: {"foo":"bar"}
Error: {"code":141,"message":"it failed!"} functionName=aFunction, code=141, message=it failed!, user=Xm6NpOyuMC
info: Ran cloud function aFunction for user CK1lvkmaLg with:
Input: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated)
Result: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) functionName=aFunction, user=CK1lvkmaLg
```
* Implement PR comments:
- add back params to metadata and add back to the test
- use screaming snake case for conts
* fix typo
2016-08-19 13:39:51 -07:00
|
|
|
foo.bar();
|
2016-11-24 15:47:41 -05:00
|
|
|
/* eslint-enable no-undef */
|
Make parse-server cloud code logging closer parse.com legacy (#2550)
* Make parse-server cloud code logging much to parse.com legacy. (fixes #2501)
1. More closely mimic the wording. Include the user id.
2. Truncate input and result at 1k char.
3. Use more sensible metadata that would makes sense to index. The guideline I used was: if it makes sense to filter on, put it in metadata. If it makes sense to "free text" search on, then put it in the message.
- file and console output, logging an object does not do what on might expect. For example, logging a function's "params":
```
expected:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, params= { foo: "bar", "bar": baz }, user=qWHLVEsbEe
what you actually get:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, foo=bar, bar=baz, user=qWHLVEsbEe
```
- logging highly variable metadata is pretty useless for indexing when logs are sent to a logging repository like elastic search. In that use case, you want to index stuff you expect to filter on like user, hook type.
- finally, putting the same input and result data in both the metadata and the message makes each message much larger with no additional value (that I know of anyway :).
4. Change some of the naming of functions in trigger.js to make future work easier. I was confused about why there were three logging functions in trigger and it took me awhile to get that before hooks and after hooks are logged differently. I just changed the names to make it obvious at first glance.
5. Add some try/catches to help any future futzers see syntax errors, etc instead of just hanging.
Some log examples from unit test output:
```
info: Ran cloud function loggerTest for user YUD2os1i5B with:
Input: {}
Result: {} functionName=loggerTest, user=YUD2os1i5B
info: beforeSave triggered for MyObject for user nssehQ3wtz:
Input: {}
Result: {} className=MyObject, triggerType=beforeSave, user=nssehQ3wtz
info: afterSave triggered for MyObject for user XdznQgTD0p:
Input: {"createdAt":"2016-08-19T01:11:31.249Z","updatedAt":"2016-08-19T01:11:31.249Z","objectId":"POoOOLL89U"} className=MyObject, triggerType=afterSave, user=XdznQgTD0p
error: beforeSave failed for MyObject for user 7JHqCZgnhf:
Input: {}
Error: {"code":141,"message":"uh oh!"} className=MyObject, triggerType=beforeSave, code=141, message=uh oh!, user=7JHqCZgnhf
info: Ran cloud function aFunction for user YR3nOoT3r9 with:
Input: {"foo":"bar"}
Result: "it worked!" functionName=aFunction, user=YR3nOoT3r9
error: Failed running cloud function aFunction for user Xm6NpOyuMC with:
Input: {"foo":"bar"}
Error: {"code":141,"message":"it failed!"} functionName=aFunction, code=141, message=it failed!, user=Xm6NpOyuMC
info: Ran cloud function aFunction for user CK1lvkmaLg with:
Input: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated)
Result: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) functionName=aFunction, user=CK1lvkmaLg
```
* Implement PR comments:
- add back params to metadata and add back to the test
- use screaming snake case for conts
* fix typo
2016-08-19 13:39:51 -07:00
|
|
|
res.success('I better throw an error.');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.run('cloudCodeWithError')
|
|
|
|
|
.then(
|
2016-11-24 15:47:41 -05:00
|
|
|
() => done.fail('should not succeed'),
|
Make parse-server cloud code logging closer parse.com legacy (#2550)
* Make parse-server cloud code logging much to parse.com legacy. (fixes #2501)
1. More closely mimic the wording. Include the user id.
2. Truncate input and result at 1k char.
3. Use more sensible metadata that would makes sense to index. The guideline I used was: if it makes sense to filter on, put it in metadata. If it makes sense to "free text" search on, then put it in the message.
- file and console output, logging an object does not do what on might expect. For example, logging a function's "params":
```
expected:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, params= { foo: "bar", "bar": baz }, user=qWHLVEsbEe
what you actually get:
info: Ran cloud function aFunction for user qWHLVEsbEe with:
Input: {"foo":"bar","bar":"baz"}
Result: "it worked!" functionName=aFunction, foo=bar, bar=baz, user=qWHLVEsbEe
```
- logging highly variable metadata is pretty useless for indexing when logs are sent to a logging repository like elastic search. In that use case, you want to index stuff you expect to filter on like user, hook type.
- finally, putting the same input and result data in both the metadata and the message makes each message much larger with no additional value (that I know of anyway :).
4. Change some of the naming of functions in trigger.js to make future work easier. I was confused about why there were three logging functions in trigger and it took me awhile to get that before hooks and after hooks are logged differently. I just changed the names to make it obvious at first glance.
5. Add some try/catches to help any future futzers see syntax errors, etc instead of just hanging.
Some log examples from unit test output:
```
info: Ran cloud function loggerTest for user YUD2os1i5B with:
Input: {}
Result: {} functionName=loggerTest, user=YUD2os1i5B
info: beforeSave triggered for MyObject for user nssehQ3wtz:
Input: {}
Result: {} className=MyObject, triggerType=beforeSave, user=nssehQ3wtz
info: afterSave triggered for MyObject for user XdznQgTD0p:
Input: {"createdAt":"2016-08-19T01:11:31.249Z","updatedAt":"2016-08-19T01:11:31.249Z","objectId":"POoOOLL89U"} className=MyObject, triggerType=afterSave, user=XdznQgTD0p
error: beforeSave failed for MyObject for user 7JHqCZgnhf:
Input: {}
Error: {"code":141,"message":"uh oh!"} className=MyObject, triggerType=beforeSave, code=141, message=uh oh!, user=7JHqCZgnhf
info: Ran cloud function aFunction for user YR3nOoT3r9 with:
Input: {"foo":"bar"}
Result: "it worked!" functionName=aFunction, user=YR3nOoT3r9
error: Failed running cloud function aFunction for user Xm6NpOyuMC with:
Input: {"foo":"bar"}
Error: {"code":141,"message":"it failed!"} functionName=aFunction, code=141, message=it failed!, user=Xm6NpOyuMC
info: Ran cloud function aFunction for user CK1lvkmaLg with:
Input: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated)
Result: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) functionName=aFunction, user=CK1lvkmaLg
```
* Implement PR comments:
- add back params to metadata and add back to the test
- use screaming snake case for conts
* fix typo
2016-08-19 13:39:51 -07:00
|
|
|
e => {
|
|
|
|
|
expect(e).toEqual(new Parse.Error(1, undefined));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-01 10:28:06 -04:00
|
|
|
it('beforeSave rejection with custom error code', function(done) {
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveFailWithErrorCode', function (req, res) {
|
|
|
|
|
res.error(999, 'Nope');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var obj = new Parse.Object('BeforeSaveFailWithErrorCode');
|
|
|
|
|
obj.set('foo', 'bar');
|
|
|
|
|
obj.save().then(function() {
|
|
|
|
|
fail('Should not have been able to save BeforeSaveFailWithErrorCode class.');
|
|
|
|
|
done();
|
|
|
|
|
}, function(error) {
|
|
|
|
|
expect(error.code).toEqual(999);
|
|
|
|
|
expect(error.message).toEqual('Nope');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-05-19 13:38:16 -07:00
|
|
|
it('basic beforeSave rejection via promise', function(done) {
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveFailWithPromise', function (req, res) {
|
|
|
|
|
var query = new Parse.Query('Yolo');
|
|
|
|
|
query.find().then(() => {
|
2016-11-24 15:47:41 -05:00
|
|
|
res.error('Nope');
|
2016-05-19 13:38:16 -07:00
|
|
|
}, () => {
|
|
|
|
|
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');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.save().then(() => {
|
2016-05-19 13:38:16 -07:00
|
|
|
expect(obj.get('foo')).toEqual('baz');
|
|
|
|
|
obj.set('foo', 'bar');
|
2016-11-24 15:47:41 -05:00
|
|
|
return obj.save().then(() => {
|
2016-05-19 13:38:16 -07:00
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
|
2016-08-17 15:26:42 +02:00
|
|
|
it('test afterSave ran on created object and returned a promise', function(done) {
|
|
|
|
|
Parse.Cloud.afterSave('AfterSaveTest2', function(req) {
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = req.object;
|
2016-11-24 15:47:41 -05:00
|
|
|
if(!obj.existed())
|
2016-08-17 15:26:42 +02:00
|
|
|
{
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-11-24 15:47:41 -05:00
|
|
|
setTimeout(function(){
|
|
|
|
|
obj.set('proof', obj.id);
|
|
|
|
|
obj.save().then(function(){
|
|
|
|
|
promise.resolve();
|
|
|
|
|
});
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterSaveTest2');
|
2016-08-17 15:26:42 +02:00
|
|
|
obj.save().then(function(){
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('AfterSaveTest2');
|
2016-11-24 15:47:41 -05:00
|
|
|
query.equalTo('proof', obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results.length).toEqual(1);
|
2016-12-07 15:17:05 -08:00
|
|
|
const savedObject = results[0];
|
2016-11-24 15:47:41 -05:00
|
|
|
expect(savedObject.get('proof')).toEqual(obj.id);
|
|
|
|
|
done();
|
|
|
|
|
},
|
2016-08-17 15:26:42 +02:00
|
|
|
function(error) {
|
2016-11-24 15:47:41 -05:00
|
|
|
fail(error);
|
|
|
|
|
done();
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
// TODO: Fails on CI randomly as racing
|
|
|
|
|
xit('test afterSave ignoring promise, object not found', function(done) {
|
2016-08-17 15:26:42 +02:00
|
|
|
Parse.Cloud.afterSave('AfterSaveTest2', function(req) {
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = req.object;
|
2016-11-24 15:47:41 -05:00
|
|
|
if(!obj.existed())
|
2016-08-17 15:26:42 +02:00
|
|
|
{
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-11-24 15:47:41 -05:00
|
|
|
setTimeout(function(){
|
|
|
|
|
obj.set('proof', obj.id);
|
|
|
|
|
obj.save().then(function(){
|
|
|
|
|
promise.resolve();
|
|
|
|
|
});
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterSaveTest2');
|
2016-08-17 15:26:42 +02:00
|
|
|
obj.save().then(function(){
|
2016-11-24 15:47:41 -05:00
|
|
|
done();
|
2016-08-17 15:26:42 +02:00
|
|
|
})
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('AfterSaveTest2');
|
2016-08-17 15:26:42 +02:00
|
|
|
query.equalTo('proof', obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
2016-11-24 15:47:41 -05:00
|
|
|
expect(results.length).toEqual(0);
|
2016-08-17 15:26:42 +02:00
|
|
|
},
|
|
|
|
|
function(error) {
|
2016-11-24 15:47:41 -05:00
|
|
|
fail(error);
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('test afterSave rejecting promise', function(done) {
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.afterSave('AfterSaveTest2', function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-11-24 15:47:41 -05:00
|
|
|
setTimeout(function(){
|
|
|
|
|
promise.reject("THIS SHOULD BE IGNORED");
|
|
|
|
|
}, 1000);
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
return promise;
|
|
|
|
|
});
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterSaveTest2');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.save().then(function(){
|
|
|
|
|
done();
|
|
|
|
|
}, function(error){
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
})
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('test afterDelete returning promise, object is deleted when destroy resolves', function(done) {
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.afterDelete('AfterDeleteTest2', function(req) {
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
setTimeout(function(){
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterDeleteTestProof');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.set('proof', req.object.id);
|
|
|
|
|
obj.save().then(function(){
|
|
|
|
|
promise.resolve();
|
|
|
|
|
});
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
}, 1000);
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
return promise;
|
|
|
|
|
});
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const errorHandler = function(error) {
|
2016-11-24 15:47:41 -05:00
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
}
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterDeleteTest2');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.save().then(function(){
|
|
|
|
|
obj.destroy().then(function(){
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('AfterDeleteTestProof');
|
2016-11-24 15:47:41 -05:00
|
|
|
query.equalTo('proof', obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results.length).toEqual(1);
|
2016-12-07 15:17:05 -08:00
|
|
|
const deletedObject = results[0];
|
2016-11-24 15:47:41 -05:00
|
|
|
expect(deletedObject.get('proof')).toEqual(obj.id);
|
|
|
|
|
done();
|
|
|
|
|
}, errorHandler);
|
|
|
|
|
}, errorHandler)
|
|
|
|
|
}, errorHandler);
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('test afterDelete ignoring promise, object is not yet deleted', function(done) {
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.afterDelete('AfterDeleteTest2', function(req) {
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
setTimeout(function(){
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterDeleteTestProof');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.set('proof', req.object.id);
|
|
|
|
|
obj.save().then(function(){
|
|
|
|
|
promise.resolve();
|
|
|
|
|
});
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
}, 1000);
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
return promise;
|
|
|
|
|
});
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const errorHandler = function(error) {
|
2016-11-24 15:47:41 -05:00
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('AfterDeleteTest2');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.save().then(function(){
|
|
|
|
|
obj.destroy().then(function(){
|
|
|
|
|
done();
|
|
|
|
|
})
|
2016-08-17 15:26:42 +02:00
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('AfterDeleteTestProof');
|
2016-11-24 15:47:41 -05:00
|
|
|
query.equalTo('proof', obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results.length).toEqual(0);
|
2016-08-17 15:26:42 +02:00
|
|
|
}, errorHandler);
|
2016-11-24 15:47:41 -05:00
|
|
|
}, errorHandler);
|
2016-08-17 15:26:42 +02:00
|
|
|
});
|
|
|
|
|
|
2016-05-19 13:38:16 -07:00
|
|
|
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();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-10 03:37:05 +08:00
|
|
|
it('test cloud function request params types', function(done) {
|
|
|
|
|
Parse.Cloud.define('params', function(req, res) {
|
|
|
|
|
expect(req.params.date instanceof Date).toBe(true);
|
|
|
|
|
expect(req.params.date.getTime()).toBe(1463907600000);
|
|
|
|
|
expect(req.params.dateList[0] instanceof Date).toBe(true);
|
|
|
|
|
expect(req.params.dateList[0].getTime()).toBe(1463907600000);
|
|
|
|
|
expect(req.params.complexStructure.date[0] instanceof Date).toBe(true);
|
|
|
|
|
expect(req.params.complexStructure.date[0].getTime()).toBe(1463907600000);
|
|
|
|
|
expect(req.params.complexStructure.deepDate.date[0] instanceof Date).toBe(true);
|
|
|
|
|
expect(req.params.complexStructure.deepDate.date[0].getTime()).toBe(1463907600000);
|
|
|
|
|
expect(req.params.complexStructure.deepDate2[0].date instanceof Date).toBe(true);
|
|
|
|
|
expect(req.params.complexStructure.deepDate2[0].date.getTime()).toBe(1463907600000);
|
2016-07-19 02:14:32 -04:00
|
|
|
// Regression for #2294
|
|
|
|
|
expect(req.params.file instanceof Parse.File).toBe(true);
|
|
|
|
|
expect(req.params.file.url()).toEqual('https://some.url');
|
|
|
|
|
// Regression for #2204
|
|
|
|
|
expect(req.params.array).toEqual(['a', 'b', 'c']);
|
|
|
|
|
expect(Array.isArray(req.params.array)).toBe(true);
|
|
|
|
|
expect(req.params.arrayOfArray).toEqual([['a', 'b', 'c'], ['d', 'e','f']]);
|
|
|
|
|
expect(Array.isArray(req.params.arrayOfArray)).toBe(true);
|
|
|
|
|
expect(Array.isArray(req.params.arrayOfArray[0])).toBe(true);
|
|
|
|
|
expect(Array.isArray(req.params.arrayOfArray[1])).toBe(true);
|
2016-06-10 03:37:05 +08:00
|
|
|
return res.success({});
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const params = {
|
2016-06-10 03:37:05 +08:00
|
|
|
'date': {
|
|
|
|
|
'__type': 'Date',
|
|
|
|
|
'iso': '2016-05-22T09:00:00.000Z'
|
|
|
|
|
},
|
|
|
|
|
'dateList': [
|
|
|
|
|
{
|
|
|
|
|
'__type': 'Date',
|
|
|
|
|
'iso': '2016-05-22T09:00:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
'lol': 'hello',
|
|
|
|
|
'complexStructure': {
|
|
|
|
|
'date': [
|
|
|
|
|
{
|
|
|
|
|
'__type': 'Date',
|
|
|
|
|
'iso': '2016-05-22T09:00:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
'deepDate': {
|
|
|
|
|
'date': [
|
|
|
|
|
{
|
|
|
|
|
'__type': 'Date',
|
|
|
|
|
'iso': '2016-05-22T09:00:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
'deepDate2': [
|
|
|
|
|
{
|
|
|
|
|
'date': {
|
|
|
|
|
'__type': 'Date',
|
|
|
|
|
'iso': '2016-05-22T09:00:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
2016-07-19 02:14:32 -04:00
|
|
|
},
|
|
|
|
|
'file': Parse.File.fromJSON({
|
|
|
|
|
__type: 'File',
|
|
|
|
|
name: 'name',
|
|
|
|
|
url: 'https://some.url'
|
|
|
|
|
}),
|
|
|
|
|
'array': ['a', 'b', 'c'],
|
|
|
|
|
'arrayOfArray': [['a', 'b', 'c'], ['d', 'e', 'f']]
|
2016-06-10 03:37:05 +08:00
|
|
|
};
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.run('params', params).then(() => {
|
2016-06-10 03:37:05 +08:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-05-19 13:38:16 -07:00
|
|
|
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');
|
2016-11-24 15:47:41 -05:00
|
|
|
obj.save().then(() => {
|
2016-05-19 13:38:16 -07:00
|
|
|
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();
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('GameScore');
|
2016-05-19 13:38:16 -07:00
|
|
|
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();
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('ChangingObject');
|
2016-05-19 13:38:16 -07:00
|
|
|
obj.save({ foo: 'bar' }).then((objAgain) => {
|
|
|
|
|
expect(objAgain.get('foo')).toEqual('baz');
|
|
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, () => {
|
2016-05-19 13:38:16 -07:00
|
|
|
fail('Should not have failed to save.');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-09-24 13:53:04 -04:00
|
|
|
it('beforeSave change propagates through the afterSave #1931', (done) => {
|
|
|
|
|
Parse.Cloud.beforeSave('ChangingObject', function(request, response) {
|
|
|
|
|
request.object.unset('file');
|
|
|
|
|
request.object.unset('date');
|
|
|
|
|
response.success();
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.afterSave('ChangingObject', function(request) {
|
2016-09-24 13:53:04 -04:00
|
|
|
expect(request.object.has("file")).toBe(false);
|
|
|
|
|
expect(request.object.has("date")).toBe(false);
|
|
|
|
|
expect(request.object.get('file')).toBeUndefined();
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
|
2016-09-24 13:53:04 -04:00
|
|
|
file.save().then(() => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('ChangingObject');
|
2016-09-24 13:53:04 -04:00
|
|
|
return obj.save({ file, date: new Date() })
|
|
|
|
|
}).then(() => {
|
|
|
|
|
done();
|
|
|
|
|
}, () => {
|
|
|
|
|
fail();
|
|
|
|
|
done();
|
|
|
|
|
})
|
|
|
|
|
});
|
2016-05-19 13:38:16 -07:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.run('functionWithParameterValidation', {"success":100}).then(() => {
|
2016-05-19 13:38:16 -07:00
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, () => {
|
2016-05-19 13:38:16 -07:00
|
|
|
fail('Validation should not have failed.');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-05-22 09:59:36 -07:00
|
|
|
|
|
|
|
|
it('doesnt receive stale user in cloud code functions after user has been updated with master key (regression test for #1836)', done => {
|
|
|
|
|
Parse.Cloud.define('testQuery', function(request, response) {
|
|
|
|
|
response.success(request.user.get('data'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.User.signUp('user', 'pass')
|
|
|
|
|
.then(user => {
|
|
|
|
|
user.set('data', 'AAA');
|
|
|
|
|
return user.save();
|
|
|
|
|
})
|
|
|
|
|
.then(() => Parse.Cloud.run('testQuery'))
|
|
|
|
|
.then(result => {
|
|
|
|
|
expect(result).toEqual('AAA');
|
|
|
|
|
Parse.User.current().set('data', 'BBB');
|
|
|
|
|
return Parse.User.current().save(null, {useMasterKey: true});
|
|
|
|
|
})
|
|
|
|
|
.then(() => Parse.Cloud.run('testQuery'))
|
|
|
|
|
.then(result => {
|
|
|
|
|
expect(result).toEqual('BBB');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('clears out the user cache for all sessions when the user is changed', done => {
|
2016-06-10 20:27:21 -07:00
|
|
|
let session1;
|
|
|
|
|
let session2;
|
|
|
|
|
let user;
|
2016-05-22 09:59:36 -07:00
|
|
|
const cacheAdapter = new InMemoryCacheAdapter({ ttl: 100000000 });
|
2016-06-10 20:27:21 -07:00
|
|
|
reconfigureServer({ cacheAdapter })
|
|
|
|
|
.then(() => {
|
|
|
|
|
Parse.Cloud.define('checkStaleUser', (request, response) => {
|
|
|
|
|
response.success(request.user.get('data'));
|
|
|
|
|
});
|
2016-05-22 09:59:36 -07:00
|
|
|
|
2016-06-10 20:27:21 -07:00
|
|
|
user = new Parse.User();
|
|
|
|
|
user.set('username', 'test');
|
|
|
|
|
user.set('password', 'moon-y');
|
|
|
|
|
user.set('data', 'first data');
|
|
|
|
|
return user.signUp();
|
|
|
|
|
})
|
2016-05-22 09:59:36 -07:00
|
|
|
.then(user => {
|
2016-06-10 20:27:21 -07:00
|
|
|
session1 = user.getSessionToken();
|
|
|
|
|
return rp({
|
|
|
|
|
uri: 'http://localhost:8378/1/login?username=test&password=moon-y',
|
2016-05-22 09:59:36 -07:00
|
|
|
json: true,
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': 'test',
|
|
|
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
|
|
|
},
|
2016-06-10 20:27:21 -07:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.then(body => {
|
|
|
|
|
session2 = body.sessionToken;
|
|
|
|
|
|
|
|
|
|
//Ensure both session tokens are in the cache
|
|
|
|
|
return Parse.Cloud.run('checkStaleUser')
|
|
|
|
|
})
|
|
|
|
|
.then(() => rp({
|
|
|
|
|
method: 'POST',
|
|
|
|
|
uri: 'http://localhost:8378/1/functions/checkStaleUser',
|
|
|
|
|
json: true,
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': 'test',
|
|
|
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
|
|
|
'X-Parse-Session-Token': session2,
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
.then(() => Parse.Promise.all([cacheAdapter.get('test:user:' + session1), cacheAdapter.get('test:user:' + session2)]))
|
|
|
|
|
.then(cachedVals => {
|
|
|
|
|
expect(cachedVals[0].objectId).toEqual(user.id);
|
|
|
|
|
expect(cachedVals[1].objectId).toEqual(user.id);
|
|
|
|
|
|
|
|
|
|
//Change with session 1 and then read with session 2.
|
|
|
|
|
user.set('data', 'second data');
|
|
|
|
|
return user.save()
|
|
|
|
|
})
|
|
|
|
|
.then(() => rp({
|
|
|
|
|
method: 'POST',
|
|
|
|
|
uri: 'http://localhost:8378/1/functions/checkStaleUser',
|
|
|
|
|
json: true,
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': 'test',
|
|
|
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
|
|
|
'X-Parse-Session-Token': session2,
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
.then(body => {
|
|
|
|
|
expect(body.result).toEqual('second data');
|
|
|
|
|
done();
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
fail(JSON.stringify(error));
|
|
|
|
|
done();
|
2016-05-22 09:59:36 -07:00
|
|
|
});
|
|
|
|
|
});
|
2016-05-23 17:13:32 -07:00
|
|
|
|
|
|
|
|
it('trivial beforeSave should not affect fetched pointers (regression test for #1238)', done => {
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveUnchanged', (req, res) => {
|
|
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var TestObject = Parse.Object.extend("TestObject");
|
|
|
|
|
var NoBeforeSaveObject = Parse.Object.extend("NoBeforeSave");
|
|
|
|
|
var BeforeSaveObject = Parse.Object.extend("BeforeSaveUnchanged");
|
|
|
|
|
|
|
|
|
|
var aTestObject = new TestObject();
|
|
|
|
|
aTestObject.set("foo", "bar");
|
|
|
|
|
aTestObject.save()
|
|
|
|
|
.then(aTestObject => {
|
|
|
|
|
var aNoBeforeSaveObj = new NoBeforeSaveObject();
|
|
|
|
|
aNoBeforeSaveObj.set("aTestObject", aTestObject);
|
|
|
|
|
expect(aNoBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
return aNoBeforeSaveObj.save();
|
|
|
|
|
})
|
|
|
|
|
.then(aNoBeforeSaveObj => {
|
|
|
|
|
expect(aNoBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
|
|
|
|
|
var aBeforeSaveObj = new BeforeSaveObject();
|
|
|
|
|
aBeforeSaveObj.set("aTestObject", aTestObject);
|
|
|
|
|
expect(aBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
return aBeforeSaveObj.save();
|
|
|
|
|
})
|
|
|
|
|
.then(aBeforeSaveObj => {
|
|
|
|
|
expect(aBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-07-15 09:24:53 -04:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('beforeSave should not affect fetched pointers', done => {
|
2016-08-05 18:23:54 +05:30
|
|
|
Parse.Cloud.beforeSave('BeforeSaveUnchanged', (req, res) => {
|
|
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
|
|
|
|
req.object.set('foo', 'baz');
|
|
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var TestObject = Parse.Object.extend("TestObject");
|
|
|
|
|
var BeforeSaveUnchangedObject = Parse.Object.extend("BeforeSaveUnchanged");
|
|
|
|
|
var BeforeSaveChangedObject = Parse.Object.extend("BeforeSaveChanged");
|
|
|
|
|
|
|
|
|
|
var aTestObject = new TestObject();
|
|
|
|
|
aTestObject.set("foo", "bar");
|
|
|
|
|
aTestObject.save()
|
|
|
|
|
.then(aTestObject => {
|
|
|
|
|
var aBeforeSaveUnchangedObject = new BeforeSaveUnchangedObject();
|
|
|
|
|
aBeforeSaveUnchangedObject.set("aTestObject", aTestObject);
|
|
|
|
|
expect(aBeforeSaveUnchangedObject.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
return aBeforeSaveUnchangedObject.save();
|
|
|
|
|
})
|
|
|
|
|
.then(aBeforeSaveUnchangedObject => {
|
|
|
|
|
expect(aBeforeSaveUnchangedObject.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
|
|
|
|
|
var aBeforeSaveChangedObject = new BeforeSaveChangedObject();
|
|
|
|
|
aBeforeSaveChangedObject.set("aTestObject", aTestObject);
|
|
|
|
|
expect(aBeforeSaveChangedObject.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
return aBeforeSaveChangedObject.save();
|
|
|
|
|
})
|
|
|
|
|
.then(aBeforeSaveChangedObject => {
|
|
|
|
|
expect(aBeforeSaveChangedObject.get("aTestObject").get("foo")).toEqual("bar");
|
|
|
|
|
expect(aBeforeSaveChangedObject.get("foo")).toEqual("baz");
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-08-15 16:48:39 -04:00
|
|
|
it('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => {
|
2016-07-15 09:24:53 -04:00
|
|
|
var TestObject = Parse.Object.extend('TestObject');
|
|
|
|
|
var NoBeforeSaveObject = Parse.Object.extend('NoBeforeSave');
|
|
|
|
|
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
|
|
|
|
var object = req.object;
|
|
|
|
|
object.set('before', 'save');
|
|
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.define('removeme', (req, res) => {
|
|
|
|
|
var testObject = new TestObject();
|
|
|
|
|
testObject.save()
|
|
|
|
|
.then(testObject => {
|
|
|
|
|
var object = new NoBeforeSaveObject({remove: testObject});
|
|
|
|
|
return object.save();
|
|
|
|
|
})
|
|
|
|
|
.then(object => {
|
|
|
|
|
object.unset('remove');
|
|
|
|
|
return object.save();
|
|
|
|
|
})
|
|
|
|
|
.then(object => {
|
|
|
|
|
res.success(object);
|
2016-08-15 16:48:39 -04:00
|
|
|
}).catch(res.error);
|
2016-07-15 09:24:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.define('removeme2', (req, res) => {
|
|
|
|
|
var testObject = new TestObject();
|
|
|
|
|
testObject.save()
|
|
|
|
|
.then(testObject => {
|
|
|
|
|
var object = new BeforeSaveObject({remove: testObject});
|
|
|
|
|
return object.save();
|
|
|
|
|
})
|
|
|
|
|
.then(object => {
|
|
|
|
|
object.unset('remove');
|
|
|
|
|
return object.save();
|
|
|
|
|
})
|
|
|
|
|
.then(object => {
|
|
|
|
|
res.success(object);
|
2016-08-15 16:48:39 -04:00
|
|
|
}).catch(res.error);
|
2016-07-15 09:24:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.run('removeme')
|
|
|
|
|
.then(aNoBeforeSaveObj => {
|
|
|
|
|
expect(aNoBeforeSaveObj.get('remove')).toEqual(undefined);
|
|
|
|
|
|
|
|
|
|
return Parse.Cloud.run('removeme2');
|
|
|
|
|
})
|
|
|
|
|
.then(aBeforeSaveObj => {
|
|
|
|
|
expect(aBeforeSaveObj.get('before')).toEqual('save');
|
|
|
|
|
expect(aBeforeSaveObj.get('remove')).toEqual(undefined);
|
|
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}).catch((err) => {
|
2016-08-15 16:48:39 -04:00
|
|
|
jfail(err);
|
|
|
|
|
done();
|
2016-07-15 09:24:53 -04:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-09-09 14:41:03 -04:00
|
|
|
/*
|
|
|
|
|
TODO: fix for Postgres
|
|
|
|
|
trying to delete a field that doesn't exists doesn't play nice
|
|
|
|
|
*/
|
|
|
|
|
it_exclude_dbs(['postgres'])('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => {
|
2016-07-15 09:24:53 -04:00
|
|
|
var TestObject = Parse.Object.extend('TestObject');
|
|
|
|
|
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
|
|
|
|
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
|
|
|
|
var object = req.object;
|
|
|
|
|
object.set('before', 'save');
|
|
|
|
|
object.unset('remove');
|
|
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let object;
|
2016-12-07 15:17:05 -08:00
|
|
|
const testObject = new TestObject({key: 'value'});
|
2016-07-15 09:24:53 -04:00
|
|
|
testObject.save().then(() => {
|
2016-11-24 15:47:41 -05:00
|
|
|
object = new BeforeSaveObject();
|
|
|
|
|
return object.save().then(() => {
|
|
|
|
|
object.set({remove:testObject})
|
|
|
|
|
return object.save();
|
|
|
|
|
});
|
2016-07-15 09:24:53 -04:00
|
|
|
}).then((objectAgain) => {
|
2016-11-24 15:47:41 -05:00
|
|
|
expect(objectAgain.get('remove')).toBeUndefined();
|
|
|
|
|
expect(object.get('remove')).toBeUndefined();
|
|
|
|
|
done();
|
2016-07-15 09:24:53 -04:00
|
|
|
}).fail((err) => {
|
2016-08-15 16:48:39 -04:00
|
|
|
jfail(err);
|
2016-07-15 09:24:53 -04:00
|
|
|
done();
|
2016-08-15 16:48:39 -04:00
|
|
|
});
|
2016-07-15 09:24:53 -04:00
|
|
|
});
|
|
|
|
|
|
2016-08-15 16:48:39 -04:00
|
|
|
it('should not include relation op (regression test for #1606)', done => {
|
2016-07-15 09:24:53 -04:00
|
|
|
var TestObject = Parse.Object.extend('TestObject');
|
|
|
|
|
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
|
|
|
|
let testObj;
|
|
|
|
|
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
|
|
|
|
var object = req.object;
|
|
|
|
|
object.set('before', 'save');
|
|
|
|
|
testObj = new TestObject();
|
2016-11-24 15:47:41 -05:00
|
|
|
testObj.save().then(() => {
|
2016-07-15 09:24:53 -04:00
|
|
|
object.relation('testsRelation').add(testObj);
|
|
|
|
|
res.success();
|
2016-08-15 16:48:39 -04:00
|
|
|
}, res.error);
|
2016-07-15 09:24:53 -04:00
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const object = new BeforeSaveObject();
|
2016-07-15 09:24:53 -04:00
|
|
|
object.save().then((objectAgain) => {
|
|
|
|
|
// Originally it would throw as it would be a non-relation
|
|
|
|
|
expect(() => { objectAgain.relation('testsRelation') }).not.toThrow();
|
|
|
|
|
done();
|
|
|
|
|
}).fail((err) => {
|
2016-08-15 16:48:39 -04:00
|
|
|
jfail(err);
|
2016-07-15 09:24:53 -04:00
|
|
|
done();
|
|
|
|
|
})
|
|
|
|
|
});
|
2016-08-30 07:19:21 -04:00
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
describe('cloud jobs', () => {
|
|
|
|
|
it('should define a job', (done) => {
|
|
|
|
|
expect(() => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
}).not.toThrow();
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: 'http://localhost:8378/1/jobs/myJob',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-Master-Key': Parse.masterKey,
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
2016-08-30 07:19:21 -04:00
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should not run without master key', (done) => {
|
|
|
|
|
expect(() => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
res.success();
|
|
|
|
|
});
|
|
|
|
|
}).not.toThrow();
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: 'http://localhost:8378/1/jobs/myJob',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail('Expected to be unauthorized');
|
|
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(err.statusCode).toBe(403);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should run with master key', (done) => {
|
|
|
|
|
expect(() => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(req.functionName).toBeUndefined();
|
|
|
|
|
expect(req.jobName).toBe('myJob');
|
|
|
|
|
expect(typeof req.jobId).toBe('string');
|
|
|
|
|
expect(typeof res.success).toBe('function');
|
|
|
|
|
expect(typeof res.error).toBe('function');
|
|
|
|
|
expect(typeof res.message).toBe('function');
|
|
|
|
|
res.success();
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}).not.toThrow();
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: 'http://localhost:8378/1/jobs/myJob',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-Master-Key': Parse.masterKey,
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
|
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should run with master key basic auth', (done) => {
|
|
|
|
|
expect(() => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(req.functionName).toBeUndefined();
|
|
|
|
|
expect(req.jobName).toBe('myJob');
|
|
|
|
|
expect(typeof req.jobId).toBe('string');
|
|
|
|
|
expect(typeof res.success).toBe('function');
|
|
|
|
|
expect(typeof res.error).toBe('function');
|
|
|
|
|
expect(typeof res.message).toBe('function');
|
|
|
|
|
res.success();
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}).not.toThrow();
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: `http://${Parse.applicationId}:${Parse.masterKey}@localhost:8378/1/jobs/myJob`,
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
|
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should set the message / success on the job', (done) => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
res.message('hello');
|
2016-11-24 15:47:41 -05:00
|
|
|
res.message().then(() => {
|
2016-08-30 07:19:21 -04:00
|
|
|
return getJobStatus(req.jobId);
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then((jobStatus) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(jobStatus.get('message')).toEqual('hello');
|
|
|
|
|
expect(jobStatus.get('status')).toEqual('running');
|
2016-11-24 15:47:41 -05:00
|
|
|
return res.success().then(() => {
|
2016-08-30 07:19:21 -04:00
|
|
|
return getJobStatus(req.jobId);
|
|
|
|
|
});
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then((jobStatus) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(jobStatus.get('message')).toEqual('hello');
|
|
|
|
|
expect(jobStatus.get('status')).toEqual('succeeded');
|
|
|
|
|
done();
|
|
|
|
|
}).catch(err => {
|
|
|
|
|
console.error(err);
|
|
|
|
|
jfail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: 'http://localhost:8378/1/jobs/myJob',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-Master-Key': Parse.masterKey,
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
|
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should set the failure on the job', (done) => {
|
|
|
|
|
Parse.Cloud.job('myJob', (req, res) => {
|
|
|
|
|
res.error('Something went wrong').then(() => {
|
2016-08-30 07:19:21 -04:00
|
|
|
return getJobStatus(req.jobId);
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then((jobStatus) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
expect(jobStatus.get('message')).toEqual('Something went wrong');
|
|
|
|
|
expect(jobStatus.get('status')).toEqual('failed');
|
|
|
|
|
done();
|
|
|
|
|
}).catch(err => {
|
|
|
|
|
jfail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-12-01 07:04:47 -08:00
|
|
|
|
2016-08-30 07:19:21 -04:00
|
|
|
rp.post({
|
|
|
|
|
url: 'http://localhost:8378/1/jobs/myJob',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-Master-Key': Parse.masterKey,
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
|
|
|
|
}, (err) => {
|
2016-08-30 07:19:21 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function getJobStatus(jobId) {
|
2016-12-07 15:17:05 -08:00
|
|
|
const q = new Parse.Query('_JobStatus');
|
2016-08-30 07:19:21 -04:00
|
|
|
return q.get(jobId, {useMasterKey: true});
|
|
|
|
|
}
|
|
|
|
|
});
|
2016-05-19 13:38:16 -07:00
|
|
|
});
|
2016-09-17 16:52:35 -04:00
|
|
|
|
|
|
|
|
describe('beforeFind hooks', () => {
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should add beforeFind trigger', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', (req) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const q = req.query;
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(q instanceof Parse.Query).toBe(true);
|
2016-12-07 15:17:05 -08:00
|
|
|
const jsonQuery = q.toJSON();
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(jsonQuery.where.key).toEqual('value');
|
|
|
|
|
expect(jsonQuery.where.some).toEqual({'$gt': 10});
|
|
|
|
|
expect(jsonQuery.include).toEqual('otherKey,otherValue');
|
|
|
|
|
expect(jsonQuery.limit).toEqual(100);
|
|
|
|
|
expect(jsonQuery.skip).toBe(undefined);
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
query.equalTo('key', 'value');
|
|
|
|
|
query.greaterThan('some', 10);
|
|
|
|
|
query.include('otherKey');
|
|
|
|
|
query.include('otherValue');
|
2016-11-24 15:47:41 -05:00
|
|
|
query.find().then(() => {
|
2016-09-17 16:52:35 -04:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should use modify', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', (req) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const q = req.query;
|
2016-09-17 16:52:35 -04:00
|
|
|
q.equalTo('forced', true);
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj0 = new Parse.Object('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
obj0.set('forced', false);
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj1 = new Parse.Object('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
obj1.set('forced', true);
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Object.saveAll([obj0, obj1]).then(() => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
query.equalTo('forced', false);
|
2016-11-24 15:47:41 -05:00
|
|
|
query.find().then((results) => {
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(results.length).toBe(1);
|
2016-12-07 15:17:05 -08:00
|
|
|
const firstResult = results[0];
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(firstResult.get('forced')).toBe(true);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should use the modified the query', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', (req) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const q = req.query;
|
|
|
|
|
const otherQuery = new Parse.Query('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
otherQuery.equalTo('forced', true);
|
|
|
|
|
return Parse.Query.or(q, otherQuery);
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj0 = new Parse.Object('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
obj0.set('forced', false);
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj1 = new Parse.Object('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
obj1.set('forced', true);
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Object.saveAll([obj0, obj1]).then(() => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
query.equalTo('forced', false);
|
2016-11-24 15:47:41 -05:00
|
|
|
query.find().then((results) => {
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(results.length).toBe(2);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should reject queries', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', () => {
|
2016-09-17 16:52:35 -04:00
|
|
|
return Promise.reject('Do not run that query');
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-24 15:47:41 -05:00
|
|
|
query.find().then(() => {
|
2016-09-17 16:52:35 -04:00
|
|
|
fail('should not succeed');
|
|
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, (err) => {
|
2016-09-17 16:52:35 -04:00
|
|
|
expect(err.code).toBe(1);
|
|
|
|
|
expect(err.message).toEqual('Do not run that query');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-24 15:47:41 -05:00
|
|
|
it('should handle empty where', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', (req) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const otherQuery = new Parse.Query('MyObject');
|
2016-09-17 16:52:35 -04:00
|
|
|
otherQuery.equalTo('some', true);
|
|
|
|
|
return Parse.Query.or(req.query, otherQuery);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
rp.get({
|
|
|
|
|
url: 'http://localhost:8378/1/classes/MyObject',
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
|
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
|
|
|
},
|
2016-11-24 15:47:41 -05:00
|
|
|
}).then(() => {
|
2016-09-17 16:52:35 -04:00
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, (err) => {
|
2016-09-17 16:52:35 -04:00
|
|
|
fail(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-11-12 09:35:34 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('afterFind hooks', () => {
|
|
|
|
|
it('should add afterFind trigger using get',(done) => {
|
|
|
|
|
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
|
|
|
|
for(let i = 0 ; i < req.objects.length ; i++){
|
|
|
|
|
req.objects[i].set("secretField","###");
|
|
|
|
|
}
|
|
|
|
|
res.success(req.objects);
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj.set('secretField', 'SSID');
|
|
|
|
|
obj.save().then(function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
query.get(obj.id).then(function(result) {
|
|
|
|
|
expect(result.get('secretField')).toEqual('###');
|
|
|
|
|
done();
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should add afterFind trigger using find',(done) => {
|
|
|
|
|
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
|
|
|
|
for(let i = 0 ; i < req.objects.length ; i++){
|
|
|
|
|
req.objects[i].set("secretField","###");
|
|
|
|
|
}
|
|
|
|
|
res.success(req.objects);
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj.set('secretField', 'SSID');
|
|
|
|
|
obj.save().then(function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
query.equalTo('objectId',obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results[0].get('secretField')).toEqual('###');
|
|
|
|
|
done();
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should filter out results',(done) => {
|
|
|
|
|
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const filteredResults = [];
|
2016-11-12 09:35:34 -08:00
|
|
|
for(let i = 0 ; i < req.objects.length ; i++){
|
2017-01-11 12:31:40 -08:00
|
|
|
if(req.objects[i].get("secretField") === "SSID1") {
|
2016-11-12 09:35:34 -08:00
|
|
|
filteredResults.push(req.objects[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.success(filteredResults);
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj0 = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj0.set('secretField', 'SSID1');
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj1 = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj1.set('secretField', 'SSID2');
|
|
|
|
|
Parse.Object.saveAll([obj0, obj1]).then(function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results[0].get('secretField')).toEqual('SSID1');
|
|
|
|
|
expect(results.length).toEqual(1);
|
|
|
|
|
done();
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle failures',(done) => {
|
|
|
|
|
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
|
|
|
|
res.error(Parse.Error.SCRIPT_FAILED, "It should fail");
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj.set('secretField', 'SSID');
|
|
|
|
|
obj.save().then(function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
query.equalTo('objectId',obj.id);
|
2016-11-24 15:47:41 -05:00
|
|
|
query.find().then(function() {
|
2016-11-12 09:35:34 -08:00
|
|
|
fail("AfterFind should handle response failure correctly");
|
|
|
|
|
done();
|
2016-11-24 15:47:41 -05:00
|
|
|
}, function() {
|
2016-11-12 09:35:34 -08:00
|
|
|
done();
|
|
|
|
|
});
|
2016-11-24 15:47:41 -05:00
|
|
|
}, function() {
|
2016-11-12 09:35:34 -08:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should also work with promise',(done) => {
|
2016-11-24 15:47:41 -05:00
|
|
|
Parse.Cloud.afterFind('MyObject', (req) => {
|
2016-12-07 15:17:05 -08:00
|
|
|
const promise = new Parse.Promise();
|
2016-11-12 09:35:34 -08:00
|
|
|
setTimeout(function(){
|
|
|
|
|
for(let i = 0 ; i < req.objects.length ; i++){
|
|
|
|
|
req.objects[i].set("secretField","###");
|
|
|
|
|
}
|
|
|
|
|
promise.resolve(req.objects);
|
|
|
|
|
}, 1000);
|
|
|
|
|
return promise;
|
|
|
|
|
});
|
2016-12-07 15:17:05 -08:00
|
|
|
const obj = new Parse.Object('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
obj.set('secretField', 'SSID');
|
|
|
|
|
obj.save().then(function() {
|
2016-12-07 15:17:05 -08:00
|
|
|
const query = new Parse.Query('MyObject');
|
2016-11-12 09:35:34 -08:00
|
|
|
query.equalTo('objectId',obj.id);
|
|
|
|
|
query.find().then(function(results) {
|
|
|
|
|
expect(results[0].get('secretField')).toEqual('###');
|
|
|
|
|
done();
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
});
|
|
|
|
|
}, function(error) {
|
|
|
|
|
fail(error);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-01 07:04:47 -08:00
|
|
|
it('should alter select', (done) => {
|
|
|
|
|
Parse.Cloud.beforeFind('MyObject', (req) => {
|
|
|
|
|
req.query.select('white');
|
|
|
|
|
return req.query;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const obj0 = new Parse.Object('MyObject')
|
|
|
|
|
.set('white', true)
|
|
|
|
|
.set('black', true);
|
|
|
|
|
obj0.save()
|
|
|
|
|
.then(() => {
|
|
|
|
|
new Parse.Query('MyObject')
|
|
|
|
|
.first()
|
|
|
|
|
.then(result => {
|
|
|
|
|
expect(result.get('white')).toBe(true);
|
|
|
|
|
expect(result.get('black')).toBe(undefined);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-11-12 09:35:34 -08:00
|
|
|
|
2016-12-01 07:04:47 -08:00
|
|
|
it('should not alter select', (done) => {
|
|
|
|
|
const obj0 = new Parse.Object('MyObject')
|
|
|
|
|
.set('white', true)
|
|
|
|
|
.set('black', true);
|
|
|
|
|
obj0.save()
|
|
|
|
|
.then(() => {
|
|
|
|
|
new Parse.Query('MyObject')
|
|
|
|
|
.first()
|
|
|
|
|
.then(result => {
|
|
|
|
|
expect(result.get('white')).toBe(true);
|
|
|
|
|
expect(result.get('black')).toBe(true);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|