diff --git a/.travis.yml b/.travis.yml index ee210a2a84..3acf7f1295 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,8 @@ addons: before_script: - ls -al "$HOME/.mongodb/versions" - psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres + - psql -c 'CREATE EXTENSION postgis;' -U postgres -d parse_server_postgres_adapter_test_database + - psql -c 'CREATE EXTENSION postgis_topology;' -U postgres -d parse_server_postgres_adapter_test_database env: global: - COVERAGE_OPTION='./node_modules/.bin/istanbul cover' @@ -26,7 +28,8 @@ branches: cache: directories: - "$HOME/.mongodb/versions" -after_script: "./node_modules/.bin/codecov" +after_script: +- bash <(curl -s https://codecov.io/bash) deploy: provider: npm email: diff --git a/package.json b/package.json index 88ebe1f3fa..b1698f5795 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,8 @@ "license": "BSD-3-Clause", "dependencies": { "babel-polyfill": "6.13.0", - "babel-runtime": "6.11.6", "bcrypt-nodejs": "0.0.3", "body-parser": "1.15.2", - "colors": "1.1.2", "commander": "2.9.0", "deepcopy": "0.6.3", "express": "4.14.0", @@ -41,7 +39,6 @@ "pg-promise": "5.2.7", "redis": "2.6.2", "request": "2.74.0", - "request-promise": "4.1.1", "semver": "5.2.0", "tv4": "1.2.7", "winston": "2.2.0", @@ -56,22 +53,20 @@ "babel-preset-es2015": "6.13.2", "babel-preset-stage-0": "6.5.0", "babel-register": "6.11.6", - "codecov": "1.0.1", "cross-env": "2.0.0", "deep-diff": "0.3.4", "gaze": "1.1.1", "istanbul": "1.0.0-alpha.1", "jasmine": "2.4.1", "mongodb-runner": "3.3.2", - "nodemon": "1.10.0" + "nodemon": "1.10.0", + "request-promise": "^4.1.1" }, "scripts": { "dev": "npm run build && node bin/dev", "build": "babel src/ -d lib/", - "pretest": "test -z \"$PARSE_SERVER_TEST_DB\" && cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 mongodb-runner start || echo", - "test": "cross-env NODE_ENV=test TESTING=1 babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js", + "test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js", "test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/jasmine/bin/jasmine.js && npm run posttest", - "posttest": "mongodb-runner stop", "coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test", "coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest", "start": "node ./bin/parse-server", diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 4a2c93d324..973deba399 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -722,7 +722,7 @@ it('beforeSave should not affect fetched pointers', done => { }); }); - it_exclude_dbs(['postgres'])('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { + it('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { var TestObject = Parse.Object.extend('TestObject'); var NoBeforeSaveObject = Parse.Object.extend('NoBeforeSave'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); @@ -746,7 +746,7 @@ it('beforeSave should not affect fetched pointers', done => { }) .then(object => { res.success(object); - }); + }).catch(res.error); }); Parse.Cloud.define('removeme2', (req, res) => { @@ -762,7 +762,7 @@ it('beforeSave should not affect fetched pointers', done => { }) .then(object => { res.success(object); - }); + }).catch(res.error); }); Parse.Cloud.run('removeme') @@ -775,10 +775,13 @@ it('beforeSave should not affect fetched pointers', done => { expect(aBeforeSaveObj.get('before')).toEqual('save'); expect(aBeforeSaveObj.get('remove')).toEqual(undefined); done(); + }).catch((err) => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { + it('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { var TestObject = Parse.Object.extend('TestObject'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); @@ -802,12 +805,12 @@ it('beforeSave should not affect fetched pointers', done => { expect(object.get('remove')).toBeUndefined(); done(); }).fail((err) => { - console.error(err); + jfail(err); done(); - }) + }); }); - it_exclude_dbs(['postgres'])('should not include relation op (regression test for #1606)', done => { + it('should not include relation op (regression test for #1606)', done => { var TestObject = Parse.Object.extend('TestObject'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); let testObj; @@ -818,7 +821,7 @@ it('beforeSave should not affect fetched pointers', done => { testObj.save().then(() => { object.relation('testsRelation').add(testObj); res.success(); - }) + }, res.error); }); let object = new BeforeSaveObject(); @@ -827,7 +830,7 @@ it('beforeSave should not affect fetched pointers', done => { expect(() => { objectAgain.relation('testsRelation') }).not.toThrow(); done(); }).fail((err) => { - console.error(err); + jfail(err); done(); }) }); diff --git a/spec/EmailVerificationToken.spec.js b/spec/EmailVerificationToken.spec.js index 93acc2ea82..e444db445c 100644 --- a/spec/EmailVerificationToken.spec.js +++ b/spec/EmailVerificationToken.spec.js @@ -2,11 +2,11 @@ const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions'); const request = require('request'); -const MongoClient = require("mongodb").MongoClient; +const Config = require('../src/Config'); describe("Email Verification Token Expiration: ", () => { - it_exclude_dbs(['postgres'])('show the invalid link page, if the user clicks on the verify email link after the email verify token expires', done => { + it('show the invalid link page, if the user clicks on the verify email link after the email verify token expires', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -41,10 +41,13 @@ describe("Email Verification Token Expiration: ", () => { done(); }); }, 1000); + }).catch((err) => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])('emailVerified should set to false, if the user does not verify their email before the email verify token expires', done => { + it('emailVerified should set to false, if the user does not verify their email before the email verify token expires', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -81,15 +84,18 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch((err) => { - fail("this should not fail"); + jfail(error); done(); }); }); }, 1000); + }).catch((err) => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then show the verify email success page', done => { + it('if user clicks on the email verify link before email verification token expiration then show the verify email success page', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -119,10 +125,13 @@ describe("Email Verification Token Expiration: ", () => { expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=testEmailVerifyTokenValidity'); done(); }); + }).catch((err) => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then emailVerified should be true', done => { + it('if user clicks on the email verify link before email verification token expiration then emailVerified should be true', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -155,14 +164,17 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch((err) => { - fail("this should not fail"); + jfail(error); done(); }); }); + }).catch((err) => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then user should be able to login', done => { + it('if user clicks on the email verify link before email verification token expiration then user should be able to login', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -196,14 +208,17 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch((error) => { - fail('login should have succeeded'); + jfail(error); done(); }); }); + }).catch((err) => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('sets the _email_verify_token_expires_at and _email_verify_token fields after user SignUp', done => { + it('sets the _email_verify_token_expires_at and _email_verify_token fields after user SignUp', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -227,14 +242,12 @@ describe("Email Verification Token Expiration: ", () => { return user.signUp(); }) .then(() => { - const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; - return MongoClient.connect(databaseURI); - }) - .then(database => { - expect(typeof database).toBe('object'); - return database.collection('test__User').findOne({username: 'sets_email_verify_token_expires_at'}); + let config = new Config('test'); + return config.database.find('_User', {username: 'sets_email_verify_token_expires_at'}); }) - .then(user => { + .then(results => { + expect(results.length).toBe(1); + let user = results[0]; expect(typeof user).toBe('object'); expect(user.emailVerified).toEqual(false); expect(typeof user._email_verify_token).toBe('string'); @@ -242,12 +255,12 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch(error => { - fail("this should not fail"); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => { + it('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -275,12 +288,10 @@ describe("Email Verification Token Expiration: ", () => { followRedirect: false, }, (error, response, body) => { expect(response.statusCode).toEqual(302); - - const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; - MongoClient.connect(databaseURI) - .then(database => { - expect(typeof database).toBe('object'); - return database.collection('test__User').findOne({username: 'unsets_email_verify_token_expires_at'}); + let config = new Config('test'); + return config.database.find('_User', {username: 'unsets_email_verify_token_expires_at'}).then((results) => { + expect(results.length).toBe(1); + return results[0]; }) .then(user => { expect(typeof user).toBe('object'); @@ -290,18 +301,18 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch(error => { - fail("this should not fail"); + jfail(error); done(); }); }); }) .catch(error => { - fail("this should not fail"); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('clicking on the email verify link by an email VERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { + it('clicking on the email verify link by an email VERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -352,12 +363,12 @@ describe("Email Verification Token Expiration: ", () => { }); }) .catch((err) => { - fail("this should not fail"); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('clicking on the email verify link by an email UNVERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { + it('clicking on the email verify link by an email UNVERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -402,14 +413,13 @@ describe("Email Verification Token Expiration: ", () => { }); }) .catch((err) => { - fail("this should not fail"); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('setting the email on the user should set a new email verification token and new expiration date for the token when expire email verify token flag is set', done => { + it('setting the email on the user should set a new email verification token and new expiration date for the token when expire email verify token flag is set', done => { - const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; let db; let user = new Parse.User(); @@ -439,12 +449,10 @@ describe("Email Verification Token Expiration: ", () => { return user.signUp(); }) .then(() => { - return MongoClient.connect(databaseURI); - }) - .then(database => { - expect(typeof database).toBe('object'); - db = database; //save the db object for later use - return db.collection('test__User').findOne({username: 'newEmailVerifyTokenOnEmailReset'}); + let config = new Config('test'); + return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => { + return results[0]; + }); }) .then(userFromDb => { expect(typeof userFromDb).toBe('object'); @@ -458,8 +466,10 @@ describe("Email Verification Token Expiration: ", () => { }); }) .then(() => { - // get user data after email reset and new token generation - return db.collection('test__User').findOne({username: 'newEmailVerifyTokenOnEmailReset'}); + let config = new Config('test'); + return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => { + return results[0]; + }); }) .then(userAfterEmailReset => { expect(typeof userAfterEmailReset).toBe('object'); @@ -468,12 +478,12 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch((err) => { - fail("this should not fail"); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('client should not see the _email_verify_token_expires_at field', done => { + it('client should not see the _email_verify_token_expires_at field', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -505,10 +515,13 @@ describe("Email Verification Token Expiration: ", () => { done(); }) .catch(error => { - fail("this should not fail"); + jfail(error); done(); }); + }).catch((err) => { + jfail(error); + done(); }); }); diff --git a/spec/GridStoreAdapter.js b/spec/GridStoreAdapter.js index 78c848f33b..dd63a4d4d0 100644 --- a/spec/GridStoreAdapter.js +++ b/spec/GridStoreAdapter.js @@ -7,7 +7,7 @@ var FilesController = require('../src/Controllers/FilesController').default; // Small additional tests to improve overall coverage -describe("GridStoreAdapter",() =>{ +describe_only_db('mongo')("GridStoreAdapter",() =>{ it("should properly instanciate the GridStore when deleting a file", (done) => { var databaseURI = 'mongodb://localhost:27017/parse'; diff --git a/spec/InstallationsRouter.spec.js b/spec/InstallationsRouter.spec.js index b2725a09af..3ebfbca68f 100644 --- a/spec/InstallationsRouter.spec.js +++ b/spec/InstallationsRouter.spec.js @@ -3,10 +3,9 @@ var Config = require('../src/Config'); var rest = require('../src/rest'); var InstallationsRouter = require('../src/Routers/InstallationsRouter').InstallationsRouter; -var config = new Config('test'); - -describe_only_db(['mongo'])('InstallationsRouter', () => { +describe('InstallationsRouter', () => { it('uses find condition from request.body', (done) => { + var config = new Config('test'); var androidDeviceRequest = { 'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'deviceType': 'android' @@ -37,10 +36,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => { var results = res.response.results; expect(results.length).toEqual(1); done(); + }).catch((err) => { + fail(JSON.stringify(err)); + done(); }); }); it('uses find condition from request.query', (done) => { + var config = new Config('test'); var androidDeviceRequest = { 'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'deviceType': 'android' @@ -72,12 +75,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => { expect(results.length).toEqual(1); done(); }).catch((err) => { + console.error(err); fail(JSON.stringify(err)); done(); }); }); it('query installations with limit = 0', (done) => { + var config = new Config('test'); var androidDeviceRequest = { 'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'deviceType': 'android' @@ -96,6 +101,7 @@ describe_only_db(['mongo'])('InstallationsRouter', () => { info: {} }; + var config = new Config('test'); var router = new InstallationsRouter(); rest.create(config, auth.nobody(config), '_Installation', androidDeviceRequest) .then(() => { @@ -106,10 +112,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => { var response = res.response; expect(response.results.length).toEqual(0); done(); + }).catch((err) => { + fail(JSON.stringify(err)); + done(); }); }); it('query installations with count = 1', done => { + var config = new Config('test'); var androidDeviceRequest = { 'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'deviceType': 'android' @@ -145,6 +155,7 @@ describe_only_db(['mongo'])('InstallationsRouter', () => { }); it('query installations with limit = 0 and count = 1', (done) => { + var config = new Config('test'); var androidDeviceRequest = { 'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'deviceType': 'android' diff --git a/spec/LoggerController.spec.js b/spec/LoggerController.spec.js index 2d773db8c4..72e4448b5b 100644 --- a/spec/LoggerController.spec.js +++ b/spec/LoggerController.spec.js @@ -13,8 +13,7 @@ describe('LoggerController', () => { expect(res.length).not.toBe(0); done(); }).catch((err) => { - console.error(err); - fail("should not fail"); + jfail(err); done(); }) }).not.toThrow(); @@ -76,7 +75,7 @@ describe('LoggerController', () => { expect(res.length).toBe(0); done(); }).catch((err) => { - console.error(err); + jfail(err); fail("should not fail"); done(); }) diff --git a/spec/OAuth.spec.js b/spec/OAuth.spec.js index 01e714e320..324104df39 100644 --- a/spec/OAuth.spec.js +++ b/spec/OAuth.spec.js @@ -217,7 +217,7 @@ describe('OAuth', function() { return request.post(options, callback); } - it_exclude_dbs(['postgres'])("should create user with REST API", done => { + it("should create user with REST API", done => { createOAuthUser((error, response, body) => { expect(error).toBe(null); var b = JSON.parse(body); @@ -228,6 +228,11 @@ describe('OAuth', function() { var q = new Parse.Query("_Session"); q.equalTo('sessionToken', sessionToken); q.first({useMasterKey: true}).then((res) => { + if (!res) { + fail('should not fail fetching the session'); + done(); + return; + } expect(res.get("installationId")).toEqual('yolo'); done(); }).fail((err) => { @@ -237,7 +242,7 @@ describe('OAuth', function() { }); }); - it_exclude_dbs(['postgres'])("should only create a single user with REST API", (done) => { + it("should only create a single user with REST API", (done) => { var objectId; createOAuthUser((error, response, body) => { expect(error).toBe(null); @@ -257,7 +262,7 @@ describe('OAuth', function() { }); }); - it_exclude_dbs(['postgres'])("unlink and link with custom provider", (done) => { + it("unlink and link with custom provider", (done) => { var provider = getMockMyOauthProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("myoauth", { diff --git a/spec/Parse.Push.spec.js b/spec/Parse.Push.spec.js index d0bad72835..51e6f3c587 100644 --- a/spec/Parse.Push.spec.js +++ b/spec/Parse.Push.spec.js @@ -47,10 +47,12 @@ describe('Parse.Push', () => { installations.push(installation); } return Parse.Object.saveAll(installations); - }); + }).catch((err) => { + console.error(err); + }) } - it_exclude_dbs(['postgres'])('should properly send push', (done) => { + it('should properly send push', (done) => { return setup().then(() => { return Parse.Push.send({ where: { @@ -64,14 +66,13 @@ describe('Parse.Push', () => { }) .then(() => { done(); - }, (err) => { - console.error(); - fail('should not fail sending push') + }).catch((err) => { + jfail(err); done(); }); }); - it_exclude_dbs(['postgres'])('should properly send push with lowercaseIncrement', (done) => { + it('should properly send push with lowercaseIncrement', (done) => { return setup().then(() => { return Parse.Push.send({ where: { @@ -84,14 +85,13 @@ describe('Parse.Push', () => { }, {useMasterKey: true}) }).then(() => { done(); - }, (err) => { - console.error(); - fail('should not fail sending push') + }).catch((err) => { + jfail(err); done(); }); }); - it_exclude_dbs(['postgres'])('should not allow clients to query _PushStatus', done => { + it('should not allow clients to query _PushStatus', done => { setup() .then(() => Parse.Push.send({ where: { @@ -113,10 +113,13 @@ describe('Parse.Push', () => { expect(body.error).toEqual('unauthorized'); done(); }); + }).catch((err) => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])('should allow master key to query _PushStatus', done => { + it('should allow master key to query _PushStatus', done => { setup() .then(() => Parse.Push.send({ where: { @@ -136,15 +139,22 @@ describe('Parse.Push', () => { 'X-Parse-Master-Key': 'test', }, }, (error, response, body) => { - expect(body.results.length).toEqual(1); - expect(body.results[0].query).toEqual('{"deviceType":"ios"}'); - expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}'); + try { + expect(body.results.length).toEqual(1); + expect(body.results[0].query).toEqual('{"deviceType":"ios"}'); + expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}'); + } catch(e) { + jfail(e); + } done(); }); + }).catch((err) => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])('should throw error if missing push configuration', done => { + it('should throw error if missing push configuration', done => { reconfigureServer({push: null}) .then(() => { return Parse.Push.send({ @@ -161,6 +171,9 @@ describe('Parse.Push', () => { }, (err) => { expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED); done(); + }).catch((err) => { + jfail(err); + done(); }); }); }); diff --git a/spec/ParseACL.spec.js b/spec/ParseACL.spec.js index 5b5a3c8677..878cf185de 100644 --- a/spec/ParseACL.spec.js +++ b/spec/ParseACL.spec.js @@ -155,7 +155,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl an object owned by one user and public delete", (done) => { + it("acl an object owned by one user and public delete", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -359,7 +359,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly readable and public get", (done) => { + it("acl making an object publicly readable and public get", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -407,7 +407,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly readable and public find", (done) => { + it("acl making an object publicly readable and public find", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -457,7 +457,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly readable and public update", (done) => { + it("acl making an object publicly readable and public update", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -504,7 +504,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly readable and public delete", (done) => { + it("acl making an object publicly readable and public delete", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -548,7 +548,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly writable and public get", (done) => { + it("acl making an object publicly writable and public get", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -595,7 +595,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly writable and public find", (done) => { + it("acl making an object publicly writable and public find", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -642,7 +642,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly writable and public update", (done) => { + it("acl making an object publicly writable and public update", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -688,7 +688,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl making an object publicly writable and public delete", (done) => { + it("acl making an object publicly writable and public delete", (done) => { // Create an object owned by Alice. var user = new Parse.User(); user.set("username", "alice"); @@ -1051,7 +1051,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl sharing with another user and public delete", (done) => { + it("acl sharing with another user and public delete", (done) => { // Sign in as Bob. Parse.User.signUp("bob", "pass", null, { success: function(bob) { @@ -1093,7 +1093,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])("acl saveAll with permissions", (done) => { + it("acl saveAll with permissions", (done) => { Parse.User.signUp("alice", "wonderland", null, { success: function(alice) { var acl = new Parse.ACL(alice); @@ -1202,7 +1202,7 @@ describe('Parse.ACL', () => { }); }); - it_exclude_dbs(['postgres'])('regression test #701', done => { + it('regression test #701', done => { var anonUser = { authData: { anonymous: { diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 6100709954..849afe72be 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -13,6 +13,31 @@ const deepcopy = require('deepcopy'); const userSchema = SchemaController.convertSchemaToAdapterSchema({ className: '_User', fields: Object.assign({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._User) }); +describe_only_db('mongo')('miscellaneous', () => { + it('test rest_create_app', function(done) { + var appId; + Parse._request('POST', 'rest_create_app').then((res) => { + expect(typeof res.application_id).toEqual('string'); + expect(res.master_key).toEqual('master'); + appId = res.application_id; + Parse.initialize(appId, 'unused'); + var obj = new Parse.Object('TestObject'); + obj.set('foo', 'bar'); + return obj.save(); + }).then(() => { + let config = new Config(appId); + return config.database.adapter.find('TestObject', { fields: {} }, {}, {}); + }).then((results) => { + expect(results.length).toEqual(1); + expect(results[0]['foo']).toEqual('bar'); + done(); + }).fail(error => { + fail(JSON.stringify(error)); + done(); + }) + }); +}) + describe('miscellaneous', function() { it('create a GameScore object', function(done) { var obj = new Parse.Object('GameScore'); @@ -88,7 +113,7 @@ describe('miscellaneous', function() { .catch(done); }); - it('ensure that email is uniquely indexed', done => { + it_exclude_dbs(['postgres'])('ensure that email is uniquely indexed', done => { let numFailed = 0; let numCreated = 0; let user1 = new Parse.User(); @@ -127,7 +152,7 @@ describe('miscellaneous', function() { .catch(done); }); - it_exclude_dbs(['postgres'])('ensure that if people already have duplicate users, they can still sign up new users', done => { + it('ensure that if people already have duplicate users, they can still sign up new users', done => { let config = new Config('test'); // Remove existing data to clear out unique index TestUtils.destroyAllDataPermanently() @@ -347,29 +372,6 @@ describe('miscellaneous', function() { }); }); - it_exclude_dbs(['postgres'])('test rest_create_app', function(done) { - var appId; - Parse._request('POST', 'rest_create_app').then((res) => { - expect(typeof res.application_id).toEqual('string'); - expect(res.master_key).toEqual('master'); - appId = res.application_id; - Parse.initialize(appId, 'unused'); - var obj = new Parse.Object('TestObject'); - obj.set('foo', 'bar'); - return obj.save(); - }).then(() => { - let config = new Config(appId); - return config.database.adapter.find('TestObject', { fields: {} }, {}, {}); - }).then((results) => { - expect(results.length).toEqual(1); - expect(results[0]['foo']).toEqual('bar'); - done(); - }).fail(error => { - fail(JSON.stringify(error)); - done(); - }) - }); - it('object is set on create and update', done => { let triggerTime = 0; // Register a mock beforeSave hook @@ -647,8 +649,7 @@ describe('miscellaneous', function() { expect(triggerTime).toBe(2); done(); }, function(error) { - console.error(error); - fail(error); + jfail(error); done(); }); }); @@ -695,8 +696,7 @@ describe('miscellaneous', function() { expect(triggerTime).toBe(2); done(); }, function(error) { - console.error(error); - fail(error); + jfail(error); done(); }); }); @@ -733,13 +733,12 @@ describe('miscellaneous', function() { expect(triggerTime).toBe(2); done(); }, error => { - console.error(error); - fail(error); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('beforeSave receives ACL', done => { + it('beforeSave receives ACL', done => { let triggerTime = 0; // Register a mock beforeSave hook Parse.Cloud.beforeSave('GameScore', function(req, res) { @@ -773,13 +772,12 @@ describe('miscellaneous', function() { expect(triggerTime).toBe(2); done(); }, error => { - console.error(error); - fail(error); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('afterSave receives ACL', done => { + it('afterSave receives ACL', done => { let triggerTime = 0; // Register a mock beforeSave hook Parse.Cloud.afterSave('GameScore', function(req, res) { @@ -813,8 +811,7 @@ describe('miscellaneous', function() { expect(triggerTime).toBe(2); done(); }, error => { - console.error(error); - fail(error); + jfail(error); done(); }); }); @@ -840,21 +837,25 @@ describe('miscellaneous', function() { selfThing: {"__type":"Pointer","className":"GameScore","objectId":obj.id}, }) }, (error, response, body) => { - body = JSON.parse(body); - expect(body.a).toBeUndefined(); - expect(body.c).toEqual(3); // 2+1 - expect(body.d.length).toBe(2); - expect(body.d.indexOf('1') > -1).toBe(true); - expect(body.d.indexOf('2') > -1).toBe(true); - expect(body.e.length).toBe(2); - expect(body.e.indexOf('1') > -1).toBe(true); - expect(body.e.indexOf('2') > -1).toBe(true); - expect(body.f.length).toBe(1); - expect(body.f.indexOf('1') > -1).toBe(true); - // return nothing on other self - expect(body.selfThing).toBeUndefined(); - // updatedAt is always set - expect(body.updatedAt).not.toBeUndefined(); + try { + body = JSON.parse(body); + expect(body.a).toBeUndefined(); + expect(body.c).toEqual(3); // 2+1 + expect(body.d.length).toBe(2); + expect(body.d.indexOf('1') > -1).toBe(true); + expect(body.d.indexOf('2') > -1).toBe(true); + expect(body.e.length).toBe(2); + expect(body.e.indexOf('1') > -1).toBe(true); + expect(body.e.indexOf('2') > -1).toBe(true); + expect(body.f.length).toBe(1); + expect(body.f.indexOf('1') > -1).toBe(true); + // return nothing on other self + expect(body.selfThing).toBeUndefined(); + // updatedAt is always set + expect(body.updatedAt).not.toBeUndefined(); + }catch(e) { + jfail(e); + } done(); }); }).fail((err) => { @@ -1189,7 +1190,7 @@ describe('miscellaneous', function() { }); }); - it_exclude_dbs(['postgres'])('gets relation fields', (done) => { + it('gets relation fields', (done) => { let object = new Parse.Object('AnObject'); let relatedObject = new Parse.Object('RelatedObject'); Parse.Object.saveAll([object, relatedObject]).then(() => { @@ -1215,6 +1216,9 @@ describe('miscellaneous', function() { }) done(); }); + }).catch((err) => { + jfail(err); + done(); }) }); @@ -1304,25 +1308,34 @@ describe('miscellaneous', function() { it_exclude_dbs(['postgres'])('bans interior keys containing . or $', done => { new Parse.Object('Obj').save({innerObj: {'key with a $': 'fails'}}) - .catch(error => { + .then(() => { + fail('should not succeed') + }, error => { expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); return new Parse.Object('Obj').save({innerObj: {'key with a .': 'fails'}}); }) - .catch(error => { + .then(() => { + fail('should not succeed') + }, error => { expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with $': 'fails'}}}); }) - .catch(error => { + .then(() => { + fail('should not succeed') + }, error => { expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with .': 'fails'}}}); }) - .catch(error => { + .then(() => { + fail('should not succeed') + done(); + }, error => { expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); done(); - }) + }); }); - it_exclude_dbs(['postgres'])('does not change inner object keys named _auth_data_something', done => { + it('does not change inner object keys named _auth_data_something', done => { new Parse.Object('O').save({ innerObj: {_auth_data_facebook: 7}}) .then(object => new Parse.Query('O').get(object.id)) .then(object => { @@ -1369,10 +1382,13 @@ describe('miscellaneous', function() { geoField: [1,2], }); done(); + }).catch((e) => { + jfail(e); + done(); }); }); - it_exclude_dbs(['postgres'])('purge all objects in class', (done) => { + it('purge all objects in class', (done) => { let object = new Parse.Object('TestObject'); object.set('foo', 'bar'); let object2 = new Parse.Object('TestObject'); @@ -1422,7 +1438,7 @@ describe('miscellaneous', function() { }); }); - it_exclude_dbs(['postgres'])('purge all objects in _Role also purge cache', (done) => { + it('purge all objects in _Role also purge cache', (done) => { let headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': 'test', diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index c37377ffe3..e329a3136a 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -11,9 +11,9 @@ for (var i = 0; i < str.length; i++) { data.push(str.charCodeAt(i)); } -describe('Parse.File testing', () => { - describe('creating files', () => { - it_exclude_dbs(['postgres'])('works with Content-Type', done => { +describe_only_db('mongo')('Parse.File testing', () => { + describe_only_db('mongo')('creating files', () => { + it('works with Content-Type', done => { var headers = { 'Content-Type': 'application/octet-stream', 'X-Parse-Application-Id': 'test', @@ -37,7 +37,7 @@ describe('Parse.File testing', () => { }); - it_exclude_dbs(['postgres'])('works with _ContentType', done => { + it('works with _ContentType', done => { request.post({ url: 'http://localhost:8378/1/files/file', @@ -53,15 +53,19 @@ describe('Parse.File testing', () => { expect(b.name).toMatch(/_file.html/); expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/); request.get(b.url, (error, response, body) => { - expect(response.headers['content-type']).toMatch('^text/html'); - expect(error).toBe(null); - expect(body).toEqual('\n'); + try { + expect(response.headers['content-type']).toMatch('^text/html'); + expect(error).toBe(null); + expect(body).toEqual('\n'); + } catch(e) { + jfail(e); + } done(); }); }); }); - it_exclude_dbs(['postgres'])('works without Content-Type', done => { + it('works without Content-Type', done => { var headers = { 'X-Parse-Application-Id': 'test', 'X-Parse-REST-API-Key': 'rest' @@ -120,7 +124,11 @@ describe('Parse.File testing', () => { url: b.url }, (error, response, body) => { expect(error).toBe(null); - expect(response.statusCode).toEqual(404); + try { + expect(response.statusCode).toEqual(404); + } catch(e) { + jfail(e); + } done(); }); }); @@ -128,7 +136,7 @@ describe('Parse.File testing', () => { }); }); - it_exclude_dbs(['postgres'])('blocks file deletions with missing or incorrect master-key header', done => { + it('blocks file deletions with missing or incorrect master-key header', done => { var headers = { 'Content-Type': 'image/jpeg', 'X-Parse-Application-Id': 'test', @@ -173,7 +181,7 @@ describe('Parse.File testing', () => { }); }); - it_exclude_dbs(['postgres'])('handles other filetypes', done => { + it('handles other filetypes', done => { var headers = { 'Content-Type': 'image/jpeg', 'X-Parse-Application-Id': 'test', @@ -207,10 +215,10 @@ describe('Parse.File testing', () => { notEqual(file.name(), "hello.txt"); done(); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("save file in object", done => { + it("save file in object", done => { var file = new Parse.File("hello.txt", data, "text/plain"); ok(!file.url()); file.save(expectSuccess({ @@ -232,12 +240,12 @@ describe('Parse.File testing', () => { } })); } - })); + }, done)); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("save file in object with escaped characters in filename", done => { + it("save file in object with escaped characters in filename", done => { var file = new Parse.File("hello . txt", data, "text/plain"); ok(!file.url()); file.save(expectSuccess({ @@ -260,9 +268,9 @@ describe('Parse.File testing', () => { } })); } - })); + }, done)); } - })); + }, done)); }); it_exclude_dbs(['postgres'])("autosave file in object", done => { @@ -282,12 +290,12 @@ describe('Parse.File testing', () => { notEqual(file.name(), "hello.txt"); done(); } - })); + }, done)); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("autosave file in object in object", done => { + it("autosave file in object in object", done => { var file = new Parse.File("hello.txt", data, "text/plain"); ok(!file.url()); @@ -311,12 +319,12 @@ describe('Parse.File testing', () => { notEqual(file.name(), "hello.txt"); done(); } - })); + }, done)); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("saving an already saved file", done => { + it("saving an already saved file", done => { var file = new Parse.File("hello.txt", data, "text/plain"); ok(!file.url()); file.save(expectSuccess({ @@ -332,12 +340,12 @@ describe('Parse.File testing', () => { equal(file.name(), previousName); done(); } - })); + }, done)); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("two saves at the same time", done => { + it("two saves at the same time", done => { var file = new Parse.File("hello.txt", data, "text/plain"); var firstName; @@ -355,7 +363,7 @@ describe('Parse.File testing', () => { }); }); - it_exclude_dbs(['postgres'])("file toJSON testing", done => { + it("file toJSON testing", done => { var file = new Parse.File("hello.txt", data, "text/plain"); ok(!file.url()); var object = new Parse.Object("TestObject"); @@ -366,10 +374,10 @@ describe('Parse.File testing', () => { ok(object.toJSON().file.url); done(); } - })); + }, done)); }); - it_exclude_dbs(['postgres'])("content-type used with no extension", done => { + it("content-type used with no extension", done => { var headers = { 'Content-Type': 'text/html', 'X-Parse-Application-Id': 'test', @@ -384,13 +392,17 @@ describe('Parse.File testing', () => { var b = JSON.parse(body); expect(b.name).toMatch(/\.html$/); request.get(b.url, (error, response, body) => { + if (!response) { + fail('response should be set'); + return done(); + } expect(response.headers['content-type']).toMatch(/^text\/html/); done(); }); }); }); - it_exclude_dbs(['postgres'])("filename is url encoded", done => { + it("filename is url encoded", done => { var headers = { 'Content-Type': 'text/html', 'X-Parse-Application-Id': 'test', @@ -488,6 +500,9 @@ describe('Parse.File testing', () => { expect(fileAgain.name()).toEqual('meep'); expect(fileAgain.url()).toEqual('http://meep.meep'); done(); + }).catch((e) => { + jfail(e); + done(); }); }); @@ -508,6 +523,9 @@ describe('Parse.File testing', () => { 'http://files.parsetfss.com/test/tfss-123.txt' ); done(); + }).catch((e) => { + jfail(e); + done(); }); }); @@ -528,10 +546,13 @@ describe('Parse.File testing', () => { 'http://files.parse.com/test/d6e80979-a128-4c57-a167-302f874700dc-123.txt' ); done(); + }).catch((e) => { + jfail(e); + done(); }); }); - it_exclude_dbs(['postgres'])('supports files in objects without urls', done => { + it('supports files in objects without urls', done => { var file = { __type: 'File', name: '123.txt' @@ -545,6 +566,9 @@ describe('Parse.File testing', () => { let fileAgain = result.get('file'); expect(fileAgain.url()).toMatch(/123.txt$/); done(); + }).catch((e) => { + jfail(e); + done(); }); }); }); diff --git a/spec/ParseGeoPoint.spec.js b/spec/ParseGeoPoint.spec.js index 54d193a3f2..ffda2b512c 100644 --- a/spec/ParseGeoPoint.spec.js +++ b/spec/ParseGeoPoint.spec.js @@ -4,7 +4,7 @@ var TestObject = Parse.Object.extend('TestObject'); describe('Parse.GeoPoint testing', () => { - it_exclude_dbs(['postgres'])('geo point roundtrip', (done) => { + it('geo point roundtrip', (done) => { var point = new Parse.GeoPoint(44.0, -11.0); var obj = new TestObject(); obj.set('location', point); @@ -26,7 +26,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo point exception two fields', (done) => { + it('geo point exception two fields', (done) => { var point = new Parse.GeoPoint(20, 20); var obj = new TestObject(); obj.set('locationOne', point); @@ -39,7 +39,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo line', (done) => { + it('geo line', (done) => { var line = []; for (var i = 0; i < 10; ++i) { var obj = new TestObject(); @@ -67,7 +67,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance large', (done) => { + it('geo max distance large', (done) => { var objects = []; [0, 1, 2].map(function(i) { var obj = new TestObject(); @@ -86,11 +86,11 @@ describe('Parse.GeoPoint testing', () => { done(); }, (err) => { fail("Couldn't query GeoPoint"); - fail(err) + jfail(err) }); }); - it_exclude_dbs(['postgres'])('geo max distance medium', (done) => { + it('geo max distance medium', (done) => { var objects = []; [0, 1, 2].map(function(i) { var obj = new TestObject(); @@ -114,7 +114,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance small', (done) => { + it('geo max distance small', (done) => { var objects = []; [0, 1, 2].map(function(i) { var obj = new TestObject(); @@ -153,11 +153,12 @@ describe('Parse.GeoPoint testing', () => { Parse.Object.saveAll([sacramento, sf, honolulu], callback); }; - it_exclude_dbs(['postgres'])('geo max distance in km everywhere', (done) => { + it('geo max distance in km everywhere', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); - query.withinKilometers('location', sfo, 4000.0); + // Honolulu is 4300 km away from SFO on a sphere ;) + query.withinKilometers('location', sfo, 4800.0); query.find({ success: function(results) { equal(results.length, 3); @@ -167,7 +168,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in km california', (done) => { + it('geo max distance in km california', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); @@ -183,7 +184,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in km bay area', (done) => { + it('geo max distance in km bay area', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); @@ -198,7 +199,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in km mid peninsula', (done) => { + it('geo max distance in km mid peninsula', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); @@ -212,11 +213,11 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in miles everywhere', (done) => { + it('geo max distance in miles everywhere', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); - query.withinMiles('location', sfo, 2500.0); + query.withinMiles('location', sfo, 2600.0); query.find({ success: function(results) { equal(results.length, 3); @@ -226,7 +227,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in miles california', (done) => { + it('geo max distance in miles california', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); @@ -242,11 +243,12 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in miles bay area', (done) => { + it('geo max distance in miles bay area', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); - query.withinMiles('location', sfo, 75.0); + // 100km is 62 miles... + query.withinMiles('location', sfo, 62.0); query.find({ success: function(results) { equal(results.length, 1); @@ -257,7 +259,7 @@ describe('Parse.GeoPoint testing', () => { }); }); - it_exclude_dbs(['postgres'])('geo max distance in miles mid peninsula', (done) => { + it('geo max distance in miles mid peninsula', (done) => { makeSomeGeoPoints(function(list) { var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var query = new Parse.Query(TestObject); diff --git a/spec/ParseGlobalConfig.spec.js b/spec/ParseGlobalConfig.spec.js index 7f57cb7ab5..04f47ac3a9 100644 --- a/spec/ParseGlobalConfig.spec.js +++ b/spec/ParseGlobalConfig.spec.js @@ -12,7 +12,7 @@ describe('a GlobalConfig', () => { { fields: {} }, { objectId: 1 }, { params: { companies: ['US', 'DK'] } } - ).then(done); + ).then(done, done); }); it_exclude_dbs(['postgres'])('can be retrieved', (done) => { @@ -24,8 +24,10 @@ describe('a GlobalConfig', () => { 'X-Parse-Master-Key' : 'test' } }, (error, response, body) => { - expect(response.statusCode).toEqual(200); - expect(body.params.companies).toEqual(['US', 'DK']); + try { + expect(response.statusCode).toEqual(200); + expect(body.params.companies).toEqual(['US', 'DK']); + } catch(e) { jfail(e); } done(); }); }); @@ -66,10 +68,12 @@ describe('a GlobalConfig', () => { 'X-Parse-Master-Key' : 'test' } }, (error, response, body) => { - expect(response.statusCode).toEqual(200); - expect(body.params.companies).toBeUndefined(); - expect(body.params.foo).toBe('bar'); - expect(Object.keys(body.params).length).toBe(1); + try { + expect(response.statusCode).toEqual(200); + expect(body.params.companies).toBeUndefined(); + expect(body.params.foo).toBe('bar'); + expect(Object.keys(body.params).length).toBe(1); + } catch(e) { jfail(e); } done(); }); }); @@ -110,6 +114,9 @@ describe('a GlobalConfig', () => { expect(body.params).toEqual({}); done(); }); + }).catch((e) => { + jfail(e); + done(); }); }); }); diff --git a/spec/ParseHooks.spec.js b/spec/ParseHooks.spec.js index f335d932b1..f3379151e9 100644 --- a/spec/ParseHooks.spec.js +++ b/spec/ParseHooks.spec.js @@ -20,7 +20,7 @@ describe('Hooks', () => { expect(res.constructor).toBe(Array.prototype.constructor); done(); }, (err) => { - fail(err); + jfail(err); done(); }); }); @@ -30,7 +30,7 @@ describe('Hooks', () => { expect(res.constructor).toBe(Array.prototype.constructor); done(); }, (err) => { - fail(err); + jfail(err); done(); }); }); @@ -71,7 +71,7 @@ describe('Hooks', () => { }) }) .catch(error => { - fail(error); + jfail(error); done(); }) }); @@ -95,7 +95,7 @@ describe('Hooks', () => { // delete return Parse.Hooks.updateTrigger("MyClass","beforeDelete", "http://anotherurl"); }, (err) => { - fail(err); + jfail(err); done(); }).then((res) => { expect(res.className).toBe("MyClass"); @@ -104,22 +104,26 @@ describe('Hooks', () => { return Parse.Hooks.removeTrigger("MyClass","beforeDelete"); }, (err) => { - fail(err); + jfail(err); done(); }).then((res) => { // Find again! but should be deleted return Parse.Hooks.getTrigger("MyClass","beforeDelete"); }, (err) => { - fail(err); + jfail(err); done(); }).then(function(){ fail("should not succeed"); done(); }, (err) => { - expect(err).not.toBe(null); - expect(err).not.toBe(undefined); - expect(err.code).toBe(143); - expect(err.message).toBe("class MyClass does not exist") + if (err) { + expect(err).not.toBe(null); + expect(err).not.toBe(undefined); + expect(err.code).toBe(143); + expect(err.message).toBe("class MyClass does not exist") + } else { + fail('should have errored'); + } done(); }); }); @@ -148,13 +152,15 @@ describe('Hooks', () => { }, (err) => { expect(err).not.toBe(undefined); expect(err).not.toBe(null); - expect(err.code).toBe(143); - expect(err.message).toBe('function name: my_new_function already exits') + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('function name: my_new_function already exits') + } return Parse.Hooks.removeFunction("my_new_function"); }).then(() => { done(); }, (err) => { - fail(err); + jfail(err); done(); }) }); @@ -167,13 +173,17 @@ describe('Hooks', () => { }).then( () => { fail("should not be able to create the same trigger"); }, (err) => { - expect(err.code).toBe(143); - expect(err.message).toBe('class MyClass already has trigger beforeSave') + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('class MyClass already has trigger beforeSave') + } return Parse.Hooks.removeTrigger("MyClass", "beforeSave"); }).then(() => { done(); }, (err) => { - fail(err); + jfail(err); done(); }) }); @@ -182,15 +192,23 @@ describe('Hooks', () => { Parse.Hooks.updateFunction("A_COOL_FUNCTION", "http://url.com").then( () => { fail("Should not succeed") }, (err) => { - expect(err.code).toBe(143); - expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); + } return Parse.Hooks.getFunction("A_COOL_FUNCTION") }).then( (res) => { fail("the function should not exist"); done(); }, (err) => { - expect(err.code).toBe(143); - expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); + } done(); }); }); @@ -199,15 +217,23 @@ describe('Hooks', () => { Parse.Hooks.updateTrigger("AClassName","beforeSave", "http://url.com").then( () => { fail("Should not succeed") }, (err) => { - expect(err.code).toBe(143); - expect(err.message).toBe('class AClassName does not exist'); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('class AClassName does not exist'); + } return Parse.Hooks.getTrigger("AClassName","beforeSave") }).then( (res) => { fail("the function should not exist"); done(); }, (err) => { - expect(err.code).toBe(143); - expect(err.message).toBe('class AClassName does not exist'); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.message).toBe('class AClassName does not exist'); + } done(); }); }); @@ -217,8 +243,12 @@ describe('Hooks', () => { Parse.Hooks.createFunction("MyFunction").then( (res) => { fail(res); }, (err) => { - expect(err.code).toBe(143); - expect(err.error).toBe("invalid hook declaration"); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(143); + expect(err.error).toBe("invalid hook declaration"); + } done(); }); }); @@ -258,7 +288,7 @@ describe('Hooks', () => { const hooksController = new HooksController(Parse.applicationId, AppCache.get('test').databaseController); return hooksController.load() }, (err) => { - console.error(err); + jfail(err); fail('Should properly create all hooks'); done(); }).then(function() { @@ -268,7 +298,7 @@ describe('Hooks', () => { } done(); }, (err) => { - console.error(err); + jfail(err); fail('should properly load all hooks'); done(); }) @@ -283,14 +313,14 @@ describe('Hooks', () => { Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunction").then(function(){ return Parse.Cloud.run("SOME_TEST_FUNCTION") }, (err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }).then(function(res){ expect(res).toBe("OK!"); done(); }, (err) => { - console.error(err); + jfail(err); fail("Should not fail calling a function"); done(); }); @@ -305,17 +335,21 @@ describe('Hooks', () => { Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunctionError").then(function(){ return Parse.Cloud.run("SOME_TEST_FUNCTION") }, (err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }).then(function(res){ fail("Should not succeed calling that function"); done(); }, (err) => { - expect(err.code).toBe(141); - expect(err.message.code).toEqual(1337) - expect(err.message.error).toEqual("hacking that one!"); - done(); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(141); + expect(err.message.code).toEqual(1337) + expect(err.message.error).toEqual("hacking that one!"); + } + done(); }); }); @@ -331,14 +365,14 @@ describe('Hooks', () => { Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKey").then(function(){ return Parse.Cloud.run("SOME_TEST_FUNCTION") }, (err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }).then(function(res){ expect(res).toBe("correct key provided"); done(); }, (err) => { - console.error(err); + jfail(err); fail("Should not fail calling a function"); done(); }); @@ -358,16 +392,20 @@ describe('Hooks', () => { Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKeyAlso").then(function(){ return Parse.Cloud.run("SOME_TEST_FUNCTION") }, (err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }).then(function(res){ fail("Should not succeed calling that function"); done(); }, (err) => { - expect(err.code).toBe(141); - expect(err.message).toEqual("incorrect key provided"); - done(); + expect(err).not.toBe(undefined); + expect(err).not.toBe(null); + if (err) { + expect(err.code).toBe(141); + expect(err.message).toEqual("incorrect key provided"); + } + done(); }); }); }); @@ -394,7 +432,7 @@ describe('Hooks', () => { expect(res.get("hello")).toEqual("world"); done(); }).fail((err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }); @@ -451,7 +489,7 @@ describe('Hooks', () => { expect(res.get("foo")).toEqual("bar"); done(); }).fail((err) => { - console.error(err); + jfail(err); fail("Should not fail creating a function"); done(); }); diff --git a/spec/ParseInstallation.spec.js b/spec/ParseInstallation.spec.js index ea12320a6e..f7d648eed8 100644 --- a/spec/ParseInstallation.spec.js +++ b/spec/ParseInstallation.spec.js @@ -22,7 +22,7 @@ describe('Installations', () => { database = config.database; }); - it_exclude_dbs(['postgres'])('creates an android installation with ids', (done) => { + it('creates an android installation with ids', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var device = 'android'; var input = { @@ -40,7 +40,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('creates an ios installation with ids', (done) => { + it('creates an ios installation with ids', (done) => { var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var device = 'ios'; var input = { @@ -58,7 +58,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('creates an embedded installation with ids', (done) => { + it('creates an embedded installation with ids', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var device = 'embedded'; var input = { @@ -76,7 +76,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('creates an android installation with all fields', (done) => { + it('creates an android installation with all fields', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var device = 'android'; var input = { @@ -99,7 +99,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('creates an ios installation with all fields', (done) => { + it('creates an ios installation with all fields', (done) => { var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var device = 'ios'; var input = { @@ -143,7 +143,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('should properly queying installations with masterKey', (done) => { + it('should properly queying installations with masterKey', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var device = 'android'; var input = { @@ -197,7 +197,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('creates an object with custom fields', (done) => { + it('creates an object with custom fields', (done) => { var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var input = { 'deviceToken': t, @@ -217,7 +217,7 @@ describe('Installations', () => { // Note: did not port test 'TestObjectIDForIdentifiers' - it_exclude_dbs(['postgres'])('merging when installationId already exists', (done) => { + it('merging when installationId already exists', (done) => { var installId1 = '12345678-abcd-abcd-abcd-123456789abc'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var installId2 = '12345678-abcd-abcd-abcd-123456789abd'; @@ -250,7 +250,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('merging when two objects both only have one id', (done) => { + it('merging when two objects both only have one id', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input1 = { @@ -290,7 +290,10 @@ describe('Installations', () => { expect(results.length).toEqual(1); expect(results[0]['_id']).toEqual(secondObject._id); done(); - }).catch((error) => { console.log(error); }); + }).catch((error) => { + jfail(error); + done(); + }); }); xit('creating multiple devices with same device token works', (done) => { @@ -324,7 +327,7 @@ describe('Installations', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('updating with new channels', (done) => { + it('updating with new channels', (done) => { var input = { installationId: '12345678-abcd-abcd-abcd-123456789abc', deviceType: 'android', @@ -347,13 +350,12 @@ describe('Installations', () => { expect(results[0].channels[0]).toEqual('baz'); done(); }).catch(error => { - console.log(error); - fail(); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('update android fails with new installation id', (done) => { + it('update android fails with new installation id', (done) => { var installId1 = '12345678-abcd-abcd-abcd-123456789abc'; var installId2 = '87654321-abcd-abcd-abcd-123456789abc'; var input = { @@ -376,7 +378,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('update ios fails with new deviceToken and no installationId', (done) => { + it('update ios fails with new deviceToken and no installationId', (done) => { var a = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var b = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var input = { @@ -398,7 +400,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('update ios updates device token', (done) => { + it('update ios updates device token', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var u = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; @@ -424,10 +426,13 @@ describe('Installations', () => { expect(results.length).toEqual(1); expect(results[0].deviceToken).toEqual(u); done(); - }); + }).catch(err => { + jfail(err); + done(); + }) }); - it_exclude_dbs(['postgres'])('update fails to change deviceType', (done) => { + it('update fails to change deviceType', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var input = { 'installationId': installId, @@ -451,7 +456,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('update android with custom field', (done) => { + it('update android with custom field', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var input = { 'installationId': installId, @@ -475,7 +480,7 @@ describe('Installations', () => { }); }); - it_exclude_dbs(['postgres'])('update android device token with duplicate device token', (done) => { + it('update android device token with duplicate device token', (done) => { var installId1 = '11111111-abcd-abcd-abcd-123456789abc'; var installId2 = '22222222-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; @@ -514,10 +519,13 @@ describe('Installations', () => { // The first object should have been deleted expect(results.length).toEqual(0); done(); - }).catch((error) => { console.log(error); }); + }).catch(error => { + jfail(error); + done(); + }); }); - it_exclude_dbs(['postgres'])('update ios device token with duplicate device token', (done) => { + it('update ios device token with duplicate device token', (done) => { var installId1 = '11111111-abcd-abcd-abcd-123456789abc'; var installId2 = '22222222-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; @@ -557,7 +565,10 @@ describe('Installations', () => { // The first object should have been deleted expect(results.length).toEqual(0); done(); - }).catch((error) => { console.log(error); }); + }).catch(error => { + jfail(error); + done(); + }); }); xit('update ios device token with duplicate token different app', (done) => { @@ -582,10 +593,13 @@ describe('Installations', () => { expect(results.length).toEqual(1); expect(results[0].installationId).toEqual(installId2); done(); + }).catch(error => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('update ios token and channels', (done) => { + it('update ios token and channels', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input = { @@ -609,10 +623,13 @@ describe('Installations', () => { expect(results[0].deviceToken).toEqual(t); expect(results[0].channels.length).toEqual(0); done(); + }).catch(error => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('update ios linking two existing objects', (done) => { + it('update ios linking two existing objects', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input = { @@ -644,10 +661,13 @@ describe('Installations', () => { expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceType).toEqual('ios'); done(); + }).catch(error => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('update is linking two existing objects w/ increment', (done) => { + it('update is linking two existing objects w/ increment', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input = { @@ -684,10 +704,13 @@ describe('Installations', () => { expect(results[0].deviceType).toEqual('ios'); expect(results[0].score).toEqual(1); done(); + }).catch(error => { + jfail(error); + done(); }); }); - it_exclude_dbs(['postgres'])('update is linking two existing with installation id', (done) => { + it('update is linking two existing with installation id', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input = { @@ -724,10 +747,13 @@ describe('Installations', () => { expect(results[0].installationId).toEqual(installId); expect(results[0].deviceToken).toEqual(t); done(); - }).catch((error) => { console.log(error); }); + }).catch(error => { + jfail(error); + done(); + }); }); - it_exclude_dbs(['postgres'])('update is linking two existing with installation id w/ op', (done) => { + it('update is linking two existing with installation id w/ op', (done) => { var installId = '12345678-abcd-abcd-abcd-123456789abc'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var input = { @@ -769,10 +795,13 @@ describe('Installations', () => { expect(results[0].deviceToken).toEqual(t); expect(results[0].score).toEqual(1); done(); - }).catch((error) => { console.log(error); }); + }).catch(error => { + jfail(error); + done(); + }); }); - it_exclude_dbs(['postgres'])('ios merge existing same token no installation id', (done) => { + it('ios merge existing same token no installation id', (done) => { // Test creating installation when there is an existing object with the // same device token but no installation ID. This is possible when // developers import device tokens from another push provider; the import diff --git a/spec/ParseObject.spec.js b/spec/ParseObject.spec.js index cb57e87233..0a281557ba 100644 --- a/spec/ParseObject.spec.js +++ b/spec/ParseObject.spec.js @@ -117,7 +117,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("relational fields", function(done) { + it("relational fields", function(done) { var item = new Item(); item.set("property", "x"); var container = new Container(); @@ -205,7 +205,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("createdAt doesn't change", function(done) { + it("createdAt doesn't change", function(done) { var object = new TestObject({ foo: "bar" }); object.save(null, { success: function() { @@ -269,15 +269,21 @@ describe('Parse.Object testing', () => { }); it_exclude_dbs(['postgres'])("can set null", function(done) { + var errored = false; var obj = new Parse.Object("TestObject"); obj.set("foo", null); obj.save(null, { success: function(obj) { - equal(obj.get("foo"), null); + on_db('mongo', () => { + equal(obj.get("foo"), null); + }); + on_db('postgres', () => { + fail('should not succeed'); + }); done(); }, error: function(obj, error) { - ok(false, error.message); + fail('should not fail'); done(); } }); @@ -365,7 +371,7 @@ describe('Parse.Object testing', () => { }).then(fail, err => next(0)); }); - it_exclude_dbs(['postgres'])("simple field deletion", function(done) { + it("simple field deletion", function(done) { var simple = new Parse.Object("SimpleObject"); simple.save({ foo: "bar" @@ -439,7 +445,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("relation deletion", function(done) { + it("relation deletion", function(done) { var simple = new Parse.Object("SimpleObject"); var child = new Parse.Object("Child"); simple.save({ @@ -578,7 +584,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("addUnique", function(done) { + it("addUnique", function(done) { var x1 = new Parse.Object('X'); x1.set('stuff', [1, 2]); x1.save().then(() => { @@ -595,12 +601,17 @@ describe('Parse.Object testing', () => { expect(x3.get('stuff')).toEqual([1, 2, 3]); done(); }, (error) => { - fail(error); + on_db('mongo', () => { + jfail(error); + }); + on_db('postgres', () => { + expect(error.message).toEqual("Postgres does not support AddUnique operator."); + }); done(); }); }); - it_exclude_dbs(['postgres'])("addUnique with object", function(done) { + it("addUnique with object", function(done) { var x1 = new Parse.Object('X'); x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]); x1.save().then(() => { @@ -617,12 +628,17 @@ describe('Parse.Object testing', () => { expect(x3.get('stuff')).toEqual([1, {'hello': 'world'}, {'foo': 'bar'}, {'bar': 'baz'}]); done(); }, (error) => { - fail(error); + on_db('mongo', () => { + jfail(error); + }); + on_db('postgres', () => { + expect(error.message).toEqual("Postgres does not support AddUnique operator."); + }); done(); }); }); - it_exclude_dbs(['postgres'])("removes with object", function(done) { + it("removes with object", function(done) { var x1 = new Parse.Object('X'); x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]); x1.save().then(() => { @@ -638,7 +654,12 @@ describe('Parse.Object testing', () => { expect(x3.get('stuff')).toEqual([1, {'foo': 'bar'}]); done(); }, (error) => { - fail(error); + on_db('mongo', () => { + jfail(error); + }); + on_db('postgres', () => { + expect(error.message).toEqual("Postgres does not support Remove operator."); + }); done(); }); }); @@ -668,7 +689,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("dirty keys", function(done) { + it("dirty keys", function(done) { var object = new Parse.Object("TestObject"); object.set("gogo", "good"); object.set("sito", "sexy"); @@ -763,7 +784,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("old attribute unset then unset", function(done) { + it("old attribute unset then unset", function(done) { var TestObject = Parse.Object.extend("TestObject"); var obj = new TestObject(); obj.set("x", 3); @@ -832,7 +853,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("old attribute unset then clear", function(done) { + it("old attribute unset then clear", function(done) { var TestObject = Parse.Object.extend("TestObject"); var obj = new TestObject(); obj.set("x", 3); @@ -901,7 +922,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("old attribute clear then unset", function(done) { + it("old attribute clear then unset", function(done) { var TestObject = Parse.Object.extend("TestObject"); var obj = new TestObject(); obj.set("x", 3); @@ -970,7 +991,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("old attribute clear then clear", function(done) { + it("old attribute clear then clear", function(done) { var TestObject = Parse.Object.extend("TestObject"); var obj = new TestObject(); obj.set("x", 3); @@ -1039,7 +1060,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("saving children in an array", function(done) { + it("saving children in an array", function(done) { var Parent = Parse.Object.extend("Parent"); var Child = Parse.Object.extend("Child"); @@ -1342,7 +1363,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("fetchAll", function(done) { + it("fetchAll", function(done) { var numItems = 11; var container = new Container(); var items = []; @@ -1389,7 +1410,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("fetchAll updates dates", function(done) { + it("fetchAll updates dates", function(done) { var updatedObject; var object = new TestObject(); object.set("x", 7); @@ -1409,7 +1430,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("fetchAll backbone-style callbacks", function(done) { + it("fetchAll backbone-style callbacks", function(done) { var numItems = 11; var container = new Container(); var items = []; @@ -1478,7 +1499,7 @@ describe('Parse.Object testing', () => { expectError(Parse.Error.MISSING_OBJECT_ID, done)); }); - it_exclude_dbs(['postgres'])("fetchAll error on deleted object", function(done) { + it("fetchAll error on deleted object", function(done) { var numItems = 11; var container = new Container(); var subContainer = new Container(); @@ -1536,7 +1557,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("fetchAllIfNeeded", function(done) { + it("fetchAllIfNeeded", function(done) { var numItems = 11; var container = new Container(); var items = []; @@ -1574,7 +1595,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])("fetchAllIfNeeded backbone-style callbacks", function(done) { + it("fetchAllIfNeeded backbone-style callbacks", function(done) { var numItems = 11; var container = new Container(); var items = []; @@ -1778,7 +1799,7 @@ describe('Parse.Object testing', () => { }); }); - it_exclude_dbs(['postgres'])('dictionary fetched pointers do not lose data on fetch', (done) => { + it('dictionary fetched pointers do not lose data on fetch', (done) => { var parent = new Parse.Object('Parent'); var dict = {}; for (var i = 0; i < 5; i++) { @@ -1832,13 +1853,13 @@ describe('Parse.Object testing', () => { expect(foo["_more"]["_nested"]).toEqual("key"); done(); }).fail( err => { - console.error(err); + jfail(err); fail("should not fail"); done(); }); }); - it_exclude_dbs(['postgres'])('should have undefined includes when object is missing', (done) => { + it('should have undefined includes when object is missing', (done) => { let obj1 = new Parse.Object("AnObject"); let obj2 = new Parse.Object("AnObject"); @@ -1852,13 +1873,19 @@ describe('Parse.Object testing', () => { return query.find(); }).then((res) => { expect(res.length).toBe(1); - expect(res[0].get("obj")).toBe(undefined); + if (res[0]) { + expect(res[0].get("obj")).toBe(undefined); + } let query = new Parse.Query("AnObject"); return query.find(); }).then((res) => { expect(res.length).toBe(1); - expect(res[0].get("obj")).not.toBe(undefined); - return res[0].get("obj").fetch(); + if (res[0]) { + expect(res[0].get("obj")).not.toBe(undefined); + return res[0].get("obj").fetch(); + } else { + done(); + } }).then(() => { fail("Should not fetch a deleted object"); }, (err) => { @@ -1867,7 +1894,7 @@ describe('Parse.Object testing', () => { }) }); - it_exclude_dbs(['postgres'])('should have undefined includes when object is missing on deeper path', (done) => { + it('should have undefined includes when object is missing on deeper path', (done) => { let obj1 = new Parse.Object("AnObject"); let obj2 = new Parse.Object("AnObject"); let obj3 = new Parse.Object("AnObject"); @@ -1884,6 +1911,9 @@ describe('Parse.Object testing', () => { expect(res.get("obj")).not.toBe(undefined); expect(res.get("obj").get("obj")).toBe(undefined); done(); - }); + }).catch(err => { + jfail(err); + done(); + }) }); }); diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index 60985aa793..e917510713 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -23,7 +23,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("notEqualTo with Relation is working", function(done) { + it("notEqualTo with Relation is working", function(done) { var user = new Parse.User(); user.setPassword("asdf"); user.setUsername("zxcv"); @@ -129,6 +129,9 @@ describe('Parse.Query testing', () => { }); }).then(function(){ done(); + }).catch((err) => { + jfail(err); + done(); }) }); @@ -147,7 +150,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("containedIn object array queries", function(done) { + it("containedIn object array queries", function(done) { var messageList = []; for (var i = 0; i < 4; ++i) { var message = new TestObject({}); @@ -172,12 +175,12 @@ describe('Parse.Query testing', () => { done(); }, error: function(e) { - fail(e); + jfail(e); done(); } }); }, (e) => { - fail(e); + jfail(e); done(); }); }); @@ -198,10 +201,13 @@ describe('Parse.Query testing', () => { done(); }, error: function(err) { - fail(err); + jfail(err); done(); }, }); + }).catch((err) => { + jfail(err); + done(); }); }); @@ -221,6 +227,9 @@ describe('Parse.Query testing', () => { done(); } }); + }).catch((err) => { + jfail(err); + done(); }); }); @@ -273,7 +282,7 @@ describe('Parse.Query testing', () => { done(); }, error: function(e) { - fail(e); + jfail(e); done(); }, }); @@ -322,7 +331,7 @@ describe('Parse.Query testing', () => { className: "BoxedNumber" }); - it_exclude_dbs(['postgres'])("equalTo queries", function(done) { + it("equalTo queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -339,7 +348,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("equalTo undefined", function(done) { + it("equalTo undefined", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -356,7 +365,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("lessThan queries", function(done) { + it("lessThan queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -373,7 +382,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("lessThanOrEqualTo queries", function(done) { + it("lessThanOrEqualTo queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -391,7 +400,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("greaterThan queries", function(done) { + it("greaterThan queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -409,7 +418,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("greaterThanOrEqualTo queries", function(done) { + it("greaterThanOrEqualTo queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -427,7 +436,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("lessThanOrEqualTo greaterThanOrEqualTo queries", function(done) { + it("lessThanOrEqualTo greaterThanOrEqualTo queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -446,7 +455,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("lessThan greaterThan queries", function(done) { + it("lessThan greaterThan queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -483,7 +492,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("containedIn queries", function(done) { + it("containedIn queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -501,7 +510,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("notContainedIn queries", function(done) { + it("notContainedIn queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -520,7 +529,7 @@ describe('Parse.Query testing', () => { }); - it_exclude_dbs(['postgres'])("objectId containedIn queries", function(done) { + it("objectId containedIn queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -547,7 +556,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("objectId equalTo queries", function(done) { + it("objectId equalTo queries", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -570,7 +579,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("find no elements", function(done) { + it("find no elements", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -691,7 +700,7 @@ describe('Parse.Query testing', () => { className: "Container" }); - it_exclude_dbs(['postgres'])("notEqualTo object", function(done) { + it("notEqualTo object", function(done) { var item1 = new TestObject(); var item2 = new TestObject(); var container1 = new Container({item: item1}); @@ -708,7 +717,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("skip", function(done) { + it("skip", function(done) { Parse.Object.saveAll([new TestObject(), new TestObject()], function() { var query = new Parse.Query(TestObject); query.skip(1); @@ -727,7 +736,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("skip doesn't affect count", function(done) { + it("skip doesn't affect count", function(done) { Parse.Object.saveAll([new TestObject(), new TestObject()], function() { var query = new Parse.Query(TestObject); query.count({ @@ -751,7 +760,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("count", function(done) { + it("count", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -769,7 +778,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by ascending number", function(done) { + it("order by ascending number", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -788,11 +797,11 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by descending number", function(done) { + it("order by descending number", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; - Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber), function(list) { + Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.descending("number"); query.find(expectSuccess({ @@ -807,13 +816,13 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by ascending number then descending string", function(done) { + it("order by ascending number then descending string", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; Parse.Object.saveAll( - [3, 1, 3, 2].map(makeBoxedNumber), + [3, 1, 3, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.ascending("number").addDescending("string"); @@ -834,38 +843,41 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by descending number then ascending string", function(done) { + it("order by descending number then ascending string", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; - Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), - function(list) { - var query = new Parse.Query(BoxedNumber); - query.descending("number").addAscending("string"); - query.find(expectSuccess({ - success: function(results) { - equal(results.length, 4); - equal(results[0].get("number"), 3); - equal(results[0].get("string"), "a"); - equal(results[1].get("number"), 3); - equal(results[1].get("string"), "c"); - equal(results[2].get("number"), 2); - equal(results[2].get("string"), "d"); - equal(results[3].get("number"), 1); - equal(results[3].get("string"), "b"); - done(); - } - })); - }); + + let objects = [3, 1, 3, 2].map(makeBoxedNumber); + Parse.Object.saveAll(objects) + .then((list) => { + var query = new Parse.Query(BoxedNumber); + query.descending("number").addAscending("string"); + return query.find(); + }).then((results) => { + equal(results.length, 4); + equal(results[0].get("number"), 3); + equal(results[0].get("string"), "a"); + equal(results[1].get("number"), 3); + equal(results[1].get("string"), "c"); + equal(results[2].get("number"), 2); + equal(results[2].get("string"), "d"); + equal(results[3].get("number"), 1); + equal(results[3].get("string"), "b"); + done(); + }, (err) => { + jfail(err); + done(); + }); }); - it_exclude_dbs(['postgres'])("order by descending number and string", function(done) { + it("order by descending number and string", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; - Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), + Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.descending("number,string"); @@ -886,12 +898,12 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by descending number and string, with space", function(done) { + it("order by descending number and string, with space", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; - Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), + Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.descending("number, string"); @@ -909,15 +921,18 @@ describe('Parse.Query testing', () => { done(); } })); + }, (err) => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])("order by descending number and string, with array arg", function(done) { + it("order by descending number and string, with array arg", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; - Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), + Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.descending(["number", "string"]); @@ -938,12 +953,12 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by descending number and string, with multiple args", function(done) { + it("order by descending number and string, with multiple args", function(done) { var strings = ["a", "b", "c", "d"]; var makeBoxedNumber = function(num, i) { return new BoxedNumber({ number: num, string: strings[i] }); }; - Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), + Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then( function(list) { var query = new Parse.Query(BoxedNumber); query.descending("number", "string"); @@ -964,7 +979,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("can't order by password", function(done) { + it("can't order by password", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -996,14 +1011,14 @@ describe('Parse.Query testing', () => { done(); }, error: function(e) { - fail(e); + jfail(e); done(); }, }); }); }); - it_exclude_dbs(['postgres'])("order by createdAt", function(done) { + it("order by createdAt", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -1027,7 +1042,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by _updated_at", function(done) { + it("order by _updated_at", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; @@ -1056,7 +1071,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("order by updatedAt", function(done) { + it("order by updatedAt", function(done) { var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; var numbers = [3, 1, 2].map(makeBoxedNumber); numbers[0].save().then(() => { @@ -1107,7 +1122,7 @@ describe('Parse.Query testing', () => { }); } - it_exclude_dbs(['postgres'])("time equality", function(done) { + it("time equality", function(done) { makeThreeTimeObjects().then(function(list) { var query = new Parse.Query(TestObject); query.equalTo("time", list[1].get("time")); @@ -1121,7 +1136,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("time lessThan", function(done) { + it("time lessThan", function(done) { makeThreeTimeObjects().then(function(list) { var query = new Parse.Query(TestObject); query.lessThan("time", list[2].get("time")); @@ -1135,7 +1150,7 @@ describe('Parse.Query testing', () => { }); // This test requires Date objects to be consistently stored as a Date. - it_exclude_dbs(['postgres'])("time createdAt", function(done) { + it("time createdAt", function(done) { makeThreeTimeObjects().then(function(list) { var query = new Parse.Query(TestObject); query.greaterThanOrEqualTo("createdAt", list[0].createdAt); @@ -1148,7 +1163,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("matches string", function(done) { + it("matches string", function(done) { var thing1 = new TestObject(); thing1.set("myString", "football"); var thing2 = new TestObject(); @@ -1165,7 +1180,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("matches regex", function(done) { + it("matches regex", function(done) { var thing1 = new TestObject(); thing1.set("myString", "football"); var thing2 = new TestObject(); @@ -1182,7 +1197,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("case insensitive regex success", function(done) { + it("case insensitive regex success", function(done) { var thing = new TestObject(); thing.set("myString", "football"); Parse.Object.saveAll([thing], function() { @@ -1196,7 +1211,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("regexes with invalid options fail", function(done) { + it("regexes with invalid options fail", function(done) { var query = new Parse.Query(TestObject); query.matches("myString", "FootBall", "some invalid option"); query.find(expectError(Parse.Error.INVALID_QUERY, done)); @@ -1222,7 +1237,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("Regular expression constructor includes modifiers inline", function(done) { + it("Regular expression constructor includes modifiers inline", function(done) { var thing = new TestObject(); thing.set("myString", "\n\nbuffer\n\nparse.COM"); Parse.Object.saveAll([thing], function() { @@ -1288,7 +1303,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("exists", function(done) { + it("exists", function(done) { var objects = []; for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { var item = new TestObject(); @@ -1314,7 +1329,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("doesNotExist", function(done) { + it("doesNotExist", function(done) { var objects = []; for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { var item = new TestObject(); @@ -1340,7 +1355,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("exists relation", function(done) { + it("exists relation", function(done) { var objects = []; for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { var container = new Container(); @@ -1354,7 +1369,7 @@ describe('Parse.Query testing', () => { } objects.push(container); }; - Parse.Object.saveAll(objects, function() { + Parse.Object.saveAll(objects).then(function() { var query = new Parse.Query(Container); query.exists("x"); query.find({ @@ -1369,7 +1384,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("doesNotExist relation", function(done) { + it("doesNotExist relation", function(done) { var objects = []; for (var i of [0, 1, 2, 3, 4, 5, 6, 7]) { var container = new Container(); @@ -1398,7 +1413,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("don't include by default", function(done) { + it("don't include by default", function(done) { var child = new TestObject(); var parent = new Container(); child.set("foo", "bar"); @@ -1564,7 +1579,7 @@ describe('Parse.Query testing', () => { }) }); - it('properly includes array of mixed objects', (done) => { + it_exclude_dbs(['postgres'])('properly includes array of mixed objects', (done) => { let objects = []; let total = 0; while(objects.length != 5) { @@ -1642,13 +1657,13 @@ describe('Parse.Query testing', () => { expect(total).toBe(0); done() }, (err) => { - console.error(err); + jfail(err); fail('should not fail'); done(); }) }); - it_exclude_dbs(['postgres'])('properly fetches nested pointers', (done) =>  { + it('properly fetches nested pointers', (done) =>  { let color = new Parse.Object('Color'); color.set('hex','#133733'); let circle = new Parse.Object('Circle'); @@ -1713,7 +1728,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("matches query", function(done) { + it("matches query", function(done) { var ParentObject = Parse.Object.extend("ParentObject"); var ChildObject = Parse.Object.extend("ChildObject"); var objects = []; @@ -1752,7 +1767,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("select query", function(done) { + it("select query", function(done) { var RestaurantObject = Parse.Object.extend("Restaurant"); var PersonObject = Parse.Object.extend("Person"); var objects = [ @@ -1778,7 +1793,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])('$select inside $or', (done) => { + it('$select inside $or', (done) => { var Restaurant = Parse.Object.extend('Restaurant'); var Person = Parse.Object.extend('Person'); var objects = [ @@ -1802,12 +1817,12 @@ describe('Parse.Query testing', () => { expect(results.length).toEqual(2); done(); }, (error) => { - fail(error); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])("dontSelect query", function(done) { + it("dontSelect query", function(done) { var RestaurantObject = Parse.Object.extend("Restaurant"); var PersonObject = Parse.Object.extend("Person"); var objects = [ @@ -1833,7 +1848,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("dontSelect query without conditions", function(done) { + it("dontSelect query without conditions", function(done) { const RestaurantObject = Parse.Object.extend("Restaurant"); const PersonObject = Parse.Object.extend("Person"); const objects = [ @@ -1920,7 +1935,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("or queries", function(done) { + it("or queries", function(done) { var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var object = new Parse.Object('BoxedNumber'); object.set('x', x); @@ -1947,7 +1962,7 @@ describe('Parse.Query testing', () => { }); // This relies on matchesQuery aka the $inQuery operator - it_exclude_dbs(['postgres'])("or complex queries", function(done) { + it("or complex queries", function(done) { var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var child = new Parse.Object('Child'); child.set('x', x); @@ -1976,7 +1991,7 @@ describe('Parse.Query testing', () => { })); }); - it_exclude_dbs(['postgres'])("async methods", function(done) { + it("async methods", function(done) { var saves = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var obj = new Parse.Object("TestObject"); obj.set("x", x + 1); @@ -2013,7 +2028,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("query.each", function(done) { + it("query.each", function(done) { var TOTAL = 50; var COUNT = 25; @@ -2048,7 +2063,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])("query.each async", function(done) { + it("query.each async", function(done) { var TOTAL = 50; var COUNT = 25; @@ -2249,7 +2264,7 @@ describe('Parse.Query testing', () => { }).then(function() { done(); }, function(err) { - ok(false, JSON.stringify(err)); + jfail(err); done(); }); }); @@ -2285,6 +2300,7 @@ describe('Parse.Query testing', () => { }).catch((error) => { console.log(error); }); }); + // PG don't support creating a null column it_exclude_dbs(['postgres'])('querying for null value', (done) => { var obj = new Parse.Object('TestObject'); obj.set('aNull', null); @@ -2299,7 +2315,7 @@ describe('Parse.Query testing', () => { }) }); - it_exclude_dbs(['postgres'])('query within dictionary', (done) => { + it('query within dictionary', (done) => { var objs = []; var promises = []; for (var i = 0; i < 2; i++) { @@ -2322,7 +2338,7 @@ describe('Parse.Query testing', () => { }); }); - it_exclude_dbs(['postgres'])('supports include on the wrong key type (#2262)', function(done) { + it('supports include on the wrong key type (#2262)', function(done) { let childObject = new Parse.Object('TestChildObject'); childObject.set('hello', 'world'); childObject.save().then(() => { @@ -2382,7 +2398,7 @@ describe('Parse.Query testing', () => { }); // #371 - it_exclude_dbs(['postgres'])('should properly interpret a query v1', (done) => { + it('should properly interpret a query v1', (done) => { var query = new Parse.Query("C1"); var auxQuery = new Parse.Query("C1"); query.matchesKeyInQuery("A1", "A2", auxQuery); @@ -2391,13 +2407,13 @@ describe('Parse.Query testing', () => { query.find().then((result) => { done(); }, (err) => { - console.error(err); + jfail(err); fail("should not failt"); done(); }) }); - it_exclude_dbs(['postgres'])('should properly interpret a query v2', (done) => { + it('should properly interpret a query v2', (done) => { var user = new Parse.User(); user.set("username", "foo"); user.set("password", "bar"); @@ -2426,9 +2442,8 @@ describe('Parse.Query testing', () => { return query.find(); }).then((res) => { done(); - done(); }, (err) => { - console.error(err); + jfail(err); fail("should not fail"); done(); }); @@ -2467,7 +2482,7 @@ describe('Parse.Query testing', () => { } done(); }).fail((err) => { - console.error(err); + jfail(err); fail('should not fail'); done(); }) @@ -2487,7 +2502,9 @@ describe('Parse.Query testing', () => { q2.doesNotExist('nonExistantKey2'); let orQuery = Parse.Query.or(q1, q2).find().then(results => { expect(results.length).toEqual(1); - expect(results[0].objectId).toEqual(q1.objectId); + if (results.length == 1) { + expect(results[0].objectId).toEqual(q1.objectId); + } done(); }); }); @@ -2550,7 +2567,7 @@ describe('Parse.Query testing', () => { }) }); - it_exclude_dbs(['postgres'])('properly handles nested ors', function(done) { + it('properly handles nested ors', function(done) { var objects = []; while(objects.length != 4) { var obj = new Parse.Object('Object'); @@ -2571,7 +2588,7 @@ describe('Parse.Query testing', () => { done(); }).catch((error) => { fail('should not fail'); - console.error(error); + jfail(error); done(); }) }); diff --git a/spec/ParseRelation.spec.js b/spec/ParseRelation.spec.js index e8df9ae3ac..9decbf1cb4 100644 --- a/spec/ParseRelation.spec.js +++ b/spec/ParseRelation.spec.js @@ -6,7 +6,7 @@ var ChildObject = Parse.Object.extend({className: "ChildObject"}); var ParentObject = Parse.Object.extend({className: "ParentObject"}); describe('Parse.Relation testing', () => { - it_exclude_dbs(['postgres'])("simple add and remove relation", (done) => { + it("simple add and remove relation", (done) => { var child = new ChildObject(); child.set("x", 2); var parent = new ParentObject(); @@ -41,7 +41,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("query relation without schema", (done) => { + it("query relation without schema", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; for (var i = 0; i < 10; i++) { @@ -75,7 +75,7 @@ describe('Parse.Relation testing', () => { })); }); - it_exclude_dbs(['postgres'])("relations are constructed right from query", (done) => { + it("relations are constructed right from query", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; @@ -121,7 +121,7 @@ describe('Parse.Relation testing', () => { }); - it_exclude_dbs(['postgres'])("compound add and remove relation", (done) => { + it("compound add and remove relation", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; for (var i = 0; i < 10; i++) { @@ -164,7 +164,7 @@ describe('Parse.Relation testing', () => { }); - it_exclude_dbs(['postgres'])("queries with relations", (done) => { + it("queries with relations", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; @@ -202,7 +202,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("queries on relation fields", (done) => { + it("queries on relation fields", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; for (var i = 0; i < 10; i++) { @@ -248,7 +248,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("queries on relation fields with multiple containedIn (regression test for #1271)", (done) => { + it("queries on relation fields with multiple containedIn (regression test for #1271)", (done) => { let ChildObject = Parse.Object.extend("ChildObject"); let childObjects = []; for (let i = 0; i < 10; i++) { @@ -334,7 +334,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("query on pointer and relation fields with equal bis", (done) => { + it("query on pointer and relation fields with equal bis", (done) => { var ChildObject = Parse.Object.extend("ChildObject"); var childObjects = []; for (var i = 0; i < 10; i++) { @@ -419,7 +419,7 @@ describe('Parse.Relation testing', () => { }); - it_exclude_dbs(['postgres'])("Get query on relation using un-fetched parent object", (done) => { + it("Get query on relation using un-fetched parent object", (done) => { // Setup data model var Wheel = Parse.Object.extend('Wheel'); var Car = Parse.Object.extend('Car'); @@ -452,7 +452,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("Find query on relation using un-fetched parent object", (done) => { + it("Find query on relation using un-fetched parent object", (done) => { // Setup data model var Wheel = Parse.Object.extend('Wheel'); var Car = Parse.Object.extend('Car'); @@ -486,7 +486,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])('Find objects with a related object using equalTo', (done) => { + it('Find objects with a related object using equalTo', (done) => { // Setup the objects var Card = Parse.Object.extend('Card'); var House = Parse.Object.extend('House'); @@ -506,7 +506,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])('should properly get related objects with unfetched queries', (done) => { + it('should properly get related objects with unfetched queries', (done) => { let objects = []; let owners = []; let allObjects = []; @@ -575,7 +575,7 @@ describe('Parse.Relation testing', () => { }) }); - it_exclude_dbs(['postgres'])("select query", function(done) { + it("select query", function(done) { var RestaurantObject = Parse.Object.extend("Restaurant"); var PersonObject = Parse.Object.extend("Person"); var OwnerObject = Parse.Object.extend('Owner'); @@ -615,7 +615,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])("dontSelect query", function(done) { + it("dontSelect query", function(done) { var RestaurantObject = Parse.Object.extend("Restaurant"); var PersonObject = Parse.Object.extend("Person"); var OwnerObject = Parse.Object.extend('Owner'); @@ -657,7 +657,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])('relations are not bidirectional (regression test for #871)', done => { + it('relations are not bidirectional (regression test for #871)', done => { let PersonObject = Parse.Object.extend("Person"); let p1 = new PersonObject(); let p2 = new PersonObject(); @@ -684,7 +684,7 @@ describe('Parse.Relation testing', () => { }); }); - it_exclude_dbs(['postgres'])('can query roles in Cloud Code (regession test #1489)', done => { + it('can query roles in Cloud Code (regession test #1489)', done => { Parse.Cloud.define('isAdmin', (request, response) => { let query = new Parse.Query(Parse.Role); query.equalTo('name', 'admin'); diff --git a/spec/ParseRole.spec.js b/spec/ParseRole.spec.js index 142fc929ae..0ca2d124ed 100644 --- a/spec/ParseRole.spec.js +++ b/spec/ParseRole.spec.js @@ -7,7 +7,7 @@ var Auth = require("../src/Auth").Auth; var Config = require("../src/Config"); describe('Parse Role testing', () => { - it_exclude_dbs(['postgres'])('Do a bunch of basic role testing', done => { + it('Do a bunch of basic role testing', done => { var user; var role; @@ -76,7 +76,7 @@ describe('Parse Role testing', () => { return role.save({}, { useMasterKey: true }); }; - it_exclude_dbs(['postgres'])("should not recursively load the same role multiple times", (done) => { + it("should not recursively load the same role multiple times", (done) => { var rootRole = "RootRole"; var roleNames = ["FooRole", "BarRole", "BazRole"]; var allRoles = [rootRole].concat(roleNames); @@ -142,7 +142,7 @@ describe('Parse Role testing', () => { }); - it_exclude_dbs(['postgres'])("should recursively load roles", (done) => { + it("should recursively load roles", (done) => { var rolesNames = ["FooRole", "BarRole", "BazRole"]; var roleIds = {}; createTestUser().then( (user) => { @@ -174,7 +174,7 @@ describe('Parse Role testing', () => { }); }); - it_exclude_dbs(['postgres'])("_Role object should not save without name.", (done) => { + it("_Role object should not save without name.", (done) => { var role = new Parse.Role(); role.save(null,{useMasterKey:true}) .then((r) => { @@ -245,7 +245,7 @@ describe('Parse Role testing', () => { }); - it_exclude_dbs(['postgres'])('can create role and query empty users', (done)=> { + it('can create role and query empty users', (done)=> { var roleACL = new Parse.ACL(); roleACL.setPublicReadAccess(true); var role = new Parse.Role('subscribers', roleACL); @@ -265,7 +265,7 @@ describe('Parse Role testing', () => { }); // Based on various scenarios described in issues #827 and #683, - it_exclude_dbs(['postgres'])('should properly handle role permissions on objects', (done) => { + it('should properly handle role permissions on objects', (done) => { var user, user2, user3; var role, role2, role3; var obj, obj2; diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index b5e4721d6e..838d334c2d 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -58,7 +58,7 @@ describe('Parse.User testing', () => { expectError(Parse.Error.OBJECT_NOT_FOUND, done)); }, error: function(err) { - console.error(err); + jfail(err); fail("Shit should not fail"); done(); } @@ -88,7 +88,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should respect ACL without locking user out', (done) => { + it('should respect ACL without locking user out', (done) => { let user = new Parse.User(); let ACL = new Parse.ACL(); ACL.setPublicReadAccess(false); @@ -148,10 +148,13 @@ describe('Parse.User testing', () => { ok(fileAgain.name()); ok(fileAgain.url()); done(); + }).catch(err => { + jfail(err); + done(); }); }); - it_exclude_dbs(['postgres'])('become sends token back', done => { + it('become sends token back', done => { let user = null; var sessionToken = null; @@ -171,7 +174,7 @@ describe('Parse.User testing', () => { }).then(() => { done(); }, error => { - fail(error); + jfail(error); done(); }); }); @@ -295,7 +298,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("cannot saveAll with non-authed user", (done) => { + it("cannot saveAll with non-authed user", (done) => { var user = new Parse.User(); user.signUp({ "password": "asdf", @@ -488,7 +491,7 @@ describe('Parse.User testing', () => { return promise._thenRunCallbacks(optionsOrCallback); } - it_exclude_dbs(['postgres'])("contained in user array queries", (done) => { + it("contained in user array queries", (done) => { var USERS = 4; var MESSAGES = 5; @@ -503,6 +506,11 @@ describe('Parse.User testing', () => { signUpAll(userList, function(users) { // Make a list of messages. + if (!users || users.length != USERS) { + fail('signupAll failed'); + done(); + return; + } var messageList = range(MESSAGES).map(function(i) { var message = new TestObject(); message.set("to", users[(i + 1) % USERS]); @@ -583,7 +591,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("count users", (done) => { + it("count users", (done) => { var james = new Parse.User(); james.set("username", "james"); james.set("password", "mypass"); @@ -711,7 +719,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("saving user after browser refresh", (done) => { + it("saving user after browser refresh", (done) => { var _ = Parse._; var id; @@ -859,7 +867,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("user on disk gets updated after save", (done) => { + it("user on disk gets updated after save", (done) => { var SuperUser = Parse.User.extend({ isSuper: function() { return true; @@ -1007,7 +1015,7 @@ describe('Parse.User testing', () => { } }); - it_exclude_dbs(['postgres'])("log in with provider", (done) => { + it("log in with provider", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1022,14 +1030,14 @@ describe('Parse.User testing', () => { done(); }, error: function(model, error) { - console.error(model, error); + jfail(error); ok(false, "linking should have worked"); done(); } }); }); - it_exclude_dbs(['postgres'])("user authData should be available in cloudcode (#2342)", (done) => { + it("user authData should be available in cloudcode (#2342)", (done) => { Parse.Cloud.define('checkLogin', (req, res) => { expect(req.user).not.toBeUndefined(); @@ -1052,14 +1060,14 @@ describe('Parse.User testing', () => { Parse.Cloud.run('checkLogin').then(done, done); }, error: function(model, error) { - console.error(model, error); + jfail(error); ok(false, "linking should have worked"); done(); } }); }); - it_exclude_dbs(['postgres'])("log in with provider and update token", (done) => { + it("log in with provider and update token", (done) => { var provider = getMockFacebookProvider(); var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token'); var errorHandler = function(err) { @@ -1093,7 +1101,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('returns authData when authed and logged in with provider (regression test for #1498)', done => { + it('returns authData when authed and logged in with provider (regression test for #1498)', done => { Parse.Object.enableSingleInstance(); let provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); @@ -1128,12 +1136,12 @@ describe('Parse.User testing', () => { }).then(() => { done(); }, error => { - fail(error); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])("log in with provider twice", (done) => { + it("log in with provider twice", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1164,14 +1172,14 @@ describe('Parse.User testing', () => { done(); }, error: function(model, error) { - fail(error); + jfail(error); ok(false, "LogIn should have worked"); done(); } }); }, error: function(model, error) { - console.error(model, error); + jfail(error); ok(false, "LogIn should have worked"); done(); } @@ -1208,7 +1216,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("login with provider should not call beforeSave trigger", (done) => { + it("login with provider should not call beforeSave trigger", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1232,7 +1240,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("link with provider", (done) => { + it("link with provider", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); var user = new Parse.User(); @@ -1372,7 +1380,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("unlink with provider", (done) => { + it("unlink with provider", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1408,7 +1416,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("unlink and link", (done) => { + it("unlink and link", (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1483,7 +1491,7 @@ describe('Parse.User testing', () => { done(); }, error: function(error) { - console.error(error); + jfail(error); fail('SHould not fail'); done(); } @@ -1501,7 +1509,7 @@ describe('Parse.User testing', () => { var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token'); var errorHandler = function(model, error) { - console.error(error); + jfail(error); fail('Should not fail'); done(); } @@ -1570,7 +1578,7 @@ describe('Parse.User testing', () => { }) }, error: function(error) { - console.error(error); + jfail(error); fail('SHould not fail'); done(); } @@ -1583,7 +1591,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should fail linking with existing', (done) => { + it('should fail linking with existing', (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1609,7 +1617,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should fail linking with existing', (done) => { + it('should fail linking with existing', (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1635,7 +1643,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should properly error when password is missing', (done) => { + it('should properly error when password is missing', (done) => { var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); Parse.User._logInWith("facebook", { @@ -1658,7 +1666,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should have authData in beforeSave and afterSave', (done) => { + it('should have authData in beforeSave and afterSave', (done) => { Parse.Cloud.beforeSave('_User', (request, response) => { let authData = request.object.get('authData'); @@ -1721,7 +1729,7 @@ describe('Parse.User testing', () => { })); }); - it_exclude_dbs(['postgres'])("log in with explicit facebook auth data", (done) => { + it("log in with explicit facebook auth data", (done) => { Parse.FacebookUtils.logIn({ id: "8675309", access_token: "jenny", @@ -1729,7 +1737,7 @@ describe('Parse.User testing', () => { }, expectSuccess({success: done})); }); - it_exclude_dbs(['postgres'])("log in async with explicit facebook auth data", (done) => { + it("log in async with explicit facebook auth data", (done) => { Parse.FacebookUtils.logIn({ id: "8675309", access_token: "jenny", @@ -1742,7 +1750,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("link with explicit facebook auth data", (done) => { + it("link with explicit facebook auth data", (done) => { Parse.User.signUp("mask", "open sesame", null, expectSuccess({ success: function(user) { Parse.FacebookUtils.link(user, { @@ -1750,14 +1758,14 @@ describe('Parse.User testing', () => { access_token: "jenny", expiration_date: new Date().toJSON() }).then(done, (error) => { - fail(error); + jfail(error); done(); }); } })); }); - it_exclude_dbs(['postgres'])("link async with explicit facebook auth data", (done) => { + it("link async with explicit facebook auth data", (done) => { Parse.User.signUp("mask", "open sesame", null, expectSuccess({ success: function(user) { Parse.FacebookUtils.link(user, { @@ -1936,7 +1944,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('unset user email', (done) => { + it('unset user email', (done) => { var user = new Parse.User(); user.set('username', 'test'); user.set('password', 'test'); @@ -2073,10 +2081,14 @@ describe('Parse.User testing', () => { url: 'http://localhost:8378/1/sessions' }, (error, response, body) => { expect(error).toBe(null); - var b = JSON.parse(body); - expect(b.results.length).toEqual(1); - expect(typeof b.results[0].user).toEqual('object'); - expect(b.results[0].user.objectId).toEqual(user.id); + try { + var b = JSON.parse(body); + expect(b.results.length).toEqual(1); + expect(typeof b.results[0].user).toEqual('object'); + expect(b.results[0].user.objectId).toEqual(user.id); + } catch(e) { + jfail(e); + } done(); }); }); @@ -2097,9 +2109,16 @@ describe('Parse.User testing', () => { url: 'http://localhost:8378/1/sessions' }, (error, response, body) => { expect(error).toBe(null); - var b = JSON.parse(body); - expect(b.results.length).toEqual(1); - var objId = b.results[0].objectId; + var objId; + try { + var b = JSON.parse(body); + expect(b.results.length).toEqual(1); + objId = b.results[0].objectId; + } catch(e) { + jfail(e); + done(); + return; + } request.del({ headers: { 'X-Parse-Application-Id': 'test', @@ -2162,7 +2181,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('test parse user become', (done) => { + it('test parse user become', (done) => { var sessionToken = null; Parse.Promise.as().then(function() { return Parse.User.signUp("flessard", "folo",{'foo':1}); @@ -2215,7 +2234,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])("session expiresAt correct format", (done) => { + it("session expiresAt correct format", (done) => { Parse.User.signUp("asdf", "zxcv", null, { success: function(user) { request.get({ @@ -2308,7 +2327,7 @@ describe('Parse.User testing', () => { }) }); - it_exclude_dbs(['postgres'])('should cleanup null authData keys ParseUser update (regression test for #1198, #2252)', (done) => { + it('should cleanup null authData keys ParseUser update (regression test for #1198, #2252)', (done) => { Parse.Cloud.beforeSave('_User', (req, res) => { req.object.set('foo', 'bar'); res.success(); @@ -2390,7 +2409,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should send email when upgrading from anon', (done) => { + it('should send email when upgrading from anon', (done) => { let emailCalled = false; let emailOptions; @@ -2437,7 +2456,7 @@ describe('Parse.User testing', () => { expect(emailOptions.user.get('email')).toEqual('user@email.com'); done(); }).catch((err) => { - console.error(err); + jfail(err); fail('no request should fail: ' + JSON.stringify(err)); done(); }); @@ -2484,7 +2503,7 @@ describe('Parse.User testing', () => { }); - it_exclude_dbs(['postgres'])('should fail to become user with expired token', (done) => { + it('should fail to become user with expired token', (done) => { let token; Parse.User.signUp("auser", "somepass", null) .then(user => rp({ @@ -2549,7 +2568,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should not overwrite username when unlinking facebook user (regression test for #1532)', done => { + it('should not overwrite username when unlinking facebook user (regression test for #1532)', done => { Parse.Object.disableSingleInstance(); var provider = getMockFacebookProvider(); Parse.User._registerAuthenticationProvider(provider); @@ -2577,12 +2596,12 @@ describe('Parse.User testing', () => { })) .catch(error => { fail('Unexpected failure testing in unlink user test'); - fail(error); + jfail(error); done(); }); }); - it_exclude_dbs(['postgres'])('should revoke sessions when converting anonymous user to "normal" user', done => { + it('should revoke sessions when converting anonymous user to "normal" user', done => { request.post({ url: 'http://localhost:8378/1/classes/_User', headers: { @@ -2618,7 +2637,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should not revoke session tokens if the server is configures to not revoke session tokens', done => { + it('should not revoke session tokens if the server is configures to not revoke session tokens', done => { reconfigureServer({ revokeSessionOnPasswordReset: false }) .then(() => { request.post({ @@ -2648,7 +2667,7 @@ describe('Parse.User testing', () => { }); }); - it_exclude_dbs(['postgres'])('should not fail querying non existing relations', done => { + it('should not fail querying non existing relations', done => { let user = new Parse.User(); user.set({ username: 'hello', diff --git a/spec/PointerPermissions.spec.js b/spec/PointerPermissions.spec.js index 4a1b048f64..27041a4de4 100644 --- a/spec/PointerPermissions.spec.js +++ b/spec/PointerPermissions.spec.js @@ -167,13 +167,13 @@ describe('Pointer Permissions', () => { expect(res.length).toBe(1); done(); }).catch((err) => { - console.error(err); + jfail(err); fail('should not fail'); done(); }) }); - it_exclude_dbs(['postgres'])('should not allow creating objects', (done) => { + it('should not allow creating objects', (done) => { let config = new Config(Parse.applicationId); let user = new Parse.User(); user.set({ @@ -465,7 +465,7 @@ describe('Pointer Permissions', () => { }); }); - it_exclude_dbs(['postgres'])('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => { + it('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => { /* tests: CLP: find/get open ({"*": true}) @@ -512,7 +512,7 @@ describe('Pointer Permissions', () => { }); }); - it_exclude_dbs(['postgres'])('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => { + it('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => { /* tests: CLP: find/get open ({"*": true}) @@ -557,7 +557,7 @@ describe('Pointer Permissions', () => { }); }); - it_exclude_dbs(['postgres'])('should let master key find objects', (done) => { + it('should let master key find objects', (done) => { let config = new Config(Parse.applicationId); let user = new Parse.User(); let object = new Parse.Object('AnObject'); @@ -587,7 +587,7 @@ describe('Pointer Permissions', () => { }) }); - it_exclude_dbs(['postgres'])('should let master key get objects', (done) => { + it('should let master key get objects', (done) => { let config = new Config(Parse.applicationId); let user = new Parse.User(); let object = new Parse.Object('AnObject'); @@ -619,7 +619,7 @@ describe('Pointer Permissions', () => { }); - it_exclude_dbs(['postgres'])('should let master key update objects', (done) => { + it('should let master key update objects', (done) => { let config = new Config(Parse.applicationId); let user = new Parse.User(); let object = new Parse.Object('AnObject'); @@ -647,7 +647,7 @@ describe('Pointer Permissions', () => { }) }); - it_exclude_dbs(['postgres'])('should let master key delete objects', (done) => { + it('should let master key delete objects', (done) => { let config = new Config(Parse.applicationId); let user = new Parse.User(); let object = new Parse.Object('AnObject'); diff --git a/spec/PromiseRouter.spec.js b/spec/PromiseRouter.spec.js index 5ba68681e4..b5323ef6e0 100644 --- a/spec/PromiseRouter.spec.js +++ b/spec/PromiseRouter.spec.js @@ -13,7 +13,7 @@ describe("PromiseRouter", () => { }); router.routes[0].handler({}).then((result) => { - console.error(result); + jfail(result); fail("this should not be called"); done(); }, (error)=> { diff --git a/spec/PurchaseValidation.spec.js b/spec/PurchaseValidation.spec.js index 384a6665e2..6574534a1c 100644 --- a/spec/PurchaseValidation.spec.js +++ b/spec/PurchaseValidation.spec.js @@ -22,9 +22,8 @@ function createProduct() { describe("test validate_receipt endpoint", () => { beforeEach( done => { createProduct().then(done).fail(function(err){ - console.error(err); done(); - }) + }); }) it_exclude_dbs(['postgres'])("should bypass appstore validation", (done) => { @@ -160,7 +159,7 @@ describe("test validate_receipt endpoint", () => { }); }); - it_exclude_dbs(['postgres'])("should not create a _Product", (done) => { + it("should not create a _Product", (done) => { var product = new Parse.Object("_Product"); product.save().then(function(){ fail("Should not be able to save"); @@ -173,7 +172,10 @@ describe("test validate_receipt endpoint", () => { it_exclude_dbs(['postgres'])("should be able to update a _Product", (done) => { var query = new Parse.Query("_Product"); - query.first().then(function(product){ + query.first().then(function(product) { + if (!product) { + return Promise.reject(new Error('Product should be found')); + } product.set("title", "a new title"); return product.save(); }).then(function(productAgain){ @@ -189,6 +191,9 @@ describe("test validate_receipt endpoint", () => { it_exclude_dbs(['postgres'])("should not be able to remove a require key in a _Product", (done) => { var query = new Parse.Query("_Product"); query.first().then(function(product){ + if (!product) { + return Promise.reject(new Error('Product should be found')); + } product.unset("title"); return product.save(); }).then(function(productAgain){ diff --git a/spec/PushController.spec.js b/spec/PushController.spec.js index e40195daf2..11d516c1c1 100644 --- a/spec/PushController.spec.js +++ b/spec/PushController.spec.js @@ -130,7 +130,7 @@ describe('PushController', () => { done(); }); - it_exclude_dbs(['postgres'])('properly increment badges', (done) => { + it('properly increment badges', (done) => { var payload = {data:{ alert: "Hello World!", @@ -184,13 +184,13 @@ describe('PushController', () => { }).then((result) => { done(); }, (err) => { - fail("should not fail"); + jfail(err); done(); }); }); - it_exclude_dbs(['postgres'])('properly set badges to 1', (done) => { + it('properly set badges to 1', (done) => { var payload = {data: { alert: "Hello World!", @@ -238,7 +238,7 @@ describe('PushController', () => { }); - it_exclude_dbs(['postgres'])('properly creates _PushStatus', (done) => { + it('properly creates _PushStatus', (done) => { var installations = []; while(installations.length != 10) { @@ -318,7 +318,7 @@ describe('PushController', () => { }); - it_exclude_dbs(['postgres'])('should properly report failures in _PushStatus', (done) => { + it('should properly report failures in _PushStatus', (done) => { var pushAdapter = { send: function(body, installations) { return installations.map((installation) => { @@ -397,7 +397,7 @@ describe('PushController', () => { }); }); - it_exclude_dbs(['postgres'])('should support object type for alert', (done) => { + it('should support object type for alert', (done) => { var payload = {data: { alert: { 'loc-key': 'hello_world', diff --git a/spec/PushRouter.spec.js b/spec/PushRouter.spec.js index 7b30ecfd45..9be3137a7a 100644 --- a/spec/PushRouter.spec.js +++ b/spec/PushRouter.spec.js @@ -68,7 +68,7 @@ describe('PushRouter', () => { done(); }); - it_exclude_dbs(['postgres'])('sends a push through REST', (done) => { + it('sends a push through REST', (done) => { request.post({ url: Parse.serverURL+"/push", json: true, diff --git a/spec/RestCreate.spec.js b/spec/RestCreate.spec.js index 155dd11bb0..fbc953ef65 100644 --- a/spec/RestCreate.spec.js +++ b/spec/RestCreate.spec.js @@ -11,7 +11,7 @@ var config = new Config('test'); let database = config.database; describe('rest create', () => { - it_exclude_dbs(['postgres'])('handles _id', done => { + it('handles _id', done => { rest.create(config, auth.nobody(config), 'Foo', {}) .then(() => database.adapter.find('Foo', { fields: {} }, {}, {})) .then(results => { @@ -23,7 +23,7 @@ describe('rest create', () => { }); }); - it_exclude_dbs(['postgres'])('handles array, object, date', (done) => { + it('handles array, object, date', (done) => { let now = new Date(); var obj = { array: [1, 2, 3], @@ -77,7 +77,7 @@ describe('rest create', () => { }); }); - it_exclude_dbs(['postgres'])('handles create on non-existent class when disabled client class creation', (done) => { + it('handles create on non-existent class when disabled client class creation', (done) => { var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {}) .then(() => { @@ -91,7 +91,7 @@ describe('rest create', () => { }); }); - it_exclude_dbs(['postgres'])('handles create on existent class when disabled client class creation', (done) => { + it('handles create on existent class when disabled client class creation', (done) => { var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); config.database.loadSchema() .then(schema => schema.addClassIfNotExists('ClientClassCreation', {})) @@ -122,7 +122,7 @@ describe('rest create', () => { }); }); - it_exclude_dbs(['postgres'])('handles anonymous user signup', (done) => { + it('handles anonymous user signup', (done) => { var data1 = { authData: { anonymous: { @@ -310,7 +310,7 @@ describe('rest create', () => { }); }); - it_exclude_dbs(['postgres'])("test default session length", (done) => { + it("test default session length", (done) => { var user = { username: 'asdf', password: 'zxcv', diff --git a/spec/RestQuery.spec.js b/spec/RestQuery.spec.js index a6c8d9e7e1..9e2b775922 100644 --- a/spec/RestQuery.spec.js +++ b/spec/RestQuery.spec.js @@ -134,7 +134,7 @@ describe('rest query', () => { }).catch((error) => { console.log(error); }); }); - it_exclude_dbs(['postgres'])('query non-existent class when disabled client class creation', (done) => { + it('query non-existent class when disabled client class creation', (done) => { var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); rest.find(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {}) .then(() => { @@ -148,7 +148,7 @@ describe('rest query', () => { }); }); - it_exclude_dbs(['postgres'])('query existent class when disabled client class creation', (done) => { + it('query existent class when disabled client class creation', (done) => { var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); config.database.loadSchema() .then(schema => schema.addClassIfNotExists('ClientClassCreation', {})) @@ -201,7 +201,7 @@ describe('rest query', () => { }); return Promise.all([p0, p1]); }).then(done).catch((err) => { - console.error(err); + jfail(err); fail('should not fail'); done(); }) @@ -221,7 +221,7 @@ describe('rest query', () => { }); }); - it_exclude_dbs(['postgres'])('query with limit = 0 and count = 1', (done) => { + it('query with limit = 0 and count = 1', (done) => { rest.create(config, nobody, 'TestObject', {foo: 'baz'} ).then(() => { return rest.create(config, nobody, diff --git a/spec/Schema.spec.js b/spec/Schema.spec.js index 2c6dc242b8..8148541953 100644 --- a/spec/Schema.spec.js +++ b/spec/Schema.spec.js @@ -30,7 +30,7 @@ describe('SchemaController', () => { }).then((schema) => { done(); }, (error) => { - fail(error); + jfail(error); done(); }); }); @@ -41,7 +41,7 @@ describe('SchemaController', () => { }).then((schema) => { done(); }, (error) => { - fail(error); + jfail(error); done(); }); }); @@ -99,7 +99,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('class-level permissions test user', (done) => { + it('class-level permissions test user', (done) => { var user; createTestUser().then((u) => { user = u; @@ -124,7 +124,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('class-level permissions test get', (done) => { + it('class-level permissions test get', (done) => { var obj; createTestUser() .then(user => { @@ -163,7 +163,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('can add classes without needing an object', done => { + it('can add classes without needing an object', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('NewClass', { foo: {type: 'String'} @@ -388,7 +388,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('will create classes', done => { + it('will create classes', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('NewClass', { aNumber: {type: 'Number'}, @@ -436,7 +436,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('creates the default fields for non-custom classes', done => { + it('creates the default fields for non-custom classes', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('_Installation', { foo: {type: 'Number'}, @@ -478,7 +478,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('creates non-custom classes which include relation field', done => { + it('creates non-custom classes which include relation field', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('_Role', {})) .then(actualSchema => { @@ -507,7 +507,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('creates non-custom classes which include pointer field', done => { + it('creates non-custom classes which include pointer field', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('_Session', {})) .then(actualSchema => { @@ -552,7 +552,7 @@ describe('SchemaController', () => { }); }); - it_exclude_dbs(['postgres'])('can check if a class exists', done => { + it('can check if a class exists', done => { config.database.loadSchema() .then(schema => { return schema.addClassIfNotExists('NewClass', {}) @@ -573,7 +573,7 @@ describe('SchemaController', () => { }) .catch(error => { fail('Couldn\'t create class'); - fail(error); + jfail(error); }); }) .catch(error => fail('Couldn\'t load schema')); @@ -654,7 +654,7 @@ describe('SchemaController', () => { } done(); }, error => { - fail(error); + jfail(error); done(); }); }); @@ -728,7 +728,7 @@ describe('SchemaController', () => { }); }) .catch(error => { - fail(error); + jfail(error); done(); }); }); diff --git a/spec/Uniqueness.spec.js b/spec/Uniqueness.spec.js index 43f130855e..cec72660b2 100644 --- a/spec/Uniqueness.spec.js +++ b/spec/Uniqueness.spec.js @@ -26,7 +26,7 @@ describe('Uniqueness', function() { }); }); - it_exclude_dbs(['postgres'])('unique indexing works on pointer fields', done => { + it('unique indexing works on pointer fields', done => { let obj = new Parse.Object('UniquePointer'); obj.save({ string: 'who cares' }) .then(() => obj.save({ ptr: obj })) @@ -52,7 +52,7 @@ describe('Uniqueness', function() { }); }); - it_exclude_dbs(['postgres'])('fails when attempting to ensure uniqueness of fields that are not currently unique', done => { + it('fails when attempting to ensure uniqueness of fields that are not currently unique', done => { let o1 = new Parse.Object('UniqueFail'); o1.set('key', 'val'); let o2 = new Parse.Object('UniqueFail'); diff --git a/spec/ValidationAndPasswordsReset.spec.js b/spec/ValidationAndPasswordsReset.spec.js index afd9ae7fab..fc4c329983 100644 --- a/spec/ValidationAndPasswordsReset.spec.js +++ b/spec/ValidationAndPasswordsReset.spec.js @@ -28,7 +28,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('sends verification email if email verification is enabled', done => { + it('sends verification email if email verification is enabled', done => { var emailAdapter = { sendVerificationEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(), @@ -97,7 +97,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('does send a validation email when updating the email', done => { + it('does send a validation email when updating the email', done => { var emailAdapter = { sendVerificationEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(), @@ -140,7 +140,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('does send a validation email with valid verification link when updating the email', done => { + it('does send a validation email with valid verification link when updating the email', done => { var emailAdapter = { sendVerificationEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(), @@ -238,7 +238,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => { + it('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => { reconfigureServer({ appName: 'test', publicServerURL: 'http://localhost:1337/1', @@ -271,7 +271,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => { + it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -314,20 +314,18 @@ describe("Custom Pages, Email Verification, Password Reset", () => { done(); }); }, (err) => { - console.error(err); + jfail(err); fail("this should not fail"); done(); - }).catch((err) => - { - console.error(err); - fail(err); + }).catch((err) => { + jfail(err); done(); }) }); }); }); - it_exclude_dbs(['postgres'])('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => { + it('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => { reconfigureServer({ appName: 'test', publicServerURL: 'http://localhost:1337/1', @@ -361,7 +359,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => { + it('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => { reconfigureServer({ appName: undefined, publicServerURL: 'http://localhost:1337/1', @@ -393,7 +391,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, have an appName, but have no publicServerURL and send a password reset email', done => { + it('fails if you include an emailAdapter, have an appName, but have no publicServerURL and send a password reset email', done => { reconfigureServer({ appName: undefined, emailAdapter: MockEmailAdapterWithOptions({ @@ -424,7 +422,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('fails if you set a publicServerURL, have an appName, but no emailAdapter and send a password reset email', done => { + it('fails if you set a publicServerURL, have an appName, but no emailAdapter and send a password reset email', done => { reconfigureServer({ appName: 'unused', publicServerURL: 'http://localhost:1337/1', @@ -452,7 +450,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('succeeds sending a password reset email if appName, publicServerURL, and email adapter are prodvided', done => { + it('succeeds sending a password reset email if appName, publicServerURL, and email adapter are prodvided', done => { reconfigureServer({ appName: 'coolapp', publicServerURL: 'http://localhost:1337/1', @@ -515,7 +513,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('receives the app name and user in the adapter', done => { + it('receives the app name and user in the adapter', done => { var emailSent = false; var emailAdapter = { sendVerificationEmail: options => { @@ -550,7 +548,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }) - it_exclude_dbs(['postgres'])('when you click the link in the email it sets emailVerified to true and redirects you', done => { + it('when you click the link in the email it sets emailVerified to true and redirects you', done => { var user = new Parse.User(); var sendEmailOptions; var emailAdapter = { @@ -583,13 +581,11 @@ describe("Custom Pages, Email Verification, Password Reset", () => { expect(user.get('emailVerified')).toEqual(true); done(); }, (err) => { - console.error(err); + jfail(err); fail("this should not fail"); done(); - }).catch((err) => - { - console.error(err); - fail(err); + }).catch((err) => { + jfail(err); done(); }) }); @@ -640,7 +636,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { }); }); - it_exclude_dbs(['postgres'])('does not update email verified if you use an invalid token', done => { + it('does not update email verified if you use an invalid token', done => { var user = new Parse.User(); var emailAdapter = { sendVerificationEmail: options => { @@ -688,7 +684,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { followRedirect: false, }, (error, response, body) => { if (error) { - console.error(error); + jfail(err); fail("Failed to get the reset link"); return; } @@ -713,7 +709,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { user.signUp().then(() => { Parse.User.requestPasswordReset('user@parse.com', { error: (err) => { - console.error(err); + jfail(err); fail("Should not fail requesting a password"); done(); } @@ -753,7 +749,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { followRedirect: false, }, (error, response, body) => { if (error) { - console.error(error); + jfail(error); fail("Failed to get the reset link"); return; } @@ -776,7 +772,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { followRedirect: false, }, (error, response, body) => { if (error) { - console.error(error); + jfail(error); fail("Failed to POST request password reset"); return; } @@ -793,7 +789,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { done(); }); }, (err) => { - console.error(err); + jfail(err); fail("should login with new password"); done(); }); @@ -816,7 +812,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => { user.signUp().then(() => { Parse.User.requestPasswordReset('user@parse.com', { error: (err) => { - console.error(err); + jfail(err); fail("Should not fail"); done(); } diff --git a/spec/helper.js b/spec/helper.js index 37d169f930..bfec460836 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -14,24 +14,43 @@ const GridStoreAdapter = require('../src/Adapters/Files/GridStoreAdapter').GridS const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter'); const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; +const postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; let databaseAdapter; +// need to bind for mocking mocha + +let startDB = () => {}; +let stopDB = () => {}; + if (process.env.PARSE_SERVER_TEST_DB === 'postgres') { - var postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; databaseAdapter = new PostgresStorageAdapter({ uri: postgresURI, collectionPrefix: 'test_', }); } else { + startDB = require('mongodb-runner/mocha/before').bind({ + timeout: () => {}, + slow: () => {} + }); + stopDB = require('mongodb-runner/mocha/after');; databaseAdapter = new MongoStorageAdapter({ uri: mongoURI, collectionPrefix: 'test_', - }) + }); } var port = 8378; let gridStoreAdapter = new GridStoreAdapter(mongoURI); - +let logLevel; +let silent = true; +if (process.env.VERBOSE) { + silent = false; + logLevel = 'verbose'; +} +if (process.env.PARSE_SERVER_LOG_LEVEL) { + silent = false; + logLevel = process.env.PARSE_SERVER_LOG_LEVEL; +} // Default server configuration for tests. var defaultConfiguration = { filesAdapter: gridStoreAdapter, @@ -45,7 +64,8 @@ var defaultConfiguration = { webhookKey: 'hook', masterKey: 'test', fileKey: 'test', - silent: !process.env.VERBOSE, + silent, + logLevel, push: { 'ios': { cert: 'prodCert.pem', @@ -65,17 +85,15 @@ var defaultConfiguration = { let openConnections = {}; // Set up a default API server for testing with default configuration. -var api = new ParseServer(defaultConfiguration); var app = express(); +var api = new ParseServer(defaultConfiguration); app.use('/1', api); - var server = app.listen(port); server.on('connection', connection => { let key = `${connection.remoteAddress}:${connection.remotePort}`; openConnections[key] = connection; connection.on('close', () => { delete openConnections[key] }); }); - // Allows testing specific configurations of Parse Server const reconfigureServer = changedConfiguration => { return new Promise((resolve, reject) => { @@ -111,6 +129,11 @@ Parse.serverURL = 'http://localhost:' + port + '/1'; // TODO: update tests to work in an A+ way Parse.Promise.disableAPlusCompliant(); +// 10 minutes timeout +beforeAll(startDB, 10*60*1000); + +afterAll(stopDB); + beforeEach(done => { try { Parse.User.enableUnsafeCurrentUser(); @@ -135,7 +158,9 @@ beforeEach(done => { Parse.serverURL = 'http://localhost:' + port + '/1'; done(); }, error => { - fail(JSON.stringify(error)); + Parse.initialize('test', 'test', 'test'); + Parse.serverURL = 'http://localhost:' + port + '/1'; + // fail(JSON.stringify(error)); done(); }) }); @@ -145,7 +170,9 @@ afterEach(function(done) { if (Object.keys(openConnections).length > 0) { fail('There were open connections to the server left after the test finished'); } - done(); + on_db('postgres', () => { + TestUtils.destroyAllDataPermanently().then(done, done); + }, done); }; Parse.Cloud._removeAllHooks(); databaseAdapter.getAllClasses() @@ -216,12 +243,12 @@ function strictEqual(a, b, message) { function notEqual(a, b, message) { expect(a).not.toEqual(b, message); } -function expectSuccess(params) { +function expectSuccess(params, done) { return { success: params.success, error: function(e) { - console.log('got error', e); fail('failure happened in expectSuccess'); + done ? done() : null; }, } } @@ -326,6 +353,9 @@ global.range = range; global.reconfigureServer = reconfigureServer; global.defaultConfiguration = defaultConfiguration; global.mockFacebookAuthenticator = mockFacebookAuthenticator; +global.jfail = function(err) { + fail(JSON.stringify(err)); +} global.it_exclude_dbs = excluded => { if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) { @@ -349,7 +379,18 @@ global.describe_only_db = db => { } else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') { return describe; } else { - return () => {}; + return () => {}; + } +} + +global.on_db = (db, callback, elseCallback) => { + if (process.env.PARSE_SERVER_TEST_DB == db) { + return callback(); + } else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') { + return callback(); + } + if (elseCallback) { + elseCallback(); } } diff --git a/spec/index.spec.js b/spec/index.spec.js index b5e4b26b36..c0c4a019e0 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -9,7 +9,7 @@ var express = require('express'); const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter'); describe('server', () => { - it_exclude_dbs(['postgres'])('requires a master key and app id', done => { + it('requires a master key and app id', done => { reconfigureServer({ appId: undefined }) .catch(error => { expect(error).toEqual('You must provide an appId!'); @@ -25,7 +25,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('support http basic authentication with masterkey', done => { + it('support http basic authentication with masterkey', done => { request.get({ url: 'http://localhost:8378/1/classes/TestObject', headers: { @@ -37,7 +37,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('support http basic authentication with javascriptKey', done => { + it('support http basic authentication with javascriptKey', done => { request.get({ url: 'http://localhost:8378/1/classes/TestObject', headers: { @@ -49,7 +49,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('fails if database is unreachable', done => { + it('fails if database is unreachable', done => { reconfigureServer({ databaseAdapter: new MongoStorageAdapter({ uri: 'mongodb://fake:fake@localhost:43605/drew3' }) }) .catch(() => { //Need to use rest api because saving via JS SDK results in fail() not getting called @@ -70,7 +70,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('can load email adapter via object', done => { + it('can load email adapter via object', done => { reconfigureServer({ appName: 'unused', verifyUserEmails: true, @@ -83,7 +83,7 @@ describe('server', () => { }).then(done, fail); }); - it_exclude_dbs(['postgres'])('can load email adapter via class', done => { + it('can load email adapter via class', done => { reconfigureServer({ appName: 'unused', verifyUserEmails: true, @@ -99,7 +99,7 @@ describe('server', () => { }).then(done, fail); }); - it_exclude_dbs(['postgres'])('can load email adapter via module name', done => { + it('can load email adapter via module name', done => { reconfigureServer({ appName: 'unused', verifyUserEmails: true, @@ -115,7 +115,7 @@ describe('server', () => { }).then(done, fail); }); - it_exclude_dbs(['postgres'])('can load email adapter via only module name', done => { + it('can load email adapter via only module name', done => { reconfigureServer({ appName: 'unused', verifyUserEmails: true, @@ -128,7 +128,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('throws if you initialize email adapter incorrecly', done => { + it('throws if you initialize email adapter incorrecly', done => { reconfigureServer({ appName: 'unused', verifyUserEmails: true, @@ -146,7 +146,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('can report the server version', done => { + it('can report the server version', done => { request.get({ url: 'http://localhost:8378/1/serverInfo', headers: { @@ -160,7 +160,7 @@ describe('server', () => { }) }); - it_exclude_dbs(['postgres'])('can create a parse-server v1', done => { + it('can create a parse-server v1', done => { var parseServer = new ParseServer.default(Object.assign({}, defaultConfiguration, { appId: "aTestApp", @@ -191,7 +191,7 @@ describe('server', () => { ); }); - it_exclude_dbs(['postgres'])('can create a parse-server v2', done => { + it('can create a parse-server v2', done => { let objId; let server let parseServer = ParseServer.ParseServer(Object.assign({}, @@ -221,13 +221,17 @@ describe('server', () => { }) .catch(error => { fail(JSON.stringify(error)) - done(); + if (server) { + server.close(done); + } else { + done(); + } }); }} )); }); - it_exclude_dbs(['postgres'])('has createLiveQueryServer', done => { + it('has createLiveQueryServer', done => { // original implementation through the factory expect(typeof ParseServer.ParseServer.createLiveQueryServer).toEqual('function'); // For import calls @@ -235,7 +239,7 @@ describe('server', () => { done(); }); - it_exclude_dbs(['postgres'])('exposes correct adapters', done => { + it('exposes correct adapters', done => { expect(ParseServer.S3Adapter).toThrow(); expect(ParseServer.GCSAdapter).toThrow('GCSAdapter is not provided by parse-server anymore; please install parse-server-gcs-adapter'); expect(ParseServer.FileSystemAdapter).toThrow(); @@ -243,7 +247,7 @@ describe('server', () => { done(); }); - it_exclude_dbs(['postgres'])('properly gives publicServerURL when set', done => { + it('properly gives publicServerURL when set', done => { reconfigureServer({ publicServerURL: 'https://myserver.com/1' }) .then(() => { var config = new Config('test', 'http://localhost:8378/1'); @@ -252,7 +256,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('properly removes trailing slash in mount', done => { + it('properly removes trailing slash in mount', done => { reconfigureServer({}) .then(() => { var config = new Config('test', 'http://localhost:8378/1/'); @@ -261,7 +265,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('should throw when getting invalid mount', done => { + it('should throw when getting invalid mount', done => { reconfigureServer({ publicServerURL: 'blabla:/some' }) .catch(error => { expect(error).toEqual('publicServerURL should be a valid HTTPS URL starting with https://') @@ -269,7 +273,7 @@ describe('server', () => { }) }); - it_exclude_dbs(['postgres'])('fails if the session length is not a number', done => { + it('fails if the session length is not a number', done => { reconfigureServer({ sessionLength: 'test' }) .catch(error => { expect(error).toEqual('Session length must be a valid number.'); @@ -277,7 +281,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('fails if the session length is less than or equal to 0', done => { + it('fails if the session length is less than or equal to 0', done => { reconfigureServer({ sessionLength: '-33' }) .catch(error => { expect(error).toEqual('Session length must be a value greater than 0.'); @@ -289,7 +293,7 @@ describe('server', () => { }); }); - it_exclude_dbs(['postgres'])('ignores the session length when expireInactiveSessions set to false', (done) => { + it('ignores the session length when expireInactiveSessions set to false', (done) => { reconfigureServer({ sessionLength: '-33', expireInactiveSessions: false @@ -301,7 +305,7 @@ describe('server', () => { .then(done); }) - it_exclude_dbs(['postgres'])('fails if you try to set revokeSessionOnPasswordReset to non-boolean', done => { + it('fails if you try to set revokeSessionOnPasswordReset to non-boolean', done => { reconfigureServer({ revokeSessionOnPasswordReset: 'non-bool' }) .catch(done); }); diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 3ad733a227..20f9319c1b 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -159,7 +159,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('creates _User schema when server starts', done => { + it('creates _User schema when server starts', done => { request.get({ url: 'http://localhost:8378/1/schemas', json: true, @@ -317,7 +317,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('responds with all fields when you create a class', done => { + it('responds with all fields when you create a class', done => { request.post({ url: 'http://localhost:8378/1/schemas', headers: masterKeyHeaders, @@ -346,7 +346,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('responds with all fields when getting incomplete schema', done => { + it('responds with all fields when getting incomplete schema', done => { config.database.loadSchema() .then(schemaController => schemaController.addClassIfNotExists('_Installation', {}, defaultClassLevelPermissions)) .then(() => { @@ -387,7 +387,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('lets you specify class name in both places', done => { + it('lets you specify class name in both places', done => { request.post({ url: 'http://localhost:8378/1/schemas/NewClass', headers: masterKeyHeaders, @@ -600,7 +600,7 @@ describe('schemas', () => { }) }); - it_exclude_dbs(['postgres'])('lets you add fields', done => { + it('lets you add fields', done => { request.post({ url: 'http://localhost:8378/1/schemas/NewClass', headers: masterKeyHeaders, @@ -650,7 +650,7 @@ describe('schemas', () => { }) }); - it_exclude_dbs(['postgres'])('lets you add fields to system schema', done => { + it('lets you add fields to system schema', done => { request.post({ url: 'http://localhost:8378/1/schemas/_User', headers: masterKeyHeaders, @@ -963,7 +963,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('should set/get schema permissions', done => { + it('should set/get schema permissions', done => { request.post({ url: 'http://localhost:8378/1/schemas/AClass', headers: masterKeyHeaders, @@ -1245,7 +1245,7 @@ describe('schemas', () => { }); } - it_exclude_dbs(['postgres'])('validate CLP 1', done => { + it('validate CLP 1', done => { let user = new Parse.User(); user.setUsername('user'); user.setPassword('user'); @@ -1294,7 +1294,7 @@ describe('schemas', () => { }) }); - it_exclude_dbs(['postgres'])('validate CLP 2', done => { + it('validate CLP 2', done => { let user = new Parse.User(); user.setUsername('user'); user.setPassword('user'); @@ -1417,7 +1417,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('validate CLP 4', done => { + it('validate CLP 4', done => { let user = new Parse.User(); user.setUsername('user'); user.setPassword('user'); @@ -1485,7 +1485,7 @@ describe('schemas', () => { }) }); - it_exclude_dbs(['postgres'])('validate CLP 5', done => { + it('validate CLP 5', done => { let user = new Parse.User(); user.setUsername('user'); user.setPassword('user'); @@ -1567,7 +1567,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])('can login when addFields is false (issue #1355)', (done) => { + it('can login when addFields is false (issue #1355)', (done) => { setPermissionsOnClass('_User', { 'create': {'*': true}, 'addField': {} @@ -1599,7 +1599,7 @@ describe('schemas', () => { }); }); - it_exclude_dbs(['postgres'])("regression test for #1991", done => { + it("regression test for #1991", done => { let user = new Parse.User(); user.setUsername('user'); user.setPassword('user'); @@ -1630,7 +1630,7 @@ describe('schemas', () => { done(); }).catch((err) => { fail('should not fail'); - console.error(err); + jfail(err); done(); }); }); diff --git a/src/Adapters/Files/GridStoreAdapter.js b/src/Adapters/Files/GridStoreAdapter.js index 8cd56b6cf9..b5dac2b7f8 100644 --- a/src/Adapters/Files/GridStoreAdapter.js +++ b/src/Adapters/Files/GridStoreAdapter.js @@ -17,7 +17,6 @@ export class GridStoreAdapter extends FilesAdapter { constructor(mongoDatabaseURI = defaults.DefaultMongoURI) { super(); this._databaseURI = mongoDatabaseURI; - this._connect(); } _connect() { diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 44c116ad7f..7fb426c55c 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -363,6 +363,10 @@ export class MongoStorageAdapter { return this._adaptiveCollection(className) .then(collection => collection.count(transformWhere(className, query, schema))); } + + performInitialization() { + return Promise.resolve(); + } } export default MongoStorageAdapter; diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 9ea1742d77..9405f36c06 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -716,10 +716,13 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => { restObject._hashed_password = mongoObject[key]; break; case '_acl': + break; case '_email_verify_token': case '_perishable_token': case '_tombstone': case '_email_verify_token_expires_at': + // Those keys will be deleted if needed in the DB Controller + restObject[key] = mongoObject[key]; break; case '_session_token': restObject['sessionToken'] = mongoObject[key]; diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index b11756359f..2a4590d19c 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -4,15 +4,25 @@ const PostgresRelationDoesNotExistError = '42P01'; const PostgresDuplicateRelationError = '42P07'; const PostgresDuplicateColumnError = '42701'; const PostgresUniqueIndexViolationError = '23505'; +const logger = require('../../../logger'); + +const debug = function(){ + let args = [...arguments]; + args = ['PG: '+arguments[0]].concat(args.slice(1, args.length)); + let log = logger.getLogger(); + log.debug.apply(log, args); +} const parseTypeToPostgresType = type => { switch (type.type) { case 'String': return 'text'; - case 'Date': return 'timestamp'; + case 'Date': return 'timestamp with time zone'; case 'Object': return 'jsonb'; + case 'File': return 'jsonb'; case 'Boolean': return 'boolean'; case 'Pointer': return 'char(10)'; case 'Number': return 'double precision'; + case 'GeoPoint': return 'point'; case 'Array': if (type.contents && type.contents.type === 'String') { return 'text[]'; @@ -23,25 +33,144 @@ const parseTypeToPostgresType = type => { } }; +const ParseToPosgresComparator = { + '$gt': '>', + '$lt': '<', + '$gte': '>=', + '$lte': '<=' +} + +const toPostgresValue = value => { + if (typeof value === 'object') { + if (value.__type === 'Date') { + return value.iso; + } + } + return value; +} + +const transformValue = value => { + if (value.__type == 'Pointer') { + return value.objectId; + } + return value; +} + +// Duplicate from then mongo adapter... +const emptyCLPS = Object.freeze({ + find: {}, + get: {}, + create: {}, + update: {}, + delete: {}, + addField: {}, +}); + +const defaultCLPS = Object.freeze({ + find: {'*': true}, + get: {'*': true}, + create: {'*': true}, + update: {'*': true}, + delete: {'*': true}, + addField: {'*': true}, +}); + +const toParseSchema = (schema) => { + if (schema.className === '_User') { + delete schema.fields._hashed_password; + } + if (schema.fields) { + delete schema.fields._wperm; + delete schema.fields._rperm; + } + let clps = defaultCLPS; + if (schema.classLevelPermissions) { + clps = {...emptyCLPS, ...schema.classLevelPermissions}; + } + return { + className: schema.className, + fields: schema.fields, + classLevelPermissions: clps, + }; +} + +const toPostgresSchema = (schema) => { + if (!schema) { + return schema; + } + schema.fields = schema.fields || {}; + schema.fields._wperm = {type: 'Array', contents: {type: 'String'}} + schema.fields._rperm = {type: 'Array', contents: {type: 'String'}} + if (schema.className === '_User') { + schema.fields._hashed_password = {type: 'String'}; + } + return schema; +} + const buildWhereClause = ({ schema, query, index }) => { let patterns = []; let values = []; + let sorts = []; + + schema = toPostgresSchema(schema); for (let fieldName in query) { + let initialPatternsLength = patterns.length; let fieldValue = query[fieldName]; - if (typeof fieldValue === 'string') { + if (fieldName.indexOf('.') >= 0) { + let components = fieldName.split('.').map((cmpt, index) => { + if (index == 0) { + return `"${cmpt}"`; + } + return `'${cmpt}'`;  + }); + let name = components.slice(0, components.length-1).join('->'); + name+='->>'+components[components.length-1]; + patterns.push(`${name} = '${fieldValue}'`); + } else if (typeof fieldValue === 'string') { patterns.push(`$${index}:name = $${index + 1}`); values.push(fieldName, fieldValue); index += 2; - } else if (fieldValue.$ne) { - patterns.push(`$${index}:name <> $${index + 1}`); - values.push(fieldName, fieldValue.$ne); + } else if (typeof fieldValue === 'boolean') { + patterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue); + index += 2; + } else if (typeof fieldValue === 'number') { + patterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue); index += 2; } else if (fieldName === '$or') { - fieldValue.map(subQuery => buildWhereClause({ schema, query: subQuery, index })).forEach(result => { - patterns.push(result.pattern); - values.push(...result.values); + let clauses = []; + let clauseValues = []; + fieldValue.forEach((subQuery, idx) =>  { + let clause = buildWhereClause({ schema, query: subQuery, index }); + clauses.push(clause.pattern); + clauseValues.push(...clause.values); + index += clause.values.length; }); - } else if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'Array') { + patterns.push(`(${clauses.join(' OR ')})`); + values.push(...clauseValues); + } + + if (fieldValue.$ne) { + if (fieldValue.$ne === null) { + patterns.push(`$${index}:name <> $${index + 1}`); + } else { + // if not null, we need to manually exclude null + patterns.push(`($${index}:name <> $${index + 1} OR $${index}:name IS NULL)`); + } + + // TODO: support arrays + values.push(fieldName, fieldValue.$ne); + index += 2; + } + + if (fieldValue.$eq) { + patterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue.$eq); + index += 2; + } + const isInOrNin = Array.isArray(fieldValue.$in) || Array.isArray(fieldValue.$nin); + if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'Array') { let inPatterns = []; let allowNull = false; values.push(fieldName); @@ -59,24 +188,93 @@ const buildWhereClause = ({ schema, query, index }) => { patterns.push(`$${index}:name && ARRAY[${inPatterns.join(',')}]`); } index = index + 1 + inPatterns.length; - } else if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'String') { - let inPatterns = []; + } else if (isInOrNin) { + var createConstraint = (baseArray, notIn) => { + if (baseArray.length > 0) { + let inPatterns = []; + values.push(fieldName); + baseArray.forEach((listElem, listIndex) => { + values.push(listElem); + inPatterns.push(`$${index + 1 + listIndex}`); + }); + let not = notIn ? 'NOT' : ''; + patterns.push(`$${index}:name ${not} IN (${inPatterns.join(',')})`); + index = index + 1 + inPatterns.length; + } else if (!notIn) { + values.push(fieldName); + patterns.push(`$${index}:name IS NULL`); + index = index + 1; + } + } + if (fieldValue.$in) { + createConstraint(fieldValue.$in, false); + } + if (fieldValue.$nin) { + createConstraint(fieldValue.$nin, true); + } + } + + if (typeof fieldValue.$exists !== 'undefined') { + if (fieldValue.$exists) { + patterns.push(`$${index}:name IS NOT NULL`); + } else { + patterns.push(`$${index}:name IS NULL`); + } values.push(fieldName); - fieldValue.$in.forEach((listElem, listIndex) => { - values.push(listElem); - inPatterns.push(`$${index + 1 + listIndex}`); - }); - patterns.push(`$${index}:name IN (${inPatterns.join(',')})`); - index = index + 1 + inPatterns.length; - } else if (fieldValue.__type === 'Pointer') { + index += 1; + } + + if (fieldValue.$nearSphere) { + let point = fieldValue.$nearSphere; + let distance = fieldValue.$maxDistance; + let distanceInKM = distance*6371*1000; + patterns.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index+1}, $${index+2})::geometry) <= $${index+3}`); + sorts.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index+1}, $${index+2})::geometry) ASC`) + values.push(fieldName, point.latitude, point.longitude, distanceInKM); + index += 4; + } + + if (fieldValue.$regex) { + let regex = fieldValue.$regex; + let operator = '~'; + let opts = fieldValue.$options; + if (opts) { + if (opts.indexOf('i') >= 0) { + operator = '~*'; + } + } + patterns.push(`$${index}:name ${operator} $${index+1}`); + values.push(fieldName, regex); + index += 2; + } + + if (fieldValue.__type === 'Pointer') { patterns.push(`$${index}:name = $${index + 1}`); values.push(fieldName, fieldValue.objectId); index += 2; - } else { - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this query type yet`); + } + + if (fieldValue.__type === 'Date') { + patterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue.iso); + index += 2; + } + + Object.keys(ParseToPosgresComparator).forEach(cmp => { + if (fieldValue[cmp]) { + let pgComparator = ParseToPosgresComparator[cmp]; + patterns.push(`$${index}:name ${pgComparator} $${index + 1}`); + values.push(fieldName, toPostgresValue(fieldValue[cmp])); + index += 2; + } + }); + + if (initialPatternsLength === patterns.length) { + throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this query type yet ${JSON.stringify(fieldValue)}`); } } - return { pattern: patterns.join(' AND '), values }; + values = values.map(transformValue); + return { pattern: patterns.join(' AND '), values, sorts }; } export class PostgresStorageAdapter { @@ -95,7 +293,7 @@ export class PostgresStorageAdapter { _ensureSchemaCollectionExists() { return this._client.none('CREATE TABLE "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )') .catch(error => { - if (error.code === PostgresDuplicateRelationError) { + if (error.code === PostgresDuplicateRelationError || error.code === PostgresUniqueIndexViolationError) { // Table already exists, must have been created by a different request. Ignore error. } else { throw error; @@ -108,42 +306,80 @@ export class PostgresStorageAdapter { } setClassLevelPermissions(className, CLPs) { - return notImplemented(); + return this._ensureSchemaCollectionExists().then(() => { + const values = [className, 'schema', 'classLevelPermissions', CLPs] + return this._client.none(`UPDATE "_SCHEMA" SET $2:name = json_object_set_key($2:name, $3::text, $4::jsonb) WHERE "className"=$1 `, values); + }).catch((err) => { + console.error("ERR!!!", err); + return Promise.reject(err); + }) } createClass(className, schema) { + return this.createTable(className, schema) + .then(() => this._client.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($, $, true)', { className, schema })) + .then(() => { + return toParseSchema(schema) + }); + } + + // Just create a table, do not insert in schema + createTable(className, schema) { + debug('createTable', className, schema); let valuesArray = []; let patternsArray = []; - Object.keys(schema.fields).forEach((fieldName, index) => { - valuesArray.push(fieldName); - let parseType = schema.fields[fieldName]; + let fields = Object.assign({}, schema.fields); + if (className === '_User') { + fields._email_verify_token_expires_at = {type: 'Date'}; + fields._email_verify_token = {type: 'String'}; + } + let index = 2; + let relations = []; + Object.keys(fields).forEach((fieldName) => { + let parseType = fields[fieldName]; + // Skip when it's a relation + // We'll create the tables later + if (parseType.type == 'Relation') { + relations.push(fieldName) + return; + } if (['_rperm', '_wperm'].includes(fieldName)) { parseType.contents = { type: 'String' }; } + valuesArray.push(fieldName); valuesArray.push(parseTypeToPostgresType(parseType)); - patternsArray.push(`$${index * 2 + 2}:name $${index * 2 + 3}:raw`); + patternsArray.push(`$${index}:name $${index+1}:raw`); + index = index+2; }); + const qs = `CREATE TABLE $1:name (${patternsArray.join(',')}, PRIMARY KEY ("objectId"))`; + const values = [className, ...valuesArray]; return this._ensureSchemaCollectionExists() - .then(() => this._client.none(`CREATE TABLE $1:name (${patternsArray.join(',')})`, [className, ...valuesArray])) + .then(() => this._client.none(qs, values)) .catch(error => { if (error.code === PostgresDuplicateRelationError) { // Table already exists, must have been created by a different request. Ignore error. } else { throw error; } - }) - .then(() => this._client.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($, $, true)', { className, schema })) - .then(() => schema); + }).then(() => { + // Create the relation tables + return Promise.all(relations.map((fieldName) => { + return this._client.none('CREATE TABLE IF NOT EXISTS $ ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`}) + })); + }); } addFieldIfNotExists(className, fieldName, type) { // TODO: Must be revised for invalid logic... + debug('addFieldIfNotExists', {className, fieldName, type}); return this._client.tx("addFieldIfNotExists", t=> { - return t.none('ALTER TABLE $ ADD COLUMN $ $', { - className, - fieldName, - postgresType: parseTypeToPostgresType(type) - }) + let promise = Promise.resolve(); + if (type.type !== 'Relation') { + promise = t.none('ALTER TABLE $ ADD COLUMN $ $', { + className, + fieldName, + postgresType: parseTypeToPostgresType(type) + }) .catch(error => { if (error.code === PostgresRelationDoesNotExistError) { return this.createClass(className, {fields: {[fieldName]: type}}) @@ -154,18 +390,22 @@ export class PostgresStorageAdapter { throw error; } }) - .then(() => t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $', {className})) - .then(result => { - if (fieldName in result[0].schema) { - throw "Attempted to add a field that already exists"; - } else { - result[0].schema.fields[fieldName] = type; - return t.none( - 'UPDATE "_SCHEMA" SET "schema"=$ WHERE "className"=$', - {schema: result[0].schema, className} - ); - } - }) + } else { + promise = t.none('CREATE TABLE IF NOT EXISTS $ ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`}) + } + return promise.then(() => { + return t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $', {className}); + }).then(result => { + if (fieldName in result[0].schema) { + throw "Attempted to add a field that already exists"; + } else { + result[0].schema.fields[fieldName] = type; + return t.none( + 'UPDATE "_SCHEMA" SET "schema"=$ WHERE "className"=$', + {schema: result[0].schema, className} + ); + } + }); }); } @@ -177,10 +417,20 @@ export class PostgresStorageAdapter { // Delete all data known to this adapter. Used for testing. deleteAllClasses() { - return this._client.any('SELECT "className" FROM "_SCHEMA"') + let now = new Date().getTime(); + debug('deleteAllClasses'); + return this._client.any('SELECT * FROM "_SCHEMA"') .then(results => { - const classes = ['_SCHEMA', ...results.map(result => result.className)]; - return this._client.tx(t=>t.batch(classes.map(className=>t.none('DROP TABLE $', { className })))); + let joins = results.reduce((list, schema) => { + Object.keys(schema.schema.fields).forEach((field) => { + if (schema.schema.fields[field].type === 'Relation') { + list.push(`_Join:${field}:${schema.className}`); + } + }) + return list; + }, []); + const classes = ['_SCHEMA','_PushStatus','_Hooks','_GlobalConfig', ...results.map(result => result.className), ...joins]; + return this._client.tx(t=>t.batch(classes.map(className=>t.none('DROP TABLE IF EXISTS $', { className })))); }, error => { if (error.code === PostgresRelationDoesNotExistError) { // No _SCHEMA collection. Don't delete anything. @@ -188,7 +438,9 @@ export class PostgresStorageAdapter { } else { throw error; } - }) + }).then(() => { + debug(`deleteAllClasses done in ${new Date().getTime() - now}`); + }); } // Remove the column and all the data. For Relations, the _Join collection is handled @@ -213,7 +465,8 @@ export class PostgresStorageAdapter { // rejection reason are TBD. getAllClasses() { return this._ensureSchemaCollectionExists() - .then(() => this._client.map('SELECT * FROM "_SCHEMA"', null, row => ({ className: row.className, ...row.schema }))); + .then(() => this._client.map('SELECT * FROM "_SCHEMA"', null, row => ({ className: row.className, ...row.schema }))) + .then(res => res.map(toParseSchema)) } // Return a promise for the schema with the given name, in Parse format. If @@ -227,15 +480,37 @@ export class PostgresStorageAdapter { } else { throw undefined; } - }); + }).then(toParseSchema); } // TODO: remove the mongo format dependency in the return value createObject(className, schema, object) { + debug('createObject', className, object); let columnsArray = []; + let newFieldsArray = []; let valuesArray = []; + schema = toPostgresSchema(schema); + let geoPoints = {}; Object.keys(object).forEach(fieldName => { + var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/); + if (authDataMatch) { + var provider = authDataMatch[1]; + object['authData'] = object['authData'] || {}; + object['authData'][provider] = object[fieldName]; + delete object[fieldName]; + fieldName = 'authData'; + } + columnsArray.push(fieldName); + if (!schema.fields[fieldName] && className === '_User') { + if (fieldName == '_email_verify_token') { + valuesArray.push(object[fieldName]); + } + if (fieldName == '_email_verify_token_expires_at') { + valuesArray.push(object[fieldName].iso); + } + return; + } switch (schema.fields[fieldName].type) { case 'Date': valuesArray.push(object[fieldName].iso); @@ -249,29 +524,42 @@ export class PostgresStorageAdapter { } else { valuesArray.push(JSON.stringify(object[fieldName])); } - break; + break; case 'Object': - valuesArray.push(object[fieldName]); - break; case 'String': - valuesArray.push(object[fieldName]); - break; case 'Number': - valuesArray.push(object[fieldName]); - break; case 'Boolean': + case 'File': valuesArray.push(object[fieldName]); break; + case 'GeoPoint': + // pop the point and process later + geoPoints[fieldName] = object[fieldName]; + columnsArray.pop(); + break; default: throw `Type ${schema.fields[fieldName].type} not supported yet`; break; } }); + + columnsArray = columnsArray.concat(Object.keys(geoPoints)); + let initialValues = valuesArray.map((val, index) => `$${index + 2 + columnsArray.length}${(['_rperm','_wperm'].includes(columnsArray[index])) ? '::text[]' : ''}`); + + let geoPointsInjects = Object.keys(geoPoints).map((key, idx) => { + let value = geoPoints[key]; + valuesArray.push(value.latitude, value.longitude); + let l = valuesArray.length + columnsArray.length; + return `POINT($${l}, $${l+1})`; + }); + let columnsPattern = columnsArray.map((col, index) => `$${index + 2}:name`).join(','); - let valuesPattern = valuesArray.map((val, index) => `$${index + 2 + columnsArray.length}${(['_rperm','_wperm'].includes(columnsArray[index])) ? '::text[]' : ''}`).join(','); + let valuesPattern = initialValues.concat(geoPointsInjects).join(',') + let qs = `INSERT INTO $1:name (${columnsPattern}) VALUES (${valuesPattern})` let values = [className, ...columnsArray, ...valuesArray] - return this._client.none(qs, values) + debug(qs, values); + return this._client.any(qs, values) .then(() => ({ ops: [object] })) .catch(error => { if (error.code === PostgresUniqueIndexViolationError) { @@ -286,7 +574,17 @@ export class PostgresStorageAdapter { // If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined. // If there is some other error, reject with INTERNAL_SERVER_ERROR. deleteObjectsByQuery(className, schema, query) { - return this._client.one(`WITH deleted AS (DELETE FROM $ RETURNING *) SELECT count(*) FROM deleted`, { className }, a => +a.count) + debug('deleteObjectsByQuery', className, query); + let values = [className]; + let index = 2; + let where = buildWhereClause({ schema, index, query }) + values.push(...where.values); + if (Object.keys(query).length == 0) { + where.pattern = 'TRUE'; + } + let qs = `WITH deleted AS (DELETE FROM $1:name WHERE ${where.pattern} RETURNING *) SELECT count(*) FROM deleted`; + debug(qs, values); + return this._client.one(qs, values , a => +a.count) .then(count => { if (count === 0) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); @@ -298,19 +596,30 @@ export class PostgresStorageAdapter { // Apply the update to all objects that match the given Parse Query. updateObjectsByQuery(className, schema, query, update) { - return notImplemented(); + debug('updateObjectsByQuery', className, query, update); + return this.findOneAndUpdate(className, schema, query, update); } // Return value not currently well specified. findOneAndUpdate(className, schema, query, update) { + debug('findOneAndUpdate', className, query, update); let conditionPatterns = []; let updatePatterns = []; let values = [className] let index = 2; - + schema = toPostgresSchema(schema); for (let fieldName in update) { let fieldValue = update[fieldName]; - if (fieldValue.__op === 'Increment') { + var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/); + if (authDataMatch) { + var provider = authDataMatch[1]; + let value = update[fieldName]; + delete update[fieldName]; + fieldName = 'authData'; + updatePatterns.push(`$${index}:name = json_object_set_key($${index}:name, $${index+1}::text, $${index+2}::jsonb)`); + values.push(fieldName, provider, value); + index += 3; + } else if (fieldValue.__op === 'Increment') { updatePatterns.push(`$${index}:name = COALESCE($${index}:name, 0) + $${index + 1}`); values.push(fieldName, fieldValue.amount); index += 2; @@ -318,23 +627,61 @@ export class PostgresStorageAdapter { updatePatterns.push(`$${index}:name = COALESCE($${index}:name, '[]'::jsonb) || $${index + 1}`); values.push(fieldName, fieldValue.objects); index += 2; + } else if (fieldValue.__op === 'Delete') { + updatePatterns.push(`$${index}:name = $${index + 1}`) + values.push(fieldName, null); + index += 2; } else if (fieldValue.__op === 'Remove') { return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support Remove operator.')); } else if (fieldValue.__op === 'AddUnique') { - return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support AddUnique operator')); + return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support AddUnique operator.')); } else if (fieldName === 'updatedAt') { //TODO: stop special casing this. It should check for __type === 'Date' and use .iso updatePatterns.push(`$${index}:name = $${index + 1}`) - values.push(fieldName, new Date(fieldValue)); + values.push(fieldName, fieldValue); index += 2; } else if (typeof fieldValue === 'string') { updatePatterns.push(`$${index}:name = $${index + 1}`); values.push(fieldName, fieldValue); index += 2; + } else if (typeof fieldValue === 'boolean') { + updatePatterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue); + index += 2; } else if (fieldValue.__type === 'Pointer') { updatePatterns.push(`$${index}:name = $${index + 1}`); values.push(fieldName, fieldValue.objectId); index += 2; + } else if (fieldValue.__type === 'Date') { + updatePatterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, toPostgresValue(fieldValue)); + index += 2; + } else if (fieldValue.__type === 'GeoPoint') { + updatePatterns.push(`$${index}:name = POINT($${index + 1}, $${index + 2})`); + values.push(fieldName, fieldValue.latitude, fieldValue.longitude); + index += 3; + } else if (typeof fieldValue === 'number') { + updatePatterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue); + index += 2; + } else if (typeof fieldValue === 'object' + && schema.fields[fieldName] + && schema.fields[fieldName].type == 'Object') { + updatePatterns.push(`$${index}:name = $${index + 1}`); + values.push(fieldName, fieldValue); + index += 2; + } else if (Array.isArray(fieldValue) + && schema.fields[fieldName] + && schema.fields[fieldName].type == 'Array') { + let expectedType = parseTypeToPostgresType(schema.fields[fieldName]); + if (expectedType === 'text[]') { + updatePatterns.push(`$${index}:name = $${index + 1}::text[]`); + } else { + updatePatterns.push(`$${index}:name = array_to_json($${index + 1}::text[])::jsonb`); + } + values.push(fieldName, fieldValue); + index += 2; } else { + debug('Not supported update', fieldName, fieldValue); return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support update ${JSON.stringify(fieldValue)} yet`)); } } @@ -343,31 +690,83 @@ export class PostgresStorageAdapter { values.push(...where.values); let qs = `UPDATE $1:name SET ${updatePatterns.join(',')} WHERE ${where.pattern} RETURNING *`; - return this._client.any(qs, values) + debug('update: ', qs, values); + return this._client.any(qs, values) .then(val => val[0]); // TODO: This is unsafe, verification is needed, or a different query method; } // Hopefully, we can get rid of this. It's only used for config and hooks. upsertOneObject(className, schema, query, update) { - return notImplemented(); + debug('upsertOneObject', {className, query, update}); + return this.createObject(className, schema, update).catch((err) => { + // ignore duplicate value errors as it's upsert + if (err.code == Parse.Error.DUPLICATE_VALUE) { + return; + } + throw err; + }); } find(className, schema, query, { skip, limit, sort }) { + debug('find', className, query, {skip, limit, sort}); + const hasLimit = limit !== undefined; + const hasSkip = skip !== undefined; let values = [className]; let where = buildWhereClause({ schema, query, index: 2 }) values.push(...where.values); - + const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : ''; - const limitPattern = limit !== undefined ? `LIMIT $${values.length + 1}` : ''; - - const qs = `SELECT * FROM $1:name ${wherePattern} ${limitPattern}`; - if (limit !== undefined) { + const limitPattern = hasLimit ? `LIMIT $${values.length + 1}` : ''; + if (hasLimit) { values.push(limit); } + const skipPattern = hasSkip ? `OFFSET $${values.length+1}` : ''; + if (hasSkip) { + values.push(skip); + } + + let sortPattern = ''; + if (sort) { + let sorting = Object.keys(sort).map((key) => { + // Using $idx pattern gives: non-integer constant in ORDER BY + if (sort[key] === 1) { + return `"${key}" ASC`; + } + return `"${key}" DESC`; + }).join(','); + sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? `ORDER BY ${sorting}` : ''; + } + if (where.sorts && Object.keys(where.sorts).length > 0) { + sortPattern = `ORDER BY ${where.sorts.join(',')}`; + } + + const qs = `SELECT * FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern}`; + debug(qs, values); return this._client.any(qs, values) + .catch((err) => { + // Query on non existing table, don't crash + if (err.code === PostgresRelationDoesNotExistError) { + return []; + } + return Promise.reject(err); + }) .then(results => results.map(object => { - Object.keys(schema.fields).filter(field => schema.fields[field].type === 'Pointer').forEach(fieldName => { - object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass }; + Object.keys(schema.fields).forEach(fieldName => { + if (schema.fields[fieldName].type === 'Pointer' && object[fieldName]) { + object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass }; + } + if (schema.fields[fieldName].type === 'Relation') { + object[fieldName] = { + __type: "Relation", + className: schema.fields[fieldName].targetClass + } + } + if (object[fieldName] && schema.fields[fieldName].type === 'GeoPoint') { + object[fieldName] = { + latitude: object[fieldName].x, + longitude: object[fieldName].y + } + } }); //TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field. if (object.createdAt) { @@ -393,7 +792,7 @@ export class PostgresStorageAdapter { } return object; - })) + })); } // Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't @@ -411,6 +810,9 @@ export class PostgresStorageAdapter { .catch(error => { if (error.code === PostgresDuplicateRelationError && error.message.includes(constraintName)) { // Index already exists. Ignore error. + } else if (error.code === PostgresUniqueIndexViolationError && error.message.includes(constraintName)) { + // Cast the error into the proper parse error + throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided'); } else { throw error; } @@ -427,11 +829,46 @@ export class PostgresStorageAdapter { const qs = `SELECT count(*) FROM $1:name ${wherePattern}`; return this._client.one(qs, values, a => +a.count); } + + performInitialization({ VolatileClassesSchemas }) { + let now = new Date().getTime(); + debug('performInitialization'); + let promises = VolatileClassesSchemas.map((schema) => { + return this.createTable(schema.className, schema); + }); + + return Promise.all(promises).then(() => { + return this._client.any(json_object_set_key).catch((err) => { + console.error(err); + }) + }).then(() => { + debug(`initialzationDone in ${new Date().getTime() - now}`); + }) + } } function notImplemented() { return Promise.reject(new Error('Not implemented yet.')); } +// Function to set a key on a nested JSON document +const json_object_set_key = 'CREATE OR REPLACE FUNCTION "json_object_set_key"(\ + "json" jsonb,\ + "key_to_set" TEXT,\ + "value_to_set" anyelement\ +)\ + RETURNS jsonb \ + LANGUAGE sql \ + IMMUTABLE \ + STRICT \ +AS $function$\ +SELECT concat(\'{\', string_agg(to_json("key") || \':\' || "value", \',\'), \'}\')::jsonb\ + FROM (SELECT *\ + FROM jsonb_each("json")\ + WHERE "key" <> "key_to_set"\ + UNION ALL\ + SELECT "key_to_set", to_json("value_to_set")::jsonb) AS "fields"\ +$function$;' + export default PostgresStorageAdapter; module.exports = PostgresStorageAdapter; // Required for tests diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index f0dbb902cd..e94202c83a 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -159,12 +159,18 @@ const filterSensitiveData = (isMaster, aclGroup, className, object) => { delete object.sessionToken; - if (isMaster || (aclGroup.indexOf(object.objectId) > -1)) { + if (isMaster) { return object; } + delete object._email_verify_token; + delete object._perishable_token; + delete object._tombstone; + delete object._email_verify_token_expires_at; + if ((aclGroup.indexOf(object.objectId) > -1)) { + return object; + } delete object.authData; - return object; }; @@ -204,7 +210,7 @@ DatabaseController.prototype.update = function(className, query, update, { query = addWriteACL(query, acl); } validateQuery(query); - return schemaController.getOneSchema(className) + return schemaController.getOneSchema(className, true) .catch(error => { // If the schema doesn't exist, pretend it exists with no fields. This behaviour // will likely need revisiting. @@ -899,7 +905,10 @@ DatabaseController.prototype.performInitizalization = function() { logger.warn('Unable to ensure uniqueness for user email addresses: ', error); return Promise.reject(error); }); - return Promise.all([usernameUniqueness, emailUniqueness]); + + // Create tables for volatile classes + let adapterInit = this.adapter.performInitialization({ VolatileClassesSchemas: SchemaController.VolatileClassesSchemas }); + return Promise.all([usernameUniqueness, emailUniqueness, adapterInit]); } function joinTableName(className, key) { diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 02208bc39b..50f7a94202 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -76,7 +76,7 @@ const defaultColumns = Object.freeze({ "pushTime": {type:'String'}, "source": {type:'String'}, // rest or webui "query": {type:'String'}, // the stringified JSON query - "payload": {type:'Object'}, // the JSON payload, + "payload": {type:'String'}, // the stringified JSON payload, "title": {type:'String'}, "expiry": {type:'Number'}, "status": {type:'String'}, @@ -256,7 +256,15 @@ const injectDefaultSchema = ({className, fields, classLevelPermissions}) => ({ ...fields, }, classLevelPermissions, -}) +}); + +const VolatileClassesSchemas = volatileClasses.map((className) => { + return convertSchemaToAdapterSchema(injectDefaultSchema({ + className, + fields: {}, + classLevelPermissions: {} + })); +}); const dbTypeMatchesObjectType = (dbType, objectType) => { if (dbType.type !== objectType.type) return false; @@ -900,4 +908,5 @@ export { systemClasses, defaultColumns, convertSchemaToAdapterSchema, + VolatileClassesSchemas, }; diff --git a/src/cli/parse-server.js b/src/cli/parse-server.js index 1ab5403b92..de84a50c41 100755 --- a/src/cli/parse-server.js +++ b/src/cli/parse-server.js @@ -4,7 +4,6 @@ import { ParseServer } from '../index'; import definitions from './cli-definitions'; import program from './utils/commander'; import { mergeWithOptions } from './utils/commander'; -import colors from 'colors'; program.loadDefinitions(definitions); @@ -44,7 +43,7 @@ if (!options.serverURL) { if (!options.appId || !options.masterKey || !options.serverURL) { program.outputHelp(); console.error(""); - console.error(colors.red("ERROR: appId and masterKey are required")); + console.error('\u001b[31mERROR: appId and masterKey are required\u001b[0m'); console.error(""); process.exit(1); } diff --git a/src/pushStatusHandler.js b/src/pushStatusHandler.js index f8c95d635a..d52a21943d 100644 --- a/src/pushStatusHandler.js +++ b/src/pushStatusHandler.js @@ -48,12 +48,13 @@ export default function pushStatusHandler(config) { // lockdown! ACL: {} } - - lastPromise = database.create(PUSH_STATUS_COLLECTION, object).then(() => { - pushStatus = { - objectId - }; - return Promise.resolve(pushStatus); + lastPromise = Promise.resolve().then(() => { + return database.create(PUSH_STATUS_COLLECTION, object).then(() => { + pushStatus = { + objectId + }; + return Promise.resolve(pushStatus); + }); }); return lastPromise; }