BVB Source Codes

parse-server Show Schema.spec.js Source code

Return Download parse-server: download Schema.spec.js Source code - Download parse-server Source code - Type:.js
  1. 'use strict';
  2.  
  3. var Config = require('../src/Config');
  4. var SchemaController = require('../src/Controllers/SchemaController');
  5. var dd = require('deep-diff');
  6.  
  7. var config;
  8.  
  9. var hasAllPODobject = () => {
  10.   var obj = new Parse.Object('HasAllPOD');
  11.   obj.set('aNumber', 5);
  12.   obj.set('aString', 'string');
  13.   obj.set('aBool', true);
  14.   obj.set('aDate', new Date());
  15.   obj.set('aObject', {k1: 'value', k2: true, k3: 5});
  16.   obj.set('aArray', ['contents', true, 5]);
  17.   obj.set('aGeoPoint', new Parse.GeoPoint({latitude: 0, longitude: 0}));
  18.   obj.set('aFile', new Parse.File('f.txt', { base64: 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=' }));
  19.   return obj;
  20. };
  21.  
  22. describe('SchemaController', () => {
  23.   beforeEach(() => {
  24.     config = new Config('test');
  25.   });
  26.  
  27.   it('can validate one object', (done) => {
  28.     config.database.loadSchema().then((schema) => {
  29.       return schema.validateObject('TestObject', {a: 1, b: 'yo', c: false});
  30.     }).then(() => {
  31.       done();
  32.     }, (error) => {
  33.       jfail(error);
  34.       done();
  35.     });
  36.   });
  37.  
  38.   it('can validate one object with dot notation', (done) => {
  39.     config.database.loadSchema().then((schema) => {
  40.       return schema.validateObject('TestObjectWithSubDoc', {x: false, y: 'YY', z: 1, 'aObject.k1': 'newValue'});
  41.     }).then(() => {
  42.       done();
  43.     }, (error) => {
  44.       jfail(error);
  45.       done();
  46.     });
  47.   });
  48.  
  49.   it('can validate two objects in a row', (done) => {
  50.     config.database.loadSchema().then((schema) => {
  51.       return schema.validateObject('Foo', {x: true, y: 'yyy', z: 0});
  52.     }).then((schema) => {
  53.       return schema.validateObject('Foo', {x: false, y: 'YY', z: 1});
  54.     }).then(() => {
  55.       done();
  56.     });
  57.   });
  58.  
  59.   it('can validate Relation object', (done) => {
  60.     config.database.loadSchema().then((schema) => {
  61.       return schema.validateObject('Stuff', {aRelation: {__type:'Relation',className:'Stuff'}});
  62.     }).then((schema) => {
  63.       return schema.validateObject('Stuff', {aRelation: {__type:'Pointer',className:'Stuff'}})
  64.       .then(() => {
  65.         fail('expected invalidity');
  66.         done();
  67.       }, done);
  68.     }, (err) => {
  69.       fail(err);
  70.       done();
  71.     });
  72.   });
  73.  
  74.   it('rejects inconsistent types', (done) => {
  75.     config.database.loadSchema().then((schema) => {
  76.       return schema.validateObject('Stuff', {bacon: 7});
  77.     }).then((schema) => {
  78.       return schema.validateObject('Stuff', {bacon: 'z'});
  79.     }).then(() => {
  80.       fail('expected invalidity');
  81.       done();
  82.     }, done);
  83.   });
  84.  
  85.   it('updates when new fields are added', (done) => {
  86.     config.database.loadSchema().then((schema) => {
  87.       return schema.validateObject('Stuff', {bacon: 7});
  88.     }).then((schema) => {
  89.       return schema.validateObject('Stuff', {sausage: 8});
  90.     }).then((schema) => {
  91.       return schema.validateObject('Stuff', {sausage: 'ate'});
  92.     }).then(() => {
  93.       fail('expected invalidity');
  94.       done();
  95.     }, done);
  96.   });
  97.  
  98.   it('class-level permissions test find', (done) => {
  99.     config.database.loadSchema().then((schema) => {
  100.       // Just to create a valid class
  101.       return schema.validateObject('Stuff', {foo: 'bar'});
  102.     }).then((schema) => {
  103.       return schema.setPermissions('Stuff', {
  104.         'find': {}
  105.       });
  106.     }).then(() => {
  107.       var query = new Parse.Query('Stuff');
  108.       return query.find();
  109.     }).then(() => {
  110.       fail('Class permissions should have rejected this query.');
  111.       done();
  112.     }, () => {
  113.       done();
  114.     });
  115.   });
  116.  
  117.   it('class-level permissions test user', (done) => {
  118.     var user;
  119.     createTestUser().then((u) => {
  120.       user = u;
  121.       return config.database.loadSchema();
  122.     }).then((schema) => {
  123.       // Just to create a valid class
  124.       return schema.validateObject('Stuff', {foo: 'bar'});
  125.     }).then((schema) => {
  126.       var find = {};
  127.       find[user.id] = true;
  128.       return schema.setPermissions('Stuff', {
  129.         'find': find
  130.       });
  131.     }).then(() => {
  132.       var query = new Parse.Query('Stuff');
  133.       return query.find();
  134.     }).then(() => {
  135.       done();
  136.     }, () => {
  137.       fail('Class permissions should have allowed this query.');
  138.       done();
  139.     });
  140.   });
  141.  
  142.   it('class-level permissions test get', (done) => {
  143.     var obj;
  144.     createTestUser()
  145.     .then(user => {
  146.       return config.database.loadSchema()
  147.       // Create a valid class
  148.       .then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
  149.       .then(schema => {
  150.         var find = {};
  151.         var get = {};
  152.         get[user.id] = true;
  153.         return schema.setPermissions('Stuff', {
  154.           'create': {'*': true},
  155.           'find': find,
  156.           'get': get
  157.         });
  158.       }).then(() => {
  159.         obj = new Parse.Object('Stuff');
  160.         obj.set('foo', 'bar');
  161.         return obj.save();
  162.       }).then((o) => {
  163.         obj = o;
  164.         var query = new Parse.Query('Stuff');
  165.         return query.find();
  166.       }).then(() => {
  167.         fail('Class permissions should have rejected this query.');
  168.         done();
  169.       }, () => {
  170.         var query = new Parse.Query('Stuff');
  171.         return query.get(obj.id).then(() => {
  172.           done();
  173.         }, () => {
  174.           fail('Class permissions should have allowed this get query');
  175.           done();
  176.         });
  177.       });
  178.     });
  179.   });
  180.  
  181.   it('class-level permissions test count', (done) => {
  182.     var obj;
  183.     return config.database.loadSchema()
  184.       // Create a valid class
  185.       .then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
  186.       .then(schema => {
  187.         var count = {};
  188.         return schema.setPermissions('Stuff', {
  189.           'create': {'*': true},
  190.           'find': {'*': true},
  191.           'count': count
  192.         })
  193.       }).then(() => {
  194.         obj = new Parse.Object('Stuff');
  195.         obj.set('foo', 'bar');
  196.         return obj.save();
  197.       }).then((o) => {
  198.         obj = o;
  199.         var query = new Parse.Query('Stuff');
  200.         return query.find();
  201.       }).then((results) => {
  202.         expect(results.length).toBe(1);
  203.         var query = new Parse.Query('Stuff');
  204.         return query.count();
  205.       }).then(() => {
  206.         fail('Class permissions should have rejected this query.');
  207.       }, (err) => {
  208.         expect(err.message).toEqual('Permission denied for action count on class Stuff.');
  209.         done();
  210.       });
  211.   });
  212.  
  213.   it('can add classes without needing an object', done => {
  214.     config.database.loadSchema()
  215.     .then(schema => schema.addClassIfNotExists('NewClass', {
  216.       foo: {type: 'String'},
  217.     }))
  218.     .then(actualSchema => {
  219.       const expectedSchema = {
  220.         className: 'NewClass',
  221.         fields: {
  222.           objectId: { type: 'String' },
  223.           updatedAt: { type: 'Date' },
  224.           createdAt: { type: 'Date' },
  225.           ACL: { type: 'ACL' },
  226.           foo: { type: 'String' },
  227.         },
  228.         classLevelPermissions: {
  229.           find: { '*': true },
  230.           get: { '*': true },
  231.           create: { '*': true },
  232.           update: { '*': true },
  233.           delete: { '*': true },
  234.           addField: { '*': true },
  235.         },
  236.       }
  237.       expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  238.       done();
  239.     })
  240.     .catch(error => {
  241.       fail('Error creating class: ' + JSON.stringify(error));
  242.     });
  243.   });
  244.  
  245.   it('can update classes without needing an object', done => {
  246.     const levelPermissions = {
  247.       find: { '*': true },
  248.       get: { '*': true },
  249.       create: { '*': true },
  250.       update: { '*': true },
  251.       delete: { '*': true },
  252.       addField: { '*': true },
  253.     };
  254.     config.database.loadSchema()
  255.       .then(schema => {
  256.         schema.validateObject('NewClass', { foo: 2 })
  257.           .then(() => schema.reloadData())
  258.           .then(() => schema.updateClass('NewClass', {
  259.             fooOne: {type: 'Number'},
  260.             fooTwo: {type: 'Array'},
  261.             fooThree: {type: 'Date'},
  262.             fooFour: {type: 'Object'},
  263.             fooFive: {type: 'Relation', targetClass: '_User' },
  264.             fooSix: {type: 'String'},
  265.             fooSeven: {type: 'Object' },
  266.             fooEight: {type: 'String'},
  267.             fooNine: {type: 'String'},
  268.             fooTeen: {type: 'Number' },
  269.             fooEleven: {type: 'String'},
  270.             fooTwelve: {type: 'String'},
  271.             fooThirteen: {type: 'String'},
  272.             fooFourteen: {type: 'String'},
  273.             fooFifteen: {type: 'String'},
  274.             fooSixteen: {type: 'String'},
  275.             fooEighteen: {type: 'String'},
  276.             fooNineteen: {type: 'String'},
  277.           }, levelPermissions, config.database))
  278.           .then(actualSchema => {
  279.             const expectedSchema = {
  280.               className: 'NewClass',
  281.               fields: {
  282.                 objectId: { type: 'String' },
  283.                 updatedAt: { type: 'Date' },
  284.                 createdAt: { type: 'Date' },
  285.                 ACL: { type: 'ACL' },
  286.                 foo: { type: 'Number' },
  287.                 fooOne: {type: 'Number'},
  288.                 fooTwo: {type: 'Array'},
  289.                 fooThree: {type: 'Date'},
  290.                 fooFour: {type: 'Object'},
  291.                 fooFive: {type: 'Relation', targetClass: '_User' },
  292.                 fooSix: {type: 'String'},
  293.                 fooSeven: {type: 'Object' },
  294.                 fooEight: {type: 'String'},
  295.                 fooNine: {type: 'String'},
  296.                 fooTeen: {type: 'Number' },
  297.                 fooEleven: {type: 'String'},
  298.                 fooTwelve: {type: 'String'},
  299.                 fooThirteen: {type: 'String'},
  300.                 fooFourteen: {type: 'String'},
  301.                 fooFifteen: {type: 'String'},
  302.                 fooSixteen: {type: 'String'},
  303.                 fooEighteen: {type: 'String'},
  304.                 fooNineteen: {type: 'String'},
  305.               },
  306.               classLevelPermissions: { ...levelPermissions },
  307.             };
  308.  
  309.             expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  310.             done();
  311.           })
  312.           .catch(error => {
  313.             console.trace(error);
  314.             done();
  315.             fail('Error creating class: ' + JSON.stringify(error));
  316.           });
  317.       });
  318.   });
  319.  
  320.   it('will fail to create a class if that class was already created by an object', done => {
  321.     config.database.loadSchema()
  322.       .then(schema => {
  323.         schema.validateObject('NewClass', { foo: 7 })
  324.           .then(() => schema.reloadData())
  325.           .then(() => schema.addClassIfNotExists('NewClass', {
  326.             foo: { type: 'String' }
  327.           }))
  328.           .catch(error => {
  329.             expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  330.             expect(error.message).toEqual('Class NewClass already exists.');
  331.             done();
  332.           });
  333.       });
  334.   });
  335.  
  336.   it('will resolve class creation races appropriately', done => {
  337.     // If two callers race to create the same schema, the response to the
  338.     // race loser should be the same as if they hadn't been racing.
  339.     config.database.loadSchema()
  340.     .then(schema => {
  341.       var p1 = schema.addClassIfNotExists('NewClass', {foo: {type: 'String'}});
  342.       var p2 = schema.addClassIfNotExists('NewClass', {foo: {type: 'String'}});
  343.       Promise.race([p1, p2])
  344.       .then(actualSchema => {
  345.         const expectedSchema = {
  346.           className: 'NewClass',
  347.           fields: {
  348.             objectId: { type: 'String' },
  349.             updatedAt: { type: 'Date' },
  350.             createdAt: { type: 'Date' },
  351.             ACL: { type: 'ACL' },
  352.             foo: { type: 'String' },
  353.           },
  354.           classLevelPermissions: {
  355.             find: { '*': true },
  356.             get: { '*': true },
  357.             create: { '*': true },
  358.             update: { '*': true },
  359.             delete: { '*': true },
  360.             addField: { '*': true },
  361.           },
  362.         }
  363.         expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  364.       });
  365.       Promise.all([p1,p2])
  366.       .catch(error => {
  367.         expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  368.         expect(error.message).toEqual('Class NewClass already exists.');
  369.         done();
  370.       });
  371.     });
  372.   });
  373.  
  374.   it('refuses to create classes with invalid names', done => {
  375.     config.database.loadSchema()
  376.     .then(schema => {
  377.       schema.addClassIfNotExists('_InvalidName', {foo: {type: 'String'}})
  378.       .catch(error => {
  379.         expect(error.error).toEqual(
  380.           'Invalid classname: _InvalidName, classnames can only have alphanumeric characters and _, and must start with an alpha character '
  381.         );
  382.         done();
  383.       });
  384.     });
  385.   });
  386.  
  387.   it('refuses to add fields with invalid names', done => {
  388.     config.database.loadSchema()
  389.     .then(schema => schema.addClassIfNotExists('NewClass', {'0InvalidName': {type: 'String'}}))
  390.     .catch(error => {
  391.       expect(error.code).toEqual(Parse.Error.INVALID_KEY_NAME);
  392.       expect(error.error).toEqual('invalid field name: 0InvalidName');
  393.       done();
  394.     });
  395.   });
  396.  
  397.   it('refuses to explicitly create the default fields for custom classes', done => {
  398.     config.database.loadSchema()
  399.     .then(schema => schema.addClassIfNotExists('NewClass', {objectId: {type: 'String'}}))
  400.     .catch(error => {
  401.       expect(error.code).toEqual(136);
  402.       expect(error.error).toEqual('field objectId cannot be added');
  403.       done();
  404.     });
  405.   });
  406.  
  407.   it('refuses to explicitly create the default fields for non-custom classes', done => {
  408.     config.database.loadSchema()
  409.     .then(schema => schema.addClassIfNotExists('_Installation', {localeIdentifier: {type: 'String'}}))
  410.     .catch(error => {
  411.       expect(error.code).toEqual(136);
  412.       expect(error.error).toEqual('field localeIdentifier cannot be added');
  413.       done();
  414.     });
  415.   });
  416.  
  417.   it('refuses to add fields with invalid types', done => {
  418.     config.database.loadSchema()
  419.     .then(schema => schema.addClassIfNotExists('NewClass', {
  420.       foo: {type: 7}
  421.     }))
  422.     .catch(error => {
  423.       expect(error.code).toEqual(Parse.Error.INVALID_JSON);
  424.       expect(error.error).toEqual('invalid JSON');
  425.       done();
  426.     });
  427.   });
  428.  
  429.   it('refuses to add fields with invalid pointer types', done => {
  430.     config.database.loadSchema()
  431.     .then(schema => schema.addClassIfNotExists('NewClass', {
  432.       foo: {type: 'Pointer'}
  433.     }))
  434.     .catch(error => {
  435.       expect(error.code).toEqual(135);
  436.       expect(error.error).toEqual('type Pointer needs a class name');
  437.       done();
  438.     });
  439.   });
  440.  
  441.   it('refuses to add fields with invalid pointer target', done => {
  442.     config.database.loadSchema()
  443.     .then(schema => schema.addClassIfNotExists('NewClass', {
  444.       foo: {type: 'Pointer', targetClass: 7},
  445.     }))
  446.     .catch(error => {
  447.       expect(error.code).toEqual(Parse.Error.INVALID_JSON);
  448.       expect(error.error).toEqual('invalid JSON');
  449.       done();
  450.     });
  451.   });
  452.  
  453.   it('refuses to add fields with invalid Relation type', done => {
  454.     config.database.loadSchema()
  455.     .then(schema => schema.addClassIfNotExists('NewClass', {
  456.       foo: {type: 'Relation', uselessKey: 7},
  457.     }))
  458.     .catch(error => {
  459.       expect(error.code).toEqual(135);
  460.       expect(error.error).toEqual('type Relation needs a class name');
  461.       done();
  462.     });
  463.   });
  464.  
  465.   it('refuses to add fields with invalid relation target', done => {
  466.     config.database.loadSchema()
  467.     .then(schema => schema.addClassIfNotExists('NewClass', {
  468.       foo: {type: 'Relation', targetClass: 7},
  469.     }))
  470.     .catch(error => {
  471.       expect(error.code).toEqual(Parse.Error.INVALID_JSON);
  472.       expect(error.error).toEqual('invalid JSON');
  473.       done();
  474.     });
  475.   });
  476.  
  477.   it('refuses to add fields with uncreatable pointer target class', done => {
  478.     config.database.loadSchema()
  479.     .then(schema => schema.addClassIfNotExists('NewClass', {
  480.       foo: {type: 'Pointer', targetClass: 'not a valid class name'},
  481.     }))
  482.     .catch(error => {
  483.       expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  484.       expect(error.error).toEqual('Invalid classname: not a valid class name, classnames can only have alphanumeric characters and _, and must start with an alpha character ');
  485.       done();
  486.     });
  487.   });
  488.  
  489.   it('refuses to add fields with uncreatable relation target class', done => {
  490.     config.database.loadSchema()
  491.     .then(schema => schema.addClassIfNotExists('NewClass', {
  492.       foo: {type: 'Relation', targetClass: 'not a valid class name'},
  493.     }))
  494.     .catch(error => {
  495.       expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  496.       expect(error.error).toEqual('Invalid classname: not a valid class name, classnames can only have alphanumeric characters and _, and must start with an alpha character ');
  497.       done();
  498.     });
  499.   });
  500.  
  501.   it('refuses to add fields with unknown types', done => {
  502.     config.database.loadSchema()
  503.     .then(schema => schema.addClassIfNotExists('NewClass', {
  504.       foo: {type: 'Unknown'},
  505.     }))
  506.     .catch(error => {
  507.       expect(error.code).toEqual(Parse.Error.INCORRECT_TYPE);
  508.       expect(error.error).toEqual('invalid field type: Unknown');
  509.       done();
  510.     });
  511.   });
  512.  
  513.   it('will create classes', done => {
  514.     config.database.loadSchema()
  515.     .then(schema => schema.addClassIfNotExists('NewClass', {
  516.       aNumber: {type: 'Number'},
  517.       aString: {type: 'String'},
  518.       aBool: {type: 'Boolean'},
  519.       aDate: {type: 'Date'},
  520.       aObject: {type: 'Object'},
  521.       aArray: {type: 'Array'},
  522.       aGeoPoint: {type: 'GeoPoint'},
  523.       aFile: {type: 'File'},
  524.       aPointer: {type: 'Pointer', targetClass: 'ThisClassDoesNotExistYet'},
  525.       aRelation: {type: 'Relation', targetClass: 'NewClass'},
  526.       aBytes: {type: 'Bytes'},
  527.     }))
  528.     .then(actualSchema => {
  529.       const expectedSchema = {
  530.         className: 'NewClass',
  531.         fields: {
  532.           objectId: { type: 'String' },
  533.           updatedAt: { type: 'Date' },
  534.           createdAt: { type: 'Date' },
  535.           ACL: { type: 'ACL' },
  536.           aString: { type: 'String' },
  537.           aNumber: { type: 'Number' },
  538.           aBool: { type: 'Boolean' },
  539.           aDate: { type: 'Date' },
  540.           aObject: { type: 'Object' },
  541.           aArray: { type: 'Array' },
  542.           aGeoPoint: { type: 'GeoPoint' },
  543.           aFile: { type: 'File' },
  544.           aPointer: { type: 'Pointer', targetClass: 'ThisClassDoesNotExistYet' },
  545.           aRelation: { type: 'Relation', targetClass: 'NewClass' },
  546.           aBytes: {type: 'Bytes'},
  547.         },
  548.         classLevelPermissions: {
  549.           find: { '*': true },
  550.           get: { '*': true },
  551.           create: { '*': true },
  552.           update: { '*': true },
  553.           delete: { '*': true },
  554.           addField: { '*': true },
  555.         },
  556.       }
  557.       expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  558.       done();
  559.     });
  560.   });
  561.  
  562.   it('creates the default fields for non-custom classes', done => {
  563.     config.database.loadSchema()
  564.     .then(schema => schema.addClassIfNotExists('_Installation', {
  565.       foo: {type: 'Number'},
  566.     }))
  567.     .then(actualSchema => {
  568.       const expectedSchema = {
  569.         className: '_Installation',
  570.         fields: {
  571.           objectId: { type: 'String' },
  572.           updatedAt: { type: 'Date' },
  573.           createdAt: { type: 'Date' },
  574.           ACL: { type: 'ACL' },
  575.           foo: { type: 'Number' },
  576.           installationId: { type: 'String' },
  577.           deviceToken: { type: 'String' },
  578.           channels: { type: 'Array' },
  579.           deviceType: { type: 'String' },
  580.           pushType: { type: 'String' },
  581.           GCMSenderId: { type: 'String' },
  582.           timeZone: { type: 'String' },
  583.           localeIdentifier: { type: 'String' },
  584.           badge: { type: 'Number' },
  585.           appVersion: { type: 'String' },
  586.           appName: { type: 'String' },
  587.           appIdentifier: { type: 'String' },
  588.           parseVersion: { type: 'String' },
  589.         },
  590.         classLevelPermissions: {
  591.           find: { '*': true },
  592.           get: { '*': true },
  593.           create: { '*': true },
  594.           update: { '*': true },
  595.           delete: { '*': true },
  596.           addField: { '*': true },
  597.         },
  598.       }
  599.       expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  600.       done();
  601.     });
  602.   });
  603.  
  604.   it('creates non-custom classes which include relation field', done => {
  605.     config.database.loadSchema()
  606.     //as `_Role` is always created by default, we only get it here
  607.     .then(schema => schema.getOneSchema('_Role'))
  608.     .then(actualSchema => {
  609.       const expectedSchema = {
  610.         className: '_Role',
  611.         fields: {
  612.           objectId: { type: 'String' },
  613.           updatedAt: { type: 'Date' },
  614.           createdAt: { type: 'Date' },
  615.           ACL: { type: 'ACL' },
  616.           name: { type: 'String' },
  617.           users: { type: 'Relation', targetClass: '_User' },
  618.           roles: { type: 'Relation', targetClass: '_Role' },
  619.         },
  620.         classLevelPermissions: {
  621.           find: { '*': true },
  622.           get: { '*': true },
  623.           create: { '*': true },
  624.           update: { '*': true },
  625.           delete: { '*': true },
  626.           addField: { '*': true },
  627.         },
  628.       };
  629.       expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  630.       done();
  631.     });
  632.   });
  633.  
  634.   it('creates non-custom classes which include pointer field', done => {
  635.     config.database.loadSchema()
  636.     .then(schema => schema.addClassIfNotExists('_Session', {}))
  637.     .then(actualSchema => {
  638.       const expectedSchema = {
  639.         className: '_Session',
  640.         fields: {
  641.           objectId: { type: 'String' },
  642.           updatedAt: { type: 'Date' },
  643.           createdAt: { type: 'Date' },
  644.           restricted: { type: 'Boolean' },
  645.           user: { type: 'Pointer', targetClass: '_User' },
  646.           installationId: { type: 'String' },
  647.           sessionToken: { type: 'String' },
  648.           expiresAt: { type: 'Date' },
  649.           createdWith: { type: 'Object' },
  650.           ACL: { type: 'ACL' },
  651.         },
  652.         classLevelPermissions: {
  653.           find: { '*': true },
  654.           get: { '*': true },
  655.           create: { '*': true },
  656.           update: { '*': true },
  657.           delete: { '*': true },
  658.           addField: { '*': true },
  659.         },
  660.       };
  661.       expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  662.       done();
  663.     });
  664.   });
  665.  
  666.   it('refuses to create two geopoints', done => {
  667.     config.database.loadSchema()
  668.     .then(schema => schema.addClassIfNotExists('NewClass', {
  669.       geo1: {type: 'GeoPoint'},
  670.       geo2: {type: 'GeoPoint'}
  671.     }))
  672.     .catch(error => {
  673.       expect(error.code).toEqual(Parse.Error.INCORRECT_TYPE);
  674.       expect(error.error).toEqual('currently, only one GeoPoint field may exist in an object. Adding geo2 when geo1 already exists.');
  675.       done();
  676.     });
  677.   });
  678.  
  679.   it('can check if a class exists', done => {
  680.     config.database.loadSchema()
  681.     .then(schema => {
  682.       return schema.addClassIfNotExists('NewClass', {})
  683.       .then(() => {
  684.         schema.hasClass('NewClass')
  685.         .then(hasClass => {
  686.           expect(hasClass).toEqual(true);
  687.           done();
  688.         })
  689.         .catch(fail);
  690.  
  691.         schema.hasClass('NonexistantClass')
  692.         .then(hasClass => {
  693.           expect(hasClass).toEqual(false);
  694.           done();
  695.         })
  696.         .catch(fail);
  697.       })
  698.       .catch(error => {
  699.         fail('Couldn\'t create class');
  700.         jfail(error);
  701.       });
  702.     })
  703.     .catch(() => fail('Couldn\'t load schema'));
  704.   });
  705.  
  706.   it('refuses to delete fields from invalid class names', done => {
  707.     config.database.loadSchema()
  708.     .then(schema => schema.deleteField('fieldName', 'invalid class name'))
  709.     .catch(error => {
  710.       expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  711.       done();
  712.     });
  713.   });
  714.  
  715.   it('refuses to delete invalid fields', done => {
  716.     config.database.loadSchema()
  717.     .then(schema => schema.deleteField('invalid field name', 'ValidClassName'))
  718.     .catch(error => {
  719.       expect(error.code).toEqual(Parse.Error.INVALID_KEY_NAME);
  720.       done();
  721.     });
  722.   });
  723.  
  724.   it('refuses to delete the default fields', done => {
  725.     config.database.loadSchema()
  726.     .then(schema => schema.deleteField('installationId', '_Installation'))
  727.     .catch(error => {
  728.       expect(error.code).toEqual(136);
  729.       expect(error.message).toEqual('field installationId cannot be changed');
  730.       done();
  731.     });
  732.   });
  733.  
  734.   it('refuses to delete fields from nonexistant classes', done => {
  735.     config.database.loadSchema()
  736.     .then(schema => schema.deleteField('field', 'NoClass'))
  737.     .catch(error => {
  738.       expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
  739.       expect(error.message).toEqual('Class NoClass does not exist.');
  740.       done();
  741.     });
  742.   });
  743.  
  744.   it('refuses to delete fields that dont exist', done => {
  745.     hasAllPODobject().save()
  746.     .then(() => config.database.loadSchema())
  747.     .then(schema => schema.deleteField('missingField', 'HasAllPOD'))
  748.     .fail(error => {
  749.       expect(error.code).toEqual(255);
  750.       expect(error.message).toEqual('Field missingField does not exist, cannot delete.');
  751.       done();
  752.     });
  753.   });
  754.  
  755.   it('drops related collection when deleting relation field', done => {
  756.     var obj1 = hasAllPODobject();
  757.     obj1.save()
  758.       .then(savedObj1 => {
  759.         var obj2 = new Parse.Object('HasPointersAndRelations');
  760.         obj2.set('aPointer', savedObj1);
  761.         var relation = obj2.relation('aRelation');
  762.         relation.add(obj1);
  763.         return obj2.save();
  764.       })
  765.       .then(() => config.database.collectionExists('_Join:aRelation:HasPointersAndRelations'))
  766.       .then(exists => {
  767.         if (!exists) {
  768.           fail('Relation collection ' +
  769.             'should exist after save.');
  770.         }
  771.       })
  772.       .then(() => config.database.loadSchema())
  773.       .then(schema => schema.deleteField('aRelation', 'HasPointersAndRelations', config.database))
  774.       .then(() => config.database.collectionExists('_Join:aRelation:HasPointersAndRelations'))
  775.       .then(exists => {
  776.         if (exists) {
  777.           fail('Relation collection should not exist after deleting relation field.');
  778.         }
  779.         done();
  780.       }, error => {
  781.         jfail(error);
  782.         done();
  783.       });
  784.   });
  785.  
  786.   it('can delete relation field when related _Join collection not exist', done => {
  787.     config.database.loadSchema()
  788.     .then(schema => {
  789.       schema.addClassIfNotExists('NewClass', {
  790.         relationField: {type: 'Relation', targetClass: '_User'}
  791.       })
  792.       .then(actualSchema => {
  793.         const expectedSchema = {
  794.           className: 'NewClass',
  795.           fields: {
  796.             objectId: { type: 'String' },
  797.             updatedAt: { type: 'Date' },
  798.             createdAt: { type: 'Date' },
  799.             ACL: { type: 'ACL' },
  800.             relationField: { type: 'Relation', targetClass: '_User' },
  801.           },
  802.           classLevelPermissions: {
  803.             find: { '*': true },
  804.             get: { '*': true },
  805.             create: { '*': true },
  806.             update: { '*': true },
  807.             delete: { '*': true },
  808.             addField: { '*': true },
  809.           },
  810.         };
  811.         expect(dd(actualSchema, expectedSchema)).toEqual(undefined);
  812.       })
  813.       .then(() => config.database.collectionExists('_Join:relationField:NewClass'))
  814.       .then(exist => {
  815.         on_db('postgres', () => {
  816.           // We create the table when creating the column
  817.           expect(exist).toEqual(true);
  818.         }, () => {
  819.           expect(exist).toEqual(false);
  820.         });
  821.  
  822.       })
  823.       .then(() => schema.deleteField('relationField', 'NewClass', config.database))
  824.       .then(() => schema.reloadData())
  825.       .then(() => {
  826.         const expectedSchema = {
  827.           objectId: { type: 'String' },
  828.           updatedAt: { type: 'Date' },
  829.           createdAt: { type: 'Date' },
  830.           ACL: { type: 'ACL' },
  831.         };
  832.         expect(dd(schema.data.NewClass, expectedSchema)).toEqual(undefined);
  833.         done();
  834.       });
  835.     });
  836.   });
  837.  
  838.   it('can delete string fields and resave as number field', done => {
  839.     Parse.Object.disableSingleInstance();
  840.     var obj1 = hasAllPODobject();
  841.     var obj2 = hasAllPODobject();
  842.     Parse.Object.saveAll([obj1, obj2])
  843.     .then(() => config.database.loadSchema())
  844.     .then(schema => schema.deleteField('aString', 'HasAllPOD', config.database))
  845.     .then(() => new Parse.Query('HasAllPOD').get(obj1.id))
  846.     .then(obj1Reloaded => {
  847.       expect(obj1Reloaded.get('aString')).toEqual(undefined);
  848.       obj1Reloaded.set('aString', ['not a string', 'this time']);
  849.       obj1Reloaded.save()
  850.       .then(obj1reloadedAgain => {
  851.         expect(obj1reloadedAgain.get('aString')).toEqual(['not a string', 'this time']);
  852.         return new Parse.Query('HasAllPOD').get(obj2.id);
  853.       })
  854.       .then(obj2reloaded => {
  855.         expect(obj2reloaded.get('aString')).toEqual(undefined);
  856.         done();
  857.         Parse.Object.enableSingleInstance();
  858.       });
  859.     })
  860.     .catch(error => {
  861.       jfail(error);
  862.       done();
  863.     });
  864.   });
  865.  
  866.   it('can delete pointer fields and resave as string', done => {
  867.     Parse.Object.disableSingleInstance();
  868.     var obj1 = new Parse.Object('NewClass');
  869.     obj1.save()
  870.     .then(() => {
  871.       obj1.set('aPointer', obj1);
  872.       return obj1.save();
  873.     })
  874.     .then(obj1 => {
  875.       expect(obj1.get('aPointer').id).toEqual(obj1.id);
  876.     })
  877.     .then(() => config.database.loadSchema())
  878.     .then(schema => schema.deleteField('aPointer', 'NewClass', config.database))
  879.     .then(() => new Parse.Query('NewClass').get(obj1.id))
  880.     .then(obj1 => {
  881.       expect(obj1.get('aPointer')).toEqual(undefined);
  882.       obj1.set('aPointer', 'Now a string');
  883.       return obj1.save();
  884.     })
  885.     .then(obj1 => {
  886.       expect(obj1.get('aPointer')).toEqual('Now a string');
  887.       done();
  888.       Parse.Object.enableSingleInstance();
  889.     });
  890.   });
  891.  
  892.   it('can merge schemas', done => {
  893.     expect(SchemaController.buildMergedSchemaObject({
  894.       _id: 'SomeClass',
  895.       someType: { type: 'Number' }
  896.     }, {
  897.       newType: {type: 'Number'}
  898.     })).toEqual({
  899.       someType: {type: 'Number'},
  900.       newType: {type: 'Number'},
  901.     });
  902.     done();
  903.   });
  904.  
  905.   it('can merge deletions', done => {
  906.     expect(SchemaController.buildMergedSchemaObject({
  907.       _id: 'SomeClass',
  908.       someType: { type: 'Number' },
  909.       outDatedType: { type: 'String' },
  910.     },{
  911.       newType: {type: 'GeoPoint'},
  912.       outDatedType: {__op: 'Delete'},
  913.     })).toEqual({
  914.       someType: {type: 'Number'},
  915.       newType: {type: 'GeoPoint'},
  916.     });
  917.     done();
  918.   });
  919.  
  920.   it('ignore default field when merge with system class', done => {
  921.     expect(SchemaController.buildMergedSchemaObject({
  922.       _id: '_User',
  923.       username: { type: 'String' },
  924.       password: { type: 'String' },
  925.       email: { type: 'String' },
  926.       emailVerified: { type: 'Boolean' },
  927.     },{
  928.       emailVerified: { type: 'String' },
  929.       customField: { type: 'String' },
  930.     })).toEqual({
  931.       customField: { type: 'String' }
  932.     });
  933.     done();
  934.   });
  935.  
  936.   it('yields a proper schema mismatch error (#2661)', done => {
  937.     const anObject = new Parse.Object('AnObject');
  938.     const anotherObject = new Parse.Object('AnotherObject');
  939.     const someObject = new Parse.Object('SomeObject');
  940.     Parse.Object.saveAll([anObject, anotherObject, someObject]).then(() => {
  941.       anObject.set('pointer', anotherObject);
  942.       return anObject.save();
  943.     }).then(() => {
  944.       anObject.set('pointer', someObject);
  945.       return anObject.save();
  946.     }).then(() => {
  947.       fail('shoud not save correctly');
  948.       done();
  949.     }, (err) => {
  950.       expect(err instanceof Parse.Error).toBeTruthy();
  951.       expect(err.message).toEqual('schema mismatch for AnObject.pointer; expected Pointer<AnotherObject> but got Pointer<SomeObject>')
  952.       done();
  953.     });
  954.   });
  955.  
  956.   it('yields a proper schema mismatch error bis (#2661)', done => {
  957.     const anObject = new Parse.Object('AnObject');
  958.     const someObject = new Parse.Object('SomeObject');
  959.     Parse.Object.saveAll([anObject, someObject]).then(() => {
  960.       anObject.set('number', 1);
  961.       return anObject.save();
  962.     }).then(() => {
  963.       anObject.set('number', someObject);
  964.       return anObject.save();
  965.     }).then(() => {
  966.       fail('shoud not save correctly');
  967.       done();
  968.     }, (err) => {
  969.       expect(err instanceof Parse.Error).toBeTruthy();
  970.       expect(err.message).toEqual('schema mismatch for AnObject.number; expected Number but got Pointer<SomeObject>')
  971.       done();
  972.     });
  973.   });
  974.  
  975.   it('yields a proper schema mismatch error ter (#2661)', done => {
  976.     const anObject = new Parse.Object('AnObject');
  977.     const someObject = new Parse.Object('SomeObject');
  978.     Parse.Object.saveAll([anObject, someObject]).then(() => {
  979.       anObject.set('pointer', someObject);
  980.       return anObject.save();
  981.     }).then(() => {
  982.       anObject.set('pointer', 1);
  983.       return anObject.save();
  984.     }).then(() => {
  985.       fail('shoud not save correctly');
  986.       done();
  987.     }, (err) => {
  988.       expect(err instanceof Parse.Error).toBeTruthy();
  989.       expect(err.message).toEqual('schema mismatch for AnObject.pointer; expected Pointer<SomeObject> but got Number')
  990.       done();
  991.     });
  992.   });
  993.  
  994.   it('properly handles volatile _Schemas', done => {
  995.     function validateSchemaStructure(schema) {
  996.       expect(schema.hasOwnProperty('className')).toBe(true);
  997.       expect(schema.hasOwnProperty('fields')).toBe(true);
  998.       expect(schema.hasOwnProperty('classLevelPermissions')).toBe(true);
  999.     }
  1000.     function validateSchemaDataStructure(schemaData) {
  1001.       Object.keys(schemaData).forEach(className => {
  1002.         const schema = schemaData[className];
  1003.         // Hooks has className...
  1004.         if (className != '_Hooks') {
  1005.           expect(schema.hasOwnProperty('className')).toBe(false);
  1006.         }
  1007.         expect(schema.hasOwnProperty('fields')).toBe(false);
  1008.         expect(schema.hasOwnProperty('classLevelPermissions')).toBe(false);
  1009.       });
  1010.     }
  1011.     let schema;
  1012.     config.database.loadSchema().then(s => {
  1013.       schema = s;
  1014.       return schema.getOneSchema('_User', false);
  1015.     }).then(userSchema => {
  1016.       validateSchemaStructure(userSchema);
  1017.       validateSchemaDataStructure(schema.data);
  1018.       return schema.getOneSchema('_PushStatus', true);
  1019.     }).then(pushStatusSchema => {
  1020.       validateSchemaStructure(pushStatusSchema);
  1021.       validateSchemaDataStructure(schema.data);
  1022.       done();
  1023.     });
  1024.   });
  1025. });
  1026.  
  1027. describe('Class Level Permissions for requiredAuth', () => {
  1028.  
  1029.   beforeEach(() => {
  1030.     config = new Config('test');
  1031.   });
  1032.  
  1033.   function createUser() {
  1034.     const user =  new Parse.User();
  1035.     user.set("username", "hello");
  1036.     user.set("password", "world");
  1037.     return user.signUp(null);
  1038.   }
  1039.  
  1040.   it('required auth test find', (done) => {
  1041.     config.database.loadSchema().then((schema) => {
  1042.       // Just to create a valid class
  1043.       return schema.validateObject('Stuff', {foo: 'bar'});
  1044.     }).then((schema) => {
  1045.       return schema.setPermissions('Stuff', {
  1046.         'find': {
  1047.           'requiresAuthentication': true
  1048.         }
  1049.       });
  1050.     }).then(() => {
  1051.       var query = new Parse.Query('Stuff');
  1052.       return query.find();
  1053.     }).then(() => {
  1054.       fail('Class permissions should have rejected this query.');
  1055.       done();
  1056.     }, (e) => {
  1057.       expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
  1058.       done();
  1059.     });
  1060.   });
  1061.  
  1062.   it('required auth test find authenticated', (done) => {
  1063.     config.database.loadSchema().then((schema) => {
  1064.       // Just to create a valid class
  1065.       return schema.validateObject('Stuff', {foo: 'bar'});
  1066.     }).then((schema) => {
  1067.       return schema.setPermissions('Stuff', {
  1068.         'find': {
  1069.           'requiresAuthentication': true
  1070.         }
  1071.       });
  1072.     }).then(() => {
  1073.       return createUser();
  1074.     }).then(() => {
  1075.       var query = new Parse.Query('Stuff');
  1076.       return query.find();
  1077.     }).then((results) => {
  1078.       expect(results.length).toEqual(0);
  1079.       done();
  1080.     }, (e) => {
  1081.       console.error(e);
  1082.       fail("Should not have failed");
  1083.       done();
  1084.     });
  1085.   });
  1086.  
  1087.   it('required auth should allow create authenticated', (done) => {
  1088.     config.database.loadSchema().then((schema) => {
  1089.       // Just to create a valid class
  1090.       return schema.validateObject('Stuff', {foo: 'bar'});
  1091.     }).then((schema) => {
  1092.       return schema.setPermissions('Stuff', {
  1093.         'create': {
  1094.           'requiresAuthentication': true
  1095.         }
  1096.       });
  1097.     }).then(() => {
  1098.       return createUser();
  1099.     }).then(() => {
  1100.       const stuff = new Parse.Object('Stuff');
  1101.       stuff.set('foo', 'bar');
  1102.       return stuff.save();
  1103.     }).then(() => {
  1104.       done();
  1105.     }, (e) => {
  1106.       console.error(e);
  1107.       fail("Should not have failed");
  1108.       done();
  1109.     });
  1110.   });
  1111.  
  1112.   it('required auth should reject create when not authenticated', (done) => {
  1113.     config.database.loadSchema().then((schema) => {
  1114.       // Just to create a valid class
  1115.       return schema.validateObject('Stuff', {foo: 'bar'});
  1116.     }).then((schema) => {
  1117.       return schema.setPermissions('Stuff', {
  1118.         'create': {
  1119.           'requiresAuthentication': true
  1120.         }
  1121.       });
  1122.     }).then(() => {
  1123.       const stuff = new Parse.Object('Stuff');
  1124.       stuff.set('foo', 'bar');
  1125.       return stuff.save();
  1126.     }).then(() => {
  1127.       fail('Class permissions should have rejected this query.');
  1128.       done();
  1129.     }, (e) => {
  1130.       expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
  1131.       done();
  1132.     });
  1133.   });
  1134.  
  1135.   it('required auth test create/get/update/delete authenticated', (done) => {
  1136.     config.database.loadSchema().then((schema) => {
  1137.       // Just to create a valid class
  1138.       return schema.validateObject('Stuff', {foo: 'bar'});
  1139.     }).then((schema) => {
  1140.       return schema.setPermissions('Stuff', {
  1141.         'create': {
  1142.           'requiresAuthentication': true
  1143.         },
  1144.         'get': {
  1145.           'requiresAuthentication': true
  1146.         },
  1147.         'delete': {
  1148.           'requiresAuthentication': true
  1149.         },
  1150.         'update': {
  1151.           'requiresAuthentication': true
  1152.         }
  1153.       });
  1154.     }).then(() => {
  1155.       return createUser();
  1156.     }).then(() => {
  1157.       const stuff = new Parse.Object('Stuff');
  1158.       stuff.set('foo', 'bar');
  1159.       return stuff.save().then(() => {
  1160.         const query = new Parse.Query('Stuff');
  1161.         return query.get(stuff.id);
  1162.       });
  1163.     }).then((gotStuff) => {
  1164.       return gotStuff.save({'foo': 'baz'}).then(() => {
  1165.         return gotStuff.destroy();
  1166.       })
  1167.     }).then(() => {
  1168.       done();
  1169.     }, (e) => {
  1170.       console.error(e);
  1171.       fail("Should not have failed");
  1172.       done();
  1173.     });
  1174.   });
  1175.  
  1176.   it('required auth test create/get/update/delete not authenitcated', (done) => {
  1177.     config.database.loadSchema().then((schema) => {
  1178.       // Just to create a valid class
  1179.       return schema.validateObject('Stuff', {foo: 'bar'});
  1180.     }).then((schema) => {
  1181.       return schema.setPermissions('Stuff', {
  1182.         'get': {
  1183.           'requiresAuthentication': true
  1184.         },
  1185.         'delete': {
  1186.           'requiresAuthentication': true
  1187.         },
  1188.         'update': {
  1189.           'requiresAuthentication': true
  1190.         },
  1191.         'create': {
  1192.           '*': true
  1193.         }
  1194.       });
  1195.     }).then(() => {
  1196.       const stuff = new Parse.Object('Stuff');
  1197.       stuff.set('foo', 'bar');
  1198.       return stuff.save().then(() => {
  1199.         const query = new Parse.Query('Stuff');
  1200.         return query.get(stuff.id);
  1201.       });
  1202.     }).then(() => {
  1203.       fail("Should not succeed!");
  1204.       done();
  1205.     }, (e) => {
  1206.       expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
  1207.       done();
  1208.     });
  1209.   });
  1210.  
  1211.   it('required auth test create/get/update/delete not authenitcated', (done) => {
  1212.     config.database.loadSchema().then((schema) => {
  1213.       // Just to create a valid class
  1214.       return schema.validateObject('Stuff', {foo: 'bar'});
  1215.     }).then((schema) => {
  1216.       return schema.setPermissions('Stuff', {
  1217.         'find': {
  1218.           'requiresAuthentication': true
  1219.         },
  1220.         'delete': {
  1221.           'requiresAuthentication': true
  1222.         },
  1223.         'update': {
  1224.           'requiresAuthentication': true
  1225.         },
  1226.         'create': {
  1227.           '*': true
  1228.         },
  1229.         'get': {
  1230.           '*': true
  1231.         }
  1232.       });
  1233.     }).then(() => {
  1234.       const stuff = new Parse.Object('Stuff');
  1235.       stuff.set('foo', 'bar');
  1236.       return stuff.save().then(() => {
  1237.         const query = new Parse.Query('Stuff');
  1238.         return query.get(stuff.id);
  1239.       })
  1240.     }).then((result) => {
  1241.       expect(result.get('foo')).toEqual('bar');
  1242.       const query = new Parse.Query('Stuff');
  1243.       return query.find();
  1244.     }).then(() => {
  1245.       fail("Should not succeed!");
  1246.       done();
  1247.     }, (e) => {
  1248.       expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
  1249.       done();
  1250.     });
  1251.   });
  1252.  
  1253.   it('required auth test create/get/update/delete with roles (#3753)', (done) => {
  1254.     let user;
  1255.     config.database.loadSchema().then((schema) => {
  1256.       // Just to create a valid class
  1257.       return schema.validateObject('Stuff', {foo: 'bar'});
  1258.     }).then((schema) => {
  1259.       return schema.setPermissions('Stuff', {
  1260.         'find': {
  1261.           'requiresAuthentication': true,
  1262.           'role:admin': true
  1263.         },
  1264.         'create': { 'role:admin': true },
  1265.         'update': { 'role:admin': true },
  1266.         'delete': { 'role:admin': true },
  1267.         'get': {
  1268.           'requiresAuthentication': true,
  1269.           'role:admin': true
  1270.         }
  1271.       });
  1272.     }).then(() => {
  1273.       const stuff = new Parse.Object('Stuff');
  1274.       stuff.set('foo', 'bar');
  1275.       return stuff.save(null, {useMasterKey: true}).then(() => {
  1276.         const query = new Parse.Query('Stuff');
  1277.         return query.get(stuff.id).then(() => {
  1278.           done.fail('should not succeed');
  1279.         }, () => {
  1280.           return new Parse.Query('Stuff').find();
  1281.         }).then(() => {
  1282.           done.fail('should not succeed');
  1283.         }, () => {
  1284.           return Promise.resolve();
  1285.         });
  1286.       }).then(() => {
  1287.         return Parse.User.signUp('user', 'password').then((signedUpUser) => {
  1288.           user = signedUpUser;
  1289.           const query = new Parse.Query('Stuff');
  1290.           return query.get(stuff.id, {sessionToken: user.getSessionToken()});
  1291.         });
  1292.       });
  1293.     }).then((result) => {
  1294.       expect(result.get('foo')).toEqual('bar');
  1295.       const query = new Parse.Query('Stuff');
  1296.       return query.find({sessionToken: user.getSessionToken()});
  1297.     }).then((results) => {
  1298.       expect(results.length).toBe(1);
  1299.       done();
  1300.     }, (e) => {
  1301.       console.error(e);
  1302.       done.fail(e);
  1303.     });
  1304.   });
  1305. })
  1306.  
downloadSchema.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