BVB Source Codes

parse-server Show ParseAPI.spec.js Source code

Return Download parse-server: download ParseAPI.spec.js Source code - Download parse-server Source code - Type:.js
  1. // A bunch of different tests are in here - it isn't very thematic.
  2. // It would probably be better to refactor them into different files.
  3. 'use strict';
  4.  
  5. var request = require('request');
  6. const rp = require('request-promise');
  7. const Parse = require("parse/node");
  8. const Config = require('../src/Config');
  9. const SchemaController = require('../src/Controllers/SchemaController');
  10. var TestUtils = require('../src/TestUtils');
  11.  
  12. const userSchema = SchemaController.convertSchemaToAdapterSchema({ className: '_User', fields: Object.assign({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._User) });
  13.  
  14. describe_only_db('mongo')('miscellaneous', () => {
  15.   it('test rest_create_app', function(done) {
  16.     var appId;
  17.     Parse._request('POST', 'rest_create_app').then((res) => {
  18.       expect(typeof res.application_id).toEqual('string');
  19.       expect(res.master_key).toEqual('master');
  20.       appId = res.application_id;
  21.       Parse.initialize(appId, 'unused');
  22.       var obj = new Parse.Object('TestObject');
  23.       obj.set('foo', 'bar');
  24.       return obj.save();
  25.     }).then(() => {
  26.       const config = new Config(appId);
  27.       return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
  28.     }).then((results) => {
  29.       expect(results.length).toEqual(1);
  30.       expect(results[0]['foo']).toEqual('bar');
  31.       done();
  32.     }).fail(error => {
  33.       fail(JSON.stringify(error));
  34.       done();
  35.     })
  36.   });
  37. })
  38.  
  39. describe('miscellaneous', function() {
  40.   it('create a GameScore object', function(done) {
  41.     var obj = new Parse.Object('GameScore');
  42.     obj.set('score', 1337);
  43.     obj.save().then(function(obj) {
  44.       expect(typeof obj.id).toBe('string');
  45.       expect(typeof obj.createdAt.toGMTString()).toBe('string');
  46.       done();
  47.     }, error => {
  48.       fail(JSON.stringify(error));
  49.       done();
  50.     });
  51.   });
  52.  
  53.   it('get a TestObject', function(done) {
  54.     create({ 'bloop' : 'blarg' }, function(obj) {
  55.       var t2 = new TestObject({ objectId: obj.id });
  56.       t2.fetch({
  57.         success: function(obj2) {
  58.           expect(obj2.get('bloop')).toEqual('blarg');
  59.           expect(obj2.id).toBeTruthy();
  60.           expect(obj2.id).toEqual(obj.id);
  61.           done();
  62.         },
  63.         error: error => {
  64.           fail(JSON.stringify(error));
  65.           done();
  66.         }
  67.       });
  68.     });
  69.   });
  70.  
  71.   it('create a valid parse user', function(done) {
  72.     createTestUser(function(data) {
  73.       expect(data.id).not.toBeUndefined();
  74.       expect(data.getSessionToken()).not.toBeUndefined();
  75.       expect(data.get('password')).toBeUndefined();
  76.       done();
  77.     }, error => {
  78.       fail(JSON.stringify(error));
  79.       done();
  80.     });
  81.   });
  82.  
  83.   it('fail to create a duplicate username', done => {
  84.     let numCreated = 0;
  85.     let numFailed = 0;
  86.     const p1 = createTestUser();
  87.     p1.then(() => {
  88.       numCreated++;
  89.       expect(numCreated).toEqual(1);
  90.     })
  91.     .catch(error => {
  92.       numFailed++;
  93.       expect(numFailed).toEqual(1);
  94.       expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
  95.     });
  96.     const p2 = createTestUser();
  97.     p2.then(() => {
  98.       numCreated++;
  99.       expect(numCreated).toEqual(1);
  100.     })
  101.     .catch(error => {
  102.       numFailed++;
  103.       expect(numFailed).toEqual(1);
  104.       expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
  105.     });
  106.     Parse.Promise.when([p1, p2])
  107.     .then(() => {
  108.       fail('one of the users should not have been created');
  109.       done();
  110.     })
  111.     .catch(done);
  112.   });
  113.  
  114.   it('ensure that email is uniquely indexed', done => {
  115.     let numFailed = 0;
  116.     let numCreated = 0;
  117.     const user1 = new Parse.User();
  118.     user1.setPassword('asdf');
  119.     user1.setUsername('u1');
  120.     user1.setEmail('dupe@dupe.dupe');
  121.     const p1 = user1.signUp();
  122.     p1.then(() => {
  123.       numCreated++;
  124.       expect(numCreated).toEqual(1);
  125.     }, error => {
  126.       numFailed++;
  127.       expect(numFailed).toEqual(1);
  128.       expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
  129.     });
  130.  
  131.     const user2 = new Parse.User();
  132.     user2.setPassword('asdf');
  133.     user2.setUsername('u2');
  134.     user2.setEmail('dupe@dupe.dupe');
  135.     const p2 = user2.signUp();
  136.     p2.then(() => {
  137.       numCreated++;
  138.       expect(numCreated).toEqual(1);
  139.     }, error => {
  140.       numFailed++;
  141.       expect(numFailed).toEqual(1);
  142.       expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
  143.     });
  144.  
  145.     Parse.Promise.when([p1, p2])
  146.     .then(() => {
  147.       fail('one of the users should not have been created');
  148.       done();
  149.     })
  150.     .catch(done);
  151.   });
  152.  
  153.   it('ensure that if people already have duplicate users, they can still sign up new users', done => {
  154.     const config = new Config('test');
  155.     // Remove existing data to clear out unique index
  156.     TestUtils.destroyAllDataPermanently()
  157.     .then(() => config.database.adapter.createClass('_User', userSchema))
  158.     .then(() => config.database.adapter.createObject('_User', userSchema, { objectId: 'x', username: 'u' }).catch(fail))
  159.     .then(() => config.database.adapter.createObject('_User', userSchema, { objectId: 'y', username: 'u' }).catch(fail))
  160.     // Create a new server to try to recreate the unique indexes
  161.     .then(reconfigureServer)
  162.     .catch(error => {
  163.       expect(error.code).toEqual(Parse.Error.DUPLICATE_VALUE);
  164.       const user = new Parse.User();
  165.       user.setPassword('asdf');
  166.       user.setUsername('zxcv');
  167.       return user.signUp().catch(fail);
  168.     })
  169.     .then(() => {
  170.       const user = new Parse.User();
  171.       user.setPassword('asdf');
  172.       user.setUsername('u');
  173.       return user.signUp()
  174.     })
  175.     .then(() => {
  176.       fail('should not have been able to sign up');
  177.       done();
  178.     })
  179.     .catch(error => {
  180.       expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
  181.       done();
  182.     })
  183.   });
  184.  
  185.   it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
  186.     const config = new Config('test');
  187.     // Remove existing data to clear out unique index
  188.     TestUtils.destroyAllDataPermanently()
  189.     .then(() => config.database.adapter.createClass('_User', userSchema))
  190.     .then(() => config.database.adapter.createObject('_User', userSchema, { objectId: 'x', email: 'a@b.c' }))
  191.     .then(() => config.database.adapter.createObject('_User', userSchema, { objectId: 'y', email: 'a@b.c' }))
  192.     .then(reconfigureServer)
  193.     .catch(() => {
  194.       const user = new Parse.User();
  195.       user.setPassword('asdf');
  196.       user.setUsername('qqq');
  197.       user.setEmail('unique@unique.unique');
  198.       return user.signUp().catch(fail);
  199.     })
  200.     .then(() => {
  201.       const user = new Parse.User();
  202.       user.setPassword('asdf');
  203.       user.setUsername('www');
  204.       user.setEmail('a@b.c');
  205.       return user.signUp()
  206.     })
  207.     .catch(error => {
  208.       expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
  209.       done();
  210.     });
  211.   });
  212.  
  213.   it('ensure that if you try to sign up a user with a unique username and email, but duplicates in some other field that has a uniqueness constraint, you get a regular duplicate value error', done => {
  214.     const config = new Config('test');
  215.     config.database.adapter.addFieldIfNotExists('_User', 'randomField', { type: 'String' })
  216.     .then(() => config.database.adapter.ensureUniqueness('_User', userSchema, ['randomField']))
  217.     .then(() => {
  218.       const user = new Parse.User();
  219.       user.setPassword('asdf');
  220.       user.setUsername('1');
  221.       user.setEmail('1@b.c');
  222.       user.set('randomField', 'a');
  223.       return user.signUp()
  224.     })
  225.     .then(() => {
  226.       const user = new Parse.User();
  227.       user.setPassword('asdf');
  228.       user.setUsername('2');
  229.       user.setEmail('2@b.c');
  230.       user.set('randomField', 'a');
  231.       return user.signUp()
  232.     })
  233.     .catch(error => {
  234.       expect(error.code).toEqual(Parse.Error.DUPLICATE_VALUE);
  235.       done();
  236.     });
  237.   });
  238.  
  239.   it('succeed in logging in', function(done) {
  240.     createTestUser(function(u) {
  241.       expect(typeof u.id).toEqual('string');
  242.  
  243.       Parse.User.logIn('test', 'moon-y', {
  244.         success: function(user) {
  245.           expect(typeof user.id).toEqual('string');
  246.           expect(user.get('password')).toBeUndefined();
  247.           expect(user.getSessionToken()).not.toBeUndefined();
  248.           Parse.User.logOut().then(done);
  249.         }, error: error => {
  250.           fail(JSON.stringify(error));
  251.           done();
  252.         }
  253.       });
  254.     }, fail);
  255.   });
  256.  
  257.   it('increment with a user object', function(done) {
  258.     createTestUser().then((user) => {
  259.       user.increment('foo');
  260.       return user.save();
  261.     }).then(() => {
  262.       return Parse.User.logIn('test', 'moon-y');
  263.     }).then((user) => {
  264.       expect(user.get('foo')).toEqual(1);
  265.       user.increment('foo');
  266.       return user.save();
  267.     }).then(() => Parse.User.logOut())
  268.     .then(() => Parse.User.logIn('test', 'moon-y'))
  269.     .then((user) => {
  270.       expect(user.get('foo')).toEqual(2);
  271.       Parse.User.logOut()
  272.       .then(done);
  273.     }, (error) => {
  274.       fail(JSON.stringify(error));
  275.       done();
  276.     });
  277.   });
  278.  
  279.   it('save various data types', function(done) {
  280.     var obj = new TestObject();
  281.     obj.set('date', new Date());
  282.     obj.set('array', [1, 2, 3]);
  283.     obj.set('object', {one: 1, two: 2});
  284.     obj.save().then(() => {
  285.       var obj2 = new TestObject({objectId: obj.id});
  286.       return obj2.fetch();
  287.     }).then((obj2) => {
  288.       expect(obj2.get('date') instanceof Date).toBe(true);
  289.       expect(obj2.get('array') instanceof Array).toBe(true);
  290.       expect(obj2.get('object') instanceof Array).toBe(false);
  291.       expect(obj2.get('object') instanceof Object).toBe(true);
  292.       done();
  293.     });
  294.   });
  295.  
  296.   it('query with limit', function(done) {
  297.     var baz = new TestObject({ foo: 'baz' });
  298.     var qux = new TestObject({ foo: 'qux' });
  299.     baz.save().then(() => {
  300.       return qux.save();
  301.     }).then(() => {
  302.       var query = new Parse.Query(TestObject);
  303.       query.limit(1);
  304.       return query.find();
  305.     }).then((results) => {
  306.       expect(results.length).toEqual(1);
  307.       done();
  308.     }, (error) => {
  309.       fail(JSON.stringify(error));
  310.       done();
  311.     });
  312.   });
  313.  
  314.   it('query without limit get default 100 records', function(done) {
  315.     var objects = [];
  316.     for (var i = 0; i < 150; i++) {
  317.       objects.push(new TestObject({name: 'name' + i}));
  318.     }
  319.     Parse.Object.saveAll(objects).then(() => {
  320.       return new Parse.Query(TestObject).find();
  321.     }).then((results) => {
  322.       expect(results.length).toEqual(100);
  323.       done();
  324.     }, error => {
  325.       fail(JSON.stringify(error));
  326.       done();
  327.     });
  328.   });
  329.  
  330.   it('basic saveAll', function(done) {
  331.     var alpha = new TestObject({ letter: 'alpha' });
  332.     var beta = new TestObject({ letter: 'beta' });
  333.     Parse.Object.saveAll([alpha, beta]).then(() => {
  334.       expect(alpha.id).toBeTruthy();
  335.       expect(beta.id).toBeTruthy();
  336.       return new Parse.Query(TestObject).find();
  337.     }).then((results) => {
  338.       expect(results.length).toEqual(2);
  339.       done();
  340.     }, (error) => {
  341.       fail(error);
  342.       done();
  343.     });
  344.   });
  345.  
  346.   it('test beforeSave set object acl success', function(done) {
  347.     var acl = new Parse.ACL({
  348.       '*': { read: true, write: false }
  349.     });
  350.     Parse.Cloud.beforeSave('BeforeSaveAddACL', function(req, res) {
  351.       req.object.setACL(acl);
  352.       res.success();
  353.     });
  354.  
  355.     var obj = new Parse.Object('BeforeSaveAddACL');
  356.     obj.set('lol', true);
  357.     obj.save().then(function() {
  358.       var query = new Parse.Query('BeforeSaveAddACL');
  359.       query.get(obj.id).then(function(objAgain) {
  360.         expect(objAgain.get('lol')).toBeTruthy();
  361.         expect(objAgain.getACL().equals(acl));
  362.         done();
  363.       }, function(error) {
  364.         fail(error);
  365.         done();
  366.       });
  367.     }, error => {
  368.       fail(JSON.stringify(error));
  369.       done();
  370.     });
  371.   });
  372.  
  373.   it('object is set on create and update', done => {
  374.     let triggerTime = 0;
  375.     // Register a mock beforeSave hook
  376.     Parse.Cloud.beforeSave('GameScore', (req, res) => {
  377.       const object = req.object;
  378.       expect(object instanceof Parse.Object).toBeTruthy();
  379.       expect(object.get('fooAgain')).toEqual('barAgain');
  380.       if (triggerTime == 0) {
  381.         // Create
  382.         expect(object.get('foo')).toEqual('bar');
  383.         // No objectId/createdAt/updatedAt
  384.         expect(object.id).toBeUndefined();
  385.         expect(object.createdAt).toBeUndefined();
  386.         expect(object.updatedAt).toBeUndefined();
  387.       } else if (triggerTime == 1) {
  388.         // Update
  389.         expect(object.get('foo')).toEqual('baz');
  390.         expect(object.id).not.toBeUndefined();
  391.         expect(object.createdAt).not.toBeUndefined();
  392.         expect(object.updatedAt).not.toBeUndefined();
  393.       } else {
  394.         res.error();
  395.       }
  396.       triggerTime++;
  397.       res.success();
  398.     });
  399.  
  400.     const obj = new Parse.Object('GameScore');
  401.     obj.set('foo', 'bar');
  402.     obj.set('fooAgain', 'barAgain');
  403.     obj.save().then(() => {
  404.       // We only update foo
  405.       obj.set('foo', 'baz');
  406.       return obj.save();
  407.     }).then(() => {
  408.       // Make sure the checking has been triggered
  409.       expect(triggerTime).toBe(2);
  410.       done();
  411.     }, error => {
  412.       fail(error);
  413.       done();
  414.     });
  415.   });
  416.   it('works when object is passed to success', done => {
  417.     let triggerTime = 0;
  418.     // Register a mock beforeSave hook
  419.     Parse.Cloud.beforeSave('GameScore', (req, res) => {
  420.       const object = req.object;
  421.       object.set('foo', 'bar');
  422.       triggerTime++;
  423.       res.success(object);
  424.     });
  425.  
  426.     const obj = new Parse.Object('GameScore');
  427.     obj.set('foo', 'baz');
  428.     obj.save().then(() => {
  429.       expect(triggerTime).toBe(1);
  430.       expect(obj.get('foo')).toEqual('bar');
  431.       done();
  432.     }, error => {
  433.       fail(error);
  434.       done();
  435.     });
  436.   });
  437.  
  438.   it('original object is set on update', done => {
  439.     let triggerTime = 0;
  440.     // Register a mock beforeSave hook
  441.     Parse.Cloud.beforeSave('GameScore', (req, res) => {
  442.       const object = req.object;
  443.       expect(object instanceof Parse.Object).toBeTruthy();
  444.       expect(object.get('fooAgain')).toEqual('barAgain');
  445.       const originalObject = req.original;
  446.       if (triggerTime == 0) {
  447.         // No id/createdAt/updatedAt
  448.         expect(object.id).toBeUndefined();
  449.         expect(object.createdAt).toBeUndefined();
  450.         expect(object.updatedAt).toBeUndefined();
  451.         // Create
  452.         expect(object.get('foo')).toEqual('bar');
  453.         // Check the originalObject is undefined
  454.         expect(originalObject).toBeUndefined();
  455.       } else if (triggerTime == 1) {
  456.         // Update
  457.         expect(object.id).not.toBeUndefined();
  458.         expect(object.createdAt).not.toBeUndefined();
  459.         expect(object.updatedAt).not.toBeUndefined();
  460.         expect(object.get('foo')).toEqual('baz');
  461.         // Check the originalObject
  462.         expect(originalObject instanceof Parse.Object).toBeTruthy();
  463.         expect(originalObject.get('fooAgain')).toEqual('barAgain');
  464.         expect(originalObject.id).not.toBeUndefined();
  465.         expect(originalObject.createdAt).not.toBeUndefined();
  466.         expect(originalObject.updatedAt).not.toBeUndefined();
  467.         expect(originalObject.get('foo')).toEqual('bar');
  468.       } else {
  469.         res.error();
  470.       }
  471.       triggerTime++;
  472.       res.success();
  473.     });
  474.  
  475.     const obj = new Parse.Object('GameScore');
  476.     obj.set('foo', 'bar');
  477.     obj.set('fooAgain', 'barAgain');
  478.     obj.save().then(() => {
  479.       // We only update foo
  480.       obj.set('foo', 'baz');
  481.       return obj.save();
  482.     }).then(() => {
  483.       // Make sure the checking has been triggered
  484.       expect(triggerTime).toBe(2);
  485.       done();
  486.     }, error => {
  487.       fail(error);
  488.       done();
  489.     });
  490.   });
  491.  
  492.   it('pointer mutation properly saves object', done => {
  493.     const className = 'GameScore';
  494.  
  495.     Parse.Cloud.beforeSave(className, (req, res) => {
  496.       const object = req.object;
  497.       expect(object instanceof Parse.Object).toBeTruthy();
  498.  
  499.       const child = object.get('child');
  500.       expect(child instanceof Parse.Object).toBeTruthy();
  501.       child.set('a', 'b');
  502.       child.save().then(() => {
  503.         res.success();
  504.       });
  505.     });
  506.  
  507.     const obj = new Parse.Object(className);
  508.     obj.set('foo', 'bar');
  509.  
  510.     const child = new Parse.Object('Child');
  511.     child.save().then(() => {
  512.       obj.set('child', child);
  513.       return obj.save();
  514.     }).then(() => {
  515.       const query = new Parse.Query(className);
  516.       query.include('child');
  517.       return query.get(obj.id).then(objAgain => {
  518.         expect(objAgain.get('foo')).toEqual('bar');
  519.  
  520.         const childAgain = objAgain.get('child');
  521.         expect(childAgain instanceof Parse.Object).toBeTruthy();
  522.         expect(childAgain.get('a')).toEqual('b');
  523.  
  524.         return Promise.resolve();
  525.       });
  526.     }).then(() => {
  527.       done();
  528.     }, error => {
  529.       fail(error);
  530.       done();
  531.     });
  532.   });
  533.  
  534.   it('pointer reassign is working properly (#1288)', (done) => {
  535.     Parse.Cloud.beforeSave('GameScore', (req, res) => {
  536.  
  537.       var obj = req.object;
  538.       if (obj.get('point')) {
  539.         return res.success();
  540.       }
  541.       var TestObject1 = Parse.Object.extend('TestObject1');
  542.       var newObj = new TestObject1({'key1': 1});
  543.  
  544.       return newObj.save().then((newObj) => {
  545.         obj.set('point' , newObj);
  546.         res.success();
  547.       });
  548.     });
  549.     var pointId;
  550.     var obj = new Parse.Object('GameScore');
  551.     obj.set('foo', 'bar');
  552.     obj.save().then(() => {
  553.       expect(obj.get('point')).not.toBeUndefined();
  554.       pointId = obj.get('point').id;
  555.       expect(pointId).not.toBeUndefined();
  556.       obj.set('foo', 'baz');
  557.       return obj.save();
  558.     }).then((obj) => {
  559.       expect(obj.get('point').id).toEqual(pointId);
  560.       done();
  561.     })
  562.   });
  563.  
  564.   it('test afterSave get full object on create and update', function(done) {
  565.     var triggerTime = 0;
  566.     // Register a mock beforeSave hook
  567.     Parse.Cloud.afterSave('GameScore', function(req, res) {
  568.       var object = req.object;
  569.       expect(object instanceof Parse.Object).toBeTruthy();
  570.       expect(object.id).not.toBeUndefined();
  571.       expect(object.createdAt).not.toBeUndefined();
  572.       expect(object.updatedAt).not.toBeUndefined();
  573.       expect(object.get('fooAgain')).toEqual('barAgain');
  574.       if (triggerTime == 0) {
  575.         // Create
  576.         expect(object.get('foo')).toEqual('bar');
  577.       } else if (triggerTime == 1) {
  578.         // Update
  579.         expect(object.get('foo')).toEqual('baz');
  580.       } else {
  581.         res.error();
  582.       }
  583.       triggerTime++;
  584.       res.success();
  585.     });
  586.  
  587.     var obj = new Parse.Object('GameScore');
  588.     obj.set('foo', 'bar');
  589.     obj.set('fooAgain', 'barAgain');
  590.     obj.save().then(function() {
  591.       // We only update foo
  592.       obj.set('foo', 'baz');
  593.       return obj.save();
  594.     }).then(function() {
  595.       // Make sure the checking has been triggered
  596.       expect(triggerTime).toBe(2);
  597.       done();
  598.     }, function(error) {
  599.       fail(error);
  600.       done();
  601.     });
  602.   });
  603.  
  604.   it('test afterSave get original object on update', function(done) {
  605.     var triggerTime = 0;
  606.     // Register a mock beforeSave hook
  607.  
  608.     Parse.Cloud.afterSave('GameScore', function(req, res) {
  609.       var object = req.object;
  610.       expect(object instanceof Parse.Object).toBeTruthy();
  611.       expect(object.get('fooAgain')).toEqual('barAgain');
  612.       expect(object.id).not.toBeUndefined();
  613.       expect(object.createdAt).not.toBeUndefined();
  614.       expect(object.updatedAt).not.toBeUndefined();
  615.       var originalObject = req.original;
  616.       if (triggerTime == 0) {
  617.         // Create
  618.         expect(object.get('foo')).toEqual('bar');
  619.         // Check the originalObject is undefined
  620.         expect(originalObject).toBeUndefined();
  621.       } else if (triggerTime == 1) {
  622.         // Update
  623.         expect(object.get('foo')).toEqual('baz');
  624.         // Check the originalObject
  625.         expect(originalObject instanceof Parse.Object).toBeTruthy();
  626.         expect(originalObject.get('fooAgain')).toEqual('barAgain');
  627.         expect(originalObject.id).not.toBeUndefined();
  628.         expect(originalObject.createdAt).not.toBeUndefined();
  629.         expect(originalObject.updatedAt).not.toBeUndefined();
  630.         expect(originalObject.get('foo')).toEqual('bar');
  631.       } else {
  632.         res.error();
  633.       }
  634.       triggerTime++;
  635.       res.success();
  636.     });
  637.  
  638.     var obj = new Parse.Object('GameScore');
  639.     obj.set('foo', 'bar');
  640.     obj.set('fooAgain', 'barAgain');
  641.     obj.save().then(function() {
  642.       // We only update foo
  643.       obj.set('foo', 'baz');
  644.       return obj.save();
  645.     }).then(function() {
  646.       // Make sure the checking has been triggered
  647.       expect(triggerTime).toBe(2);
  648.       done();
  649.     }, function(error) {
  650.       jfail(error);
  651.       done();
  652.     });
  653.   });
  654.  
  655.   it('test afterSave get full original object even req auth can not query it', (done) => {
  656.     var triggerTime = 0;
  657.     // Register a mock beforeSave hook
  658.     Parse.Cloud.afterSave('GameScore', function(req, res) {
  659.       var object = req.object;
  660.       var originalObject = req.original;
  661.       if (triggerTime == 0) {
  662.         // Create
  663.       } else if (triggerTime == 1) {
  664.         // Update
  665.         expect(object.get('foo')).toEqual('baz');
  666.         // Make sure we get the full originalObject
  667.         expect(originalObject instanceof Parse.Object).toBeTruthy();
  668.         expect(originalObject.get('fooAgain')).toEqual('barAgain');
  669.         expect(originalObject.id).not.toBeUndefined();
  670.         expect(originalObject.createdAt).not.toBeUndefined();
  671.         expect(originalObject.updatedAt).not.toBeUndefined();
  672.         expect(originalObject.get('foo')).toEqual('bar');
  673.       } else {
  674.         res.error();
  675.       }
  676.       triggerTime++;
  677.       res.success();
  678.     });
  679.  
  680.     var obj = new Parse.Object('GameScore');
  681.     obj.set('foo', 'bar');
  682.     obj.set('fooAgain', 'barAgain');
  683.     var acl = new Parse.ACL();
  684.     // Make sure our update request can not query the object
  685.     acl.setPublicReadAccess(false);
  686.     acl.setPublicWriteAccess(true);
  687.     obj.setACL(acl);
  688.     obj.save().then(function() {
  689.       // We only update foo
  690.       obj.set('foo', 'baz');
  691.       return obj.save();
  692.     }).then(function() {
  693.       // Make sure the checking has been triggered
  694.       expect(triggerTime).toBe(2);
  695.       done();
  696.     }, function(error) {
  697.       jfail(error);
  698.       done();
  699.     });
  700.   });
  701.  
  702.   it('afterSave flattens custom operations', done => {
  703.     var triggerTime = 0;
  704.     // Register a mock beforeSave hook
  705.     Parse.Cloud.afterSave('GameScore', function(req, res) {
  706.       const object = req.object;
  707.       expect(object instanceof Parse.Object).toBeTruthy();
  708.       const originalObject = req.original;
  709.       if (triggerTime == 0) {
  710.         // Create
  711.         expect(object.get('yolo')).toEqual(1);
  712.       } else if (triggerTime == 1) {
  713.         // Update
  714.         expect(object.get('yolo')).toEqual(2);
  715.         // Check the originalObject
  716.         expect(originalObject.get('yolo')).toEqual(1);
  717.       } else {
  718.         res.error();
  719.       }
  720.       triggerTime++;
  721.       res.success();
  722.     });
  723.  
  724.     var obj = new Parse.Object('GameScore');
  725.     obj.increment('yolo', 1);
  726.     obj.save().then(() => {
  727.       obj.increment('yolo', 1);
  728.       return obj.save();
  729.     }).then(() => {
  730.       // Make sure the checking has been triggered
  731.       expect(triggerTime).toBe(2);
  732.       done();
  733.     }, error => {
  734.       jfail(error);
  735.       done();
  736.     });
  737.   });
  738.  
  739.   it('beforeSave receives ACL', done => {
  740.     let triggerTime = 0;
  741.     // Register a mock beforeSave hook
  742.     Parse.Cloud.beforeSave('GameScore', function(req, res) {
  743.       const object = req.object;
  744.       if (triggerTime == 0) {
  745.         const acl = object.getACL();
  746.         expect(acl.getPublicReadAccess()).toBeTruthy();
  747.         expect(acl.getPublicWriteAccess()).toBeTruthy();
  748.       } else if (triggerTime == 1) {
  749.         const acl = object.getACL();
  750.         expect(acl.getPublicReadAccess()).toBeFalsy();
  751.         expect(acl.getPublicWriteAccess()).toBeTruthy();
  752.       } else {
  753.         res.error();
  754.       }
  755.       triggerTime++;
  756.       res.success();
  757.     });
  758.  
  759.     const obj = new Parse.Object('GameScore');
  760.     const acl = new Parse.ACL();
  761.     acl.setPublicReadAccess(true);
  762.     acl.setPublicWriteAccess(true);
  763.     obj.setACL(acl);
  764.     obj.save().then(() => {
  765.       acl.setPublicReadAccess(false);
  766.       obj.setACL(acl);
  767.       return obj.save();
  768.     }).then(() => {
  769.       // Make sure the checking has been triggered
  770.       expect(triggerTime).toBe(2);
  771.       done();
  772.     }, error => {
  773.       jfail(error);
  774.       done();
  775.     });
  776.   });
  777.  
  778.   it('afterSave receives ACL', done => {
  779.     let triggerTime = 0;
  780.     // Register a mock beforeSave hook
  781.     Parse.Cloud.afterSave('GameScore', function(req, res) {
  782.       const object = req.object;
  783.       if (triggerTime == 0) {
  784.         const acl = object.getACL();
  785.         expect(acl.getPublicReadAccess()).toBeTruthy();
  786.         expect(acl.getPublicWriteAccess()).toBeTruthy();
  787.       } else if (triggerTime == 1) {
  788.         const acl = object.getACL();
  789.         expect(acl.getPublicReadAccess()).toBeFalsy();
  790.         expect(acl.getPublicWriteAccess()).toBeTruthy();
  791.       } else {
  792.         res.error();
  793.       }
  794.       triggerTime++;
  795.       res.success();
  796.     });
  797.  
  798.     const obj = new Parse.Object('GameScore');
  799.     const acl = new Parse.ACL();
  800.     acl.setPublicReadAccess(true);
  801.     acl.setPublicWriteAccess(true);
  802.     obj.setACL(acl);
  803.     obj.save().then(() => {
  804.       acl.setPublicReadAccess(false);
  805.       obj.setACL(acl);
  806.       return obj.save();
  807.     }).then(() => {
  808.       // Make sure the checking has been triggered
  809.       expect(triggerTime).toBe(2);
  810.       done();
  811.     }, error => {
  812.       jfail(error);
  813.       done();
  814.     });
  815.   });
  816.  
  817.   it('should return the updated fields on PUT', done => {
  818.     const obj = new Parse.Object('GameScore');
  819.     obj.save({a:'hello', c: 1, d: ['1'], e:['1'], f:['1','2']}).then(() => {
  820.       var headers = {
  821.         'Content-Type': 'application/json',
  822.         'X-Parse-Application-Id': 'test',
  823.         'X-Parse-REST-API-Key': 'rest',
  824.         'X-Parse-Installation-Id': 'yolo'
  825.       };
  826.       request.put({
  827.         headers: headers,
  828.         url: 'http://localhost:8378/1/classes/GameScore/' + obj.id,
  829.         body: JSON.stringify({
  830.           a: 'b',
  831.           c: {"__op":"Increment","amount":2},
  832.           d: {"__op":"Add", objects: ['2']},
  833.           e: {"__op":"AddUnique", objects: ['1', '2']},
  834.           f: {"__op":"Remove", objects: ['2']},
  835.           selfThing: {"__type":"Pointer","className":"GameScore","objectId":obj.id},
  836.         })
  837.       }, (error, response, body) => {
  838.         try {
  839.           body = JSON.parse(body);
  840.           expect(body.a).toBeUndefined();
  841.           expect(body.c).toEqual(3); // 2+1
  842.           expect(body.d.length).toBe(2);
  843.           expect(body.d.indexOf('1') > -1).toBe(true);
  844.           expect(body.d.indexOf('2') > -1).toBe(true);
  845.           expect(body.e.length).toBe(2);
  846.           expect(body.e.indexOf('1') > -1).toBe(true);
  847.           expect(body.e.indexOf('2') > -1).toBe(true);
  848.           expect(body.f.length).toBe(1);
  849.           expect(body.f.indexOf('1') > -1).toBe(true);
  850.           // return nothing on other self
  851.           expect(body.selfThing).toBeUndefined();
  852.           // updatedAt is always set
  853.           expect(body.updatedAt).not.toBeUndefined();
  854.         }catch(e) {
  855.           jfail(e);
  856.         }
  857.         done();
  858.       });
  859.     }).fail(() => {
  860.       fail('Should not fail');
  861.       done();
  862.     })
  863.   })
  864.  
  865.   it('test cloud function error handling', (done) => {
  866.     // Register a function which will fail
  867.     Parse.Cloud.define('willFail', (req, res) => {
  868.       res.error('noway');
  869.     });
  870.     Parse.Cloud.run('willFail').then(() => {
  871.       fail('Should not have succeeded.');
  872.       done();
  873.     }, (e) => {
  874.       expect(e.code).toEqual(141);
  875.       expect(e.message).toEqual('noway');
  876.       done();
  877.     });
  878.   });
  879.  
  880.   it('test cloud function error handling with custom error code', (done) => {
  881.     // Register a function which will fail
  882.     Parse.Cloud.define('willFail', (req, res) => {
  883.       res.error(999, 'noway');
  884.     });
  885.     Parse.Cloud.run('willFail').then(() => {
  886.       fail('Should not have succeeded.');
  887.       done();
  888.     }, (e) => {
  889.       expect(e.code).toEqual(999);
  890.       expect(e.message).toEqual('noway');
  891.       done();
  892.     });
  893.   });
  894.  
  895.   it('test cloud function error handling with standard error code', (done) => {
  896.     // Register a function which will fail
  897.     Parse.Cloud.define('willFail', (req, res) => {
  898.       res.error('noway');
  899.     });
  900.     Parse.Cloud.run('willFail').then(() => {
  901.       fail('Should not have succeeded.');
  902.       done();
  903.     }, (e) => {
  904.       expect(e.code).toEqual(Parse.Error.SCRIPT_FAILED);
  905.       expect(e.message).toEqual('noway');
  906.       done();
  907.     });
  908.   });
  909.  
  910.   it('test beforeSave/afterSave get installationId', function(done) {
  911.     let triggerTime = 0;
  912.     Parse.Cloud.beforeSave('GameScore', function(req, res) {
  913.       triggerTime++;
  914.       expect(triggerTime).toEqual(1);
  915.       expect(req.installationId).toEqual('yolo');
  916.       res.success();
  917.     });
  918.     Parse.Cloud.afterSave('GameScore', function(req) {
  919.       triggerTime++;
  920.       expect(triggerTime).toEqual(2);
  921.       expect(req.installationId).toEqual('yolo');
  922.     });
  923.  
  924.     var headers = {
  925.       'Content-Type': 'application/json',
  926.       'X-Parse-Application-Id': 'test',
  927.       'X-Parse-REST-API-Key': 'rest',
  928.       'X-Parse-Installation-Id': 'yolo'
  929.     };
  930.     request.post({
  931.       headers: headers,
  932.       url: 'http://localhost:8378/1/classes/GameScore',
  933.       body: JSON.stringify({ a: 'b' })
  934.     }, (error) => {
  935.       expect(error).toBe(null);
  936.       expect(triggerTime).toEqual(2);
  937.       done();
  938.     });
  939.   });
  940.  
  941.   it('test beforeDelete/afterDelete get installationId', function(done) {
  942.     let triggerTime = 0;
  943.     Parse.Cloud.beforeDelete('GameScore', function(req, res) {
  944.       triggerTime++;
  945.       expect(triggerTime).toEqual(1);
  946.       expect(req.installationId).toEqual('yolo');
  947.       res.success();
  948.     });
  949.     Parse.Cloud.afterDelete('GameScore', function(req) {
  950.       triggerTime++;
  951.       expect(triggerTime).toEqual(2);
  952.       expect(req.installationId).toEqual('yolo');
  953.     });
  954.  
  955.     var headers = {
  956.       'Content-Type': 'application/json',
  957.       'X-Parse-Application-Id': 'test',
  958.       'X-Parse-REST-API-Key': 'rest',
  959.       'X-Parse-Installation-Id': 'yolo'
  960.     };
  961.     request.post({
  962.       headers: headers,
  963.       url: 'http://localhost:8378/1/classes/GameScore',
  964.       body: JSON.stringify({ a: 'b' })
  965.     }, (error, response, body) => {
  966.       expect(error).toBe(null);
  967.       request.del({
  968.         headers: headers,
  969.         url: 'http://localhost:8378/1/classes/GameScore/' + JSON.parse(body).objectId
  970.       }, (error) => {
  971.         expect(error).toBe(null);
  972.         expect(triggerTime).toEqual(2);
  973.         done();
  974.       });
  975.     });
  976.   });
  977.  
  978.   it('test cloud function query parameters', (done) => {
  979.     Parse.Cloud.define('echoParams', (req, res) => {
  980.       res.success(req.params);
  981.     });
  982.     var headers = {
  983.       'Content-Type': 'application/json',
  984.       'X-Parse-Application-Id': 'test',
  985.       'X-Parse-Javascript-Key': 'test'
  986.     };
  987.     request.post({
  988.       headers: headers,
  989.       url: 'http://localhost:8378/1/functions/echoParams', //?option=1&other=2
  990.       qs: {
  991.         option: 1,
  992.         other: 2
  993.       },
  994.       body: '{"foo":"bar", "other": 1}'
  995.     }, (error, response, body) => {
  996.       expect(error).toBe(null);
  997.       var res = JSON.parse(body).result;
  998.       expect(res.option).toEqual('1');
  999.       // Make sure query string params override body params
  1000.       expect(res.other).toEqual('2');
  1001.       expect(res.foo).toEqual("bar");
  1002.       done();
  1003.     });
  1004.   });
  1005.  
  1006.   it('test cloud function parameter validation', (done) => {
  1007.     // Register a function with validation
  1008.     Parse.Cloud.define('functionWithParameterValidationFailure', (req, res) => {
  1009.       res.success('noway');
  1010.     }, (request) => {
  1011.       return request.params.success === 100;
  1012.     });
  1013.  
  1014.     Parse.Cloud.run('functionWithParameterValidationFailure', {"success":500}).then(() => {
  1015.       fail('Validation should not have succeeded');
  1016.       done();
  1017.     }, (e) => {
  1018.       expect(e.code).toEqual(142);
  1019.       expect(e.message).toEqual('Validation failed.');
  1020.       done();
  1021.     });
  1022.   });
  1023.  
  1024.   it('can handle null params in cloud functions (regression test for #1742)', done => {
  1025.     Parse.Cloud.define('func', (request, response) => {
  1026.       expect(request.params.nullParam).toEqual(null);
  1027.       response.success('yay');
  1028.     });
  1029.  
  1030.     Parse.Cloud.run('func', {nullParam: null})
  1031.     .then(() => {
  1032.       done()
  1033.     }, () => {
  1034.       fail('cloud code call failed');
  1035.       done();
  1036.     });
  1037.   });
  1038.  
  1039.   it('can handle date params in cloud functions (#2214)', done => {
  1040.     const date = new Date();
  1041.     Parse.Cloud.define('dateFunc', (request, response) => {
  1042.       expect(request.params.date.__type).toEqual('Date');
  1043.       expect(request.params.date.iso).toEqual(date.toISOString());
  1044.       response.success('yay');
  1045.     });
  1046.  
  1047.     Parse.Cloud.run('dateFunc', {date: date})
  1048.     .then(() => {
  1049.       done()
  1050.     }, () => {
  1051.       fail('cloud code call failed');
  1052.       done();
  1053.     });
  1054.   });
  1055.  
  1056.   it('fails on invalid client key', done => {
  1057.     var headers = {
  1058.       'Content-Type': 'application/octet-stream',
  1059.       'X-Parse-Application-Id': 'test',
  1060.       'X-Parse-Client-Key': 'notclient'
  1061.     };
  1062.     request.get({
  1063.       headers: headers,
  1064.       url: 'http://localhost:8378/1/classes/TestObject'
  1065.     }, (error, response, body) => {
  1066.       expect(error).toBe(null);
  1067.       var b = JSON.parse(body);
  1068.       expect(b.error).toEqual('unauthorized');
  1069.       done();
  1070.     });
  1071.   });
  1072.  
  1073.   it('fails on invalid windows key', done => {
  1074.     var headers = {
  1075.       'Content-Type': 'application/octet-stream',
  1076.       'X-Parse-Application-Id': 'test',
  1077.       'X-Parse-Windows-Key': 'notwindows'
  1078.     };
  1079.     request.get({
  1080.       headers: headers,
  1081.       url: 'http://localhost:8378/1/classes/TestObject'
  1082.     }, (error, response, body) => {
  1083.       expect(error).toBe(null);
  1084.       var b = JSON.parse(body);
  1085.       expect(b.error).toEqual('unauthorized');
  1086.       done();
  1087.     });
  1088.   });
  1089.  
  1090.   it('fails on invalid javascript key', done => {
  1091.     var headers = {
  1092.       'Content-Type': 'application/octet-stream',
  1093.       'X-Parse-Application-Id': 'test',
  1094.       'X-Parse-Javascript-Key': 'notjavascript'
  1095.     };
  1096.     request.get({
  1097.       headers: headers,
  1098.       url: 'http://localhost:8378/1/classes/TestObject'
  1099.     }, (error, response, body) => {
  1100.       expect(error).toBe(null);
  1101.       var b = JSON.parse(body);
  1102.       expect(b.error).toEqual('unauthorized');
  1103.       done();
  1104.     });
  1105.   });
  1106.  
  1107.   it('fails on invalid rest api key', done => {
  1108.     var headers = {
  1109.       'Content-Type': 'application/octet-stream',
  1110.       'X-Parse-Application-Id': 'test',
  1111.       'X-Parse-REST-API-Key': 'notrest'
  1112.     };
  1113.     request.get({
  1114.       headers: headers,
  1115.       url: 'http://localhost:8378/1/classes/TestObject'
  1116.     }, (error, response, body) => {
  1117.       expect(error).toBe(null);
  1118.       var b = JSON.parse(body);
  1119.       expect(b.error).toEqual('unauthorized');
  1120.       done();
  1121.     });
  1122.   });
  1123.  
  1124.   it('fails on invalid function', done => {
  1125.     Parse.Cloud.run('somethingThatDoesDefinitelyNotExist').then(() => {
  1126.       fail('This should have never suceeded');
  1127.       done();
  1128.     }, (e) => {
  1129.       expect(e.code).toEqual(Parse.Error.SCRIPT_FAILED);
  1130.       expect(e.message).toEqual('Invalid function: "somethingThatDoesDefinitelyNotExist"');
  1131.       done();
  1132.     });
  1133.   });
  1134.  
  1135.   it('dedupes an installation properly and returns updatedAt', (done) => {
  1136.     const headers = {
  1137.       'Content-Type': 'application/json',
  1138.       'X-Parse-Application-Id': 'test',
  1139.       'X-Parse-REST-API-Key': 'rest'
  1140.     };
  1141.     const data = {
  1142.       'installationId': 'lkjsahdfkjhsdfkjhsdfkjhsdf',
  1143.       'deviceType': 'embedded'
  1144.     };
  1145.     const requestOptions = {
  1146.       headers: headers,
  1147.       url: 'http://localhost:8378/1/installations',
  1148.       body: JSON.stringify(data)
  1149.     };
  1150.     request.post(requestOptions, (error, response, body) => {
  1151.       expect(error).toBe(null);
  1152.       const b = JSON.parse(body);
  1153.       expect(typeof b.objectId).toEqual('string');
  1154.       request.post(requestOptions, (error, response, body) => {
  1155.         expect(error).toBe(null);
  1156.         const b = JSON.parse(body);
  1157.         expect(typeof b.updatedAt).toEqual('string');
  1158.         done();
  1159.       });
  1160.     });
  1161.   });
  1162.  
  1163.   it('android login providing empty authData block works', (done) => {
  1164.     const headers = {
  1165.       'Content-Type': 'application/json',
  1166.       'X-Parse-Application-Id': 'test',
  1167.       'X-Parse-REST-API-Key': 'rest'
  1168.     };
  1169.     const data = {
  1170.       username: 'pulse1989',
  1171.       password: 'password1234',
  1172.       authData: {}
  1173.     };
  1174.     const requestOptions = {
  1175.       headers: headers,
  1176.       url: 'http://localhost:8378/1/users',
  1177.       body: JSON.stringify(data)
  1178.     };
  1179.     request.post(requestOptions, (error) => {
  1180.       expect(error).toBe(null);
  1181.       requestOptions.url = 'http://localhost:8378/1/login';
  1182.       request.get(requestOptions, (error, response, body) => {
  1183.         expect(error).toBe(null);
  1184.         const b = JSON.parse(body);
  1185.         expect(typeof b['sessionToken']).toEqual('string');
  1186.         done();
  1187.       });
  1188.     });
  1189.   });
  1190.  
  1191.   it('gets relation fields', (done) => {
  1192.     const object = new Parse.Object('AnObject');
  1193.     const relatedObject = new Parse.Object('RelatedObject');
  1194.     Parse.Object.saveAll([object, relatedObject]).then(() => {
  1195.       object.relation('related').add(relatedObject);
  1196.       return object.save();
  1197.     }).then(() => {
  1198.       const headers = {
  1199.         'Content-Type': 'application/json',
  1200.         'X-Parse-Application-Id': 'test',
  1201.         'X-Parse-REST-API-Key': 'rest'
  1202.       };
  1203.       const requestOptions = {
  1204.         headers: headers,
  1205.         url: 'http://localhost:8378/1/classes/AnObject',
  1206.         json: true
  1207.       };
  1208.       request.get(requestOptions, (err, res, body) => {
  1209.         expect(body.results.length).toBe(1);
  1210.         const result = body.results[0];
  1211.         expect(result.related).toEqual({
  1212.           __type: "Relation",
  1213.           className: 'RelatedObject'
  1214.         })
  1215.         done();
  1216.       });
  1217.     }).catch((err) => {
  1218.       jfail(err);
  1219.       done();
  1220.     })
  1221.   });
  1222.  
  1223.   it('properly returns incremented values (#1554)', (done) => {
  1224.     const headers = {
  1225.       'Content-Type': 'application/json',
  1226.       'X-Parse-Application-Id': 'test',
  1227.       'X-Parse-REST-API-Key': 'rest'
  1228.     };
  1229.     const requestOptions = {
  1230.       headers: headers,
  1231.       url: 'http://localhost:8378/1/classes/AnObject',
  1232.       json: true
  1233.     };
  1234.     const object = new Parse.Object('AnObject');
  1235.  
  1236.     function runIncrement(amount) {
  1237.       const options = Object.assign({}, requestOptions, {
  1238.         body: {
  1239.           "key": {
  1240.             __op: 'Increment',
  1241.             amount: amount
  1242.           }
  1243.         },
  1244.         url: 'http://localhost:8378/1/classes/AnObject/' + object.id
  1245.       })
  1246.       return new Promise((resolve, reject) => {
  1247.         request.put(options, (err, res, body)  => {
  1248.           if (err) {
  1249.             reject(err);
  1250.           } else {
  1251.             resolve(body);
  1252.           }
  1253.         });
  1254.       })
  1255.     }
  1256.  
  1257.     object.save().then(() => {
  1258.       return runIncrement(1);
  1259.     }).then((res) => {
  1260.       expect(res.key).toBe(1);
  1261.       return runIncrement(-1);
  1262.     }).then((res) => {
  1263.       expect(res.key).toBe(0);
  1264.       done();
  1265.     })
  1266.   })
  1267.  
  1268.   it('ignores _RevocableSession "header" send by JS SDK', (done) => {
  1269.     const object = new Parse.Object('AnObject');
  1270.     object.set('a', 'b');
  1271.     object.save().then(() => {
  1272.       request.post({
  1273.         headers: {'Content-Type': 'application/json'},
  1274.         url: 'http://localhost:8378/1/classes/AnObject',
  1275.         body: {
  1276.           _method: 'GET',
  1277.           _ApplicationId: 'test',
  1278.           _JavaScriptKey: 'test',
  1279.           _ClientVersion: 'js1.8.3',
  1280.           _InstallationId: 'iid',
  1281.           _RevocableSession: "1",
  1282.         },
  1283.         json: true
  1284.       }, (err, res, body) => {
  1285.         expect(body.error).toBeUndefined();
  1286.         expect(body.results).not.toBeUndefined();
  1287.         expect(body.results.length).toBe(1);
  1288.         const result = body.results[0];
  1289.         expect(result.a).toBe('b');
  1290.         done();
  1291.       })
  1292.     });
  1293.   });
  1294.  
  1295.   it('doesnt convert interior keys of objects that use special names', done => {
  1296.     const obj = new Parse.Object('Obj');
  1297.     obj.set('val', { createdAt: 'a', updatedAt: 1 });
  1298.     obj.save()
  1299.     .then(obj => new Parse.Query('Obj').get(obj.id))
  1300.     .then(obj => {
  1301.       expect(obj.get('val').createdAt).toEqual('a');
  1302.       expect(obj.get('val').updatedAt).toEqual(1);
  1303.       done();
  1304.     });
  1305.   });
  1306.  
  1307.   it('bans interior keys containing . or $', done => {
  1308.     new Parse.Object('Obj').save({innerObj: {'key with a $': 'fails'}})
  1309.     .then(() => {
  1310.       fail('should not succeed')
  1311.     }, error => {
  1312.       expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
  1313.       return new Parse.Object('Obj').save({innerObj: {'key with a .': 'fails'}});
  1314.     })
  1315.     .then(() => {
  1316.       fail('should not succeed')
  1317.     }, error => {
  1318.       expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
  1319.       return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with $': 'fails'}}});
  1320.     })
  1321.     .then(() => {
  1322.       fail('should not succeed')
  1323.     }, error => {
  1324.       expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
  1325.       return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with .': 'fails'}}});
  1326.     })
  1327.     .then(() => {
  1328.       fail('should not succeed')
  1329.       done();
  1330.     }, error => {
  1331.       expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
  1332.       done();
  1333.     });
  1334.   });
  1335.  
  1336.   it('does not change inner object keys named _auth_data_something', done => {
  1337.     new Parse.Object('O').save({ innerObj: {_auth_data_facebook: 7}})
  1338.     .then(object => new Parse.Query('O').get(object.id))
  1339.     .then(object => {
  1340.       expect(object.get('innerObj')).toEqual({_auth_data_facebook: 7});
  1341.       done();
  1342.     });
  1343.   });
  1344.  
  1345.   it('does not change inner object key names _p_somethign', done => {
  1346.     new Parse.Object('O').save({ innerObj: {_p_data: 7}})
  1347.     .then(object => new Parse.Query('O').get(object.id))
  1348.     .then(object => {
  1349.       expect(object.get('innerObj')).toEqual({_p_data: 7});
  1350.       done();
  1351.     });
  1352.   });
  1353.  
  1354.   it('does not change inner object key names _rperm, _wperm', done => {
  1355.     new Parse.Object('O').save({ innerObj: {_rperm: 7, _wperm: 8}})
  1356.     .then(object => new Parse.Query('O').get(object.id))
  1357.     .then(object => {
  1358.       expect(object.get('innerObj')).toEqual({_rperm: 7, _wperm: 8});
  1359.       done();
  1360.     });
  1361.   });
  1362.  
  1363.   it('does not change inner objects if the key has the same name as a geopoint field on the class, and the value is an array of length 2, or if the key has the same name as a file field on the class, and the value is a string', done => {
  1364.     const file = new Parse.File('myfile.txt', { base64: 'eAo=' });
  1365.     file.save()
  1366.     .then(f => {
  1367.       const obj = new Parse.Object('O');
  1368.       obj.set('fileField', f);
  1369.       obj.set('geoField', new Parse.GeoPoint(0, 0));
  1370.       obj.set('innerObj', {
  1371.         fileField: "data",
  1372.         geoField: [1,2],
  1373.       });
  1374.       return obj.save();
  1375.     })
  1376.     .then(object => object.fetch())
  1377.     .then(object => {
  1378.       expect(object.get('innerObj')).toEqual({
  1379.         fileField: "data",
  1380.         geoField: [1,2],
  1381.       });
  1382.       done();
  1383.     }).catch((e) => {
  1384.       jfail(e);
  1385.       done();
  1386.     });
  1387.   });
  1388.  
  1389.   it('purge all objects in class', (done) => {
  1390.     const object = new Parse.Object('TestObject');
  1391.     object.set('foo', 'bar');
  1392.     const object2 = new Parse.Object('TestObject');
  1393.     object2.set('alice', 'wonderland');
  1394.     Parse.Object.saveAll([object, object2])
  1395.     .then(() => {
  1396.       const query = new Parse.Query(TestObject);
  1397.       return query.count()
  1398.     }).then((count) => {
  1399.       expect(count).toBe(2);
  1400.       const headers = {
  1401.         'Content-Type': 'application/json',
  1402.         'X-Parse-Application-Id': 'test',
  1403.         'X-Parse-Master-Key': 'test'
  1404.       };
  1405.       request.del({
  1406.         headers: headers,
  1407.         url: 'http://localhost:8378/1/purge/TestObject',
  1408.         json: true
  1409.       }, (err) => {
  1410.         expect(err).toBe(null);
  1411.         const query = new Parse.Query(TestObject);
  1412.         return query.count().then((count) => {
  1413.           expect(count).toBe(0);
  1414.           done();
  1415.         });
  1416.       });
  1417.     });
  1418.   });
  1419.  
  1420.   it('fail on purge all objects in class without master key', (done) => {
  1421.     const headers = {
  1422.       'Content-Type': 'application/json',
  1423.       'X-Parse-Application-Id': 'test',
  1424.       'X-Parse-REST-API-Key': 'rest'
  1425.     };
  1426.     rp({
  1427.       method: 'DELETE',
  1428.       headers: headers,
  1429.       uri: 'http://localhost:8378/1/purge/TestObject',
  1430.       json: true
  1431.     }).then(() => {
  1432.       fail('Should not succeed');
  1433.     }).catch(err => {
  1434.       expect(err.error.error).toEqual('unauthorized: master key is required');
  1435.       done();
  1436.     });
  1437.   });
  1438.  
  1439.   it('purge all objects in _Role also purge cache', (done) => {
  1440.     const headers = {
  1441.       'Content-Type': 'application/json',
  1442.       'X-Parse-Application-Id': 'test',
  1443.       'X-Parse-Master-Key': 'test'
  1444.     };
  1445.     var user, object;
  1446.     createTestUser().then((x) => {
  1447.       user = x;
  1448.       const acl = new Parse.ACL();
  1449.       acl.setPublicReadAccess(true);
  1450.       acl.setPublicWriteAccess(false);
  1451.       const role = new Parse.Object('_Role');
  1452.       role.set('name', 'TestRole');
  1453.       role.setACL(acl);
  1454.       const users = role.relation('users');
  1455.       users.add(user);
  1456.       return role.save({}, { useMasterKey: true });
  1457.     }).then(() => {
  1458.       const query = new Parse.Query('_Role');
  1459.       return query.find({ useMasterKey: true });
  1460.     }).then((x) => {
  1461.       expect(x.length).toEqual(1);
  1462.       const relation = x[0].relation('users').query();
  1463.       return relation.first({ useMasterKey: true });
  1464.     }).then((x) => {
  1465.       expect(x.id).toEqual(user.id);
  1466.       object = new Parse.Object('TestObject');
  1467.       const acl = new Parse.ACL();
  1468.       acl.setPublicReadAccess(false);
  1469.       acl.setPublicWriteAccess(false);
  1470.       acl.setRoleReadAccess('TestRole', true);
  1471.       acl.setRoleWriteAccess('TestRole', true);
  1472.       object.setACL(acl);
  1473.       return object.save();
  1474.     }).then(() => {
  1475.       const query = new Parse.Query('TestObject');
  1476.       return query.find({ sessionToken: user.getSessionToken() });
  1477.     }).then((x) => {
  1478.       expect(x.length).toEqual(1);
  1479.       return rp({
  1480.         method: 'DELETE',
  1481.         headers: headers,
  1482.         uri: 'http://localhost:8378/1/purge/_Role',
  1483.         json: true
  1484.       });
  1485.     }).then(() => {
  1486.       const query = new Parse.Query('TestObject');
  1487.       return query.get(object.id, { sessionToken: user.getSessionToken() });
  1488.     }).then(() => {
  1489.       fail('Should not succeed');
  1490.     }, (e) => {
  1491.       expect(e.code).toEqual(Parse.Error.OBJECT_NOT_FOUND);
  1492.       done();
  1493.     });
  1494.   });
  1495.  
  1496.   it('should not update schema beforeSave #2672', (done) => {
  1497.     Parse.Cloud.beforeSave('MyObject', (request, response) => {
  1498.       if (request.object.get('secret')) {
  1499.         response.error('cannot set secret here');
  1500.         return;
  1501.       }
  1502.       response.success();
  1503.     });
  1504.  
  1505.     const object = new Parse.Object('MyObject');
  1506.     object.set('key', 'value');
  1507.     object.save().then(() => {
  1508.       return object.save({'secret': 'should not update schema'});
  1509.     }).then(() => {
  1510.       fail();
  1511.       done();
  1512.     }, () => {
  1513.       return rp({
  1514.         method: 'GET',
  1515.         headers: {
  1516.           'X-Parse-Application-Id': 'test',
  1517.           'X-Parse-Master-Key': 'test'
  1518.         },
  1519.         uri: 'http://localhost:8378/1/schemas/MyObject',
  1520.         json: true
  1521.       });
  1522.     }).then((res) => {
  1523.       const fields = res.fields;
  1524.       expect(fields.secret).toBeUndefined();
  1525.       done();
  1526.     }, (err) => {
  1527.       jfail(err);
  1528.       done();
  1529.     });
  1530.   });
  1531. });
  1532.  
  1533. describe_only_db('mongo')('legacy _acl', () => {
  1534.   it('should have _acl when locking down (regression for #2465)', (done) =>  {
  1535.     const headers = {
  1536.       'X-Parse-Application-Id': 'test',
  1537.       'X-Parse-REST-API-Key': 'rest'
  1538.     }
  1539.     rp({
  1540.       method: 'POST',
  1541.       headers: headers,
  1542.       uri: 'http://localhost:8378/1/classes/Report',
  1543.       body: {
  1544.         ACL: {},
  1545.         name: 'My Report'
  1546.       },
  1547.       json: true
  1548.     }).then(() => {
  1549.       const config = new Config('test');
  1550.       const adapter = config.database.adapter;
  1551.       return adapter._adaptiveCollection("Report")
  1552.           .then(collection => collection.find({}))
  1553.     }).then((results) => {
  1554.       expect(results.length).toBe(1);
  1555.       const result = results[0];
  1556.       expect(result.name).toEqual('My Report');
  1557.       expect(result._wperm).toEqual([]);
  1558.       expect(result._rperm).toEqual([]);
  1559.       expect(result._acl).toEqual({});
  1560.       done();
  1561.     }).catch((err) => {
  1562.       fail(JSON.stringify(err));
  1563.       done();
  1564.     });
  1565.   });
  1566. });
  1567.  
downloadParseAPI.spec.js Source code - Download parse-server Source code
Related Source Codes/Software:
react-boilerplate - 2017-06-07
webtorrent - Streaming torrent client for the web ... 2017-06-06
machine-learning-for-software-engineers - A complete daily plan for studying to become a mac... 2017-06-06
upterm - A terminal emulator for the 21st century. 2017-06-06
lottie-android - Render After Effects animations natively on Androi... 2017-06-07
AsyncDisplayKit - Smooth asynchronous user interfaces for iOS apps. ... 2017-06-07
ionicons - The premium icon font for Ionic ... 2017-06-07
storybook - 2017-06-07
prettier - Prettier is an opinionated JavaScript formatter. ... 2017-06-08
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top