* Removes runtime dependency babel-polyfill (#2692) * Removes runtime dependency babel-polyfill * removes references to polyfilled array includes * Better support for polyfilling * Removes unnecessary log * Adds killswitch if tests are polyfilled * Reverts usage of includes on strings
437 lines
11 KiB
JavaScript
437 lines
11 KiB
JavaScript
"use strict"
|
||
// Sets up a Parse API server for testing.
|
||
|
||
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 5000;
|
||
|
||
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) {
|
||
return elseCallback();
|
||
}
|
||
}
|
||
|
||
if (global._babelPolyfill) {
|
||
console.error('We should not use polyfilled tests');
|
||
process.exit(1);
|
||
}
|
||
|
||
var cache = require('../src/cache').default;
|
||
var express = require('express');
|
||
var facebook = require('../src/authDataManager/facebook');
|
||
var ParseServer = require('../src/index').ParseServer;
|
||
var path = require('path');
|
||
var TestUtils = require('../src/TestUtils');
|
||
var MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
|
||
const GridStoreAdapter = require('../src/Adapters/Files/GridStoreAdapter').GridStoreAdapter;
|
||
const FSAdapter = require('parse-server-fs-adapter');
|
||
const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter');
|
||
const RedisCacheAdapter = require('../src/Adapters/Cache/RedisCacheAdapter').default;
|
||
|
||
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') {
|
||
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 filesAdapter;
|
||
|
||
on_db('mongo', () => {
|
||
filesAdapter = new GridStoreAdapter(mongoURI);
|
||
}, () => {
|
||
filesAdapter = new FSAdapter();
|
||
});
|
||
|
||
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,
|
||
serverURL: 'http://localhost:' + port + '/1',
|
||
databaseAdapter,
|
||
appId: 'test',
|
||
javascriptKey: 'test',
|
||
dotNetKey: 'windows',
|
||
clientKey: 'client',
|
||
restAPIKey: 'rest',
|
||
webhookKey: 'hook',
|
||
masterKey: 'test',
|
||
fileKey: 'test',
|
||
silent,
|
||
logLevel,
|
||
push: {
|
||
'ios': {
|
||
cert: 'prodCert.pem',
|
||
key: 'prodKey.pem',
|
||
production: true,
|
||
bundleId: 'bundleId',
|
||
}
|
||
},
|
||
oauth: { // Override the facebook provider
|
||
facebook: mockFacebook(),
|
||
myoauth: {
|
||
module: path.resolve(__dirname, "myoauth") // relative path as it's run from src
|
||
}
|
||
}
|
||
};
|
||
|
||
if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
|
||
defaultConfiguration.cacheAdapter = new RedisCacheAdapter();
|
||
}
|
||
|
||
let openConnections = {};
|
||
|
||
// Set up a default API server for testing with default configuration.
|
||
var app = express();
|
||
var api = new ParseServer(defaultConfiguration);
|
||
app.use('/1', api);
|
||
app.use('/1', (req, res) => {
|
||
fail('should not call next');
|
||
});
|
||
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) => {
|
||
server.close(() => {
|
||
try {
|
||
let newConfiguration = Object.assign({}, defaultConfiguration, changedConfiguration, {
|
||
__indexBuildCompletionCallbackForTests: indexBuildPromise => indexBuildPromise.then(resolve, reject)
|
||
});
|
||
cache.clear();
|
||
app = express();
|
||
api = new ParseServer(newConfiguration);
|
||
api.use(require('./testing-routes').router);
|
||
app.use('/1', api);
|
||
app.use('/1', (req, res) => {
|
||
fail('should not call next');
|
||
});
|
||
server = app.listen(port);
|
||
server.on('connection', connection => {
|
||
let key = `${connection.remoteAddress}:${connection.remotePort}`;
|
||
openConnections[key] = connection;
|
||
connection.on('close', () => { delete openConnections[key] });
|
||
});
|
||
} catch(error) {
|
||
reject(error);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// Set up a Parse client to talk to our test API server
|
||
var Parse = require('parse/node');
|
||
Parse.serverURL = 'http://localhost:' + port + '/1';
|
||
|
||
// This is needed because we ported a bunch of tests from the non-A+ way.
|
||
// 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();
|
||
} catch (error) {
|
||
if (error !== 'You need to call Parse.initialize before using Parse.') {
|
||
throw error;
|
||
}
|
||
}
|
||
TestUtils.destroyAllDataPermanently()
|
||
.catch(error => {
|
||
// For tests that connect to their own mongo, there won't be any data to delete.
|
||
if (error.message === 'ns not found' || error.message.startsWith('connect ECONNREFUSED')) {
|
||
return;
|
||
} else {
|
||
fail(error);
|
||
return;
|
||
}
|
||
})
|
||
.then(reconfigureServer)
|
||
.then(() => {
|
||
Parse.initialize('test', 'test', 'test');
|
||
Parse.serverURL = 'http://localhost:' + port + '/1';
|
||
done();
|
||
}, error => {
|
||
Parse.initialize('test', 'test', 'test');
|
||
Parse.serverURL = 'http://localhost:' + port + '/1';
|
||
// fail(JSON.stringify(error));
|
||
done();
|
||
})
|
||
});
|
||
|
||
afterEach(function(done) {
|
||
let afterLogOut = () => {
|
||
if (Object.keys(openConnections).length > 0) {
|
||
fail('There were open connections to the server left after the test finished');
|
||
}
|
||
on_db('postgres', () => {
|
||
TestUtils.destroyAllDataPermanently().then(done, done);
|
||
}, done);
|
||
};
|
||
Parse.Cloud._removeAllHooks();
|
||
databaseAdapter.getAllClasses()
|
||
.then(allSchemas => {
|
||
allSchemas.forEach((schema) => {
|
||
var className = schema.className;
|
||
expect(className).toEqual({ asymmetricMatch: className => {
|
||
if (!className.startsWith('_')) {
|
||
return true;
|
||
} else {
|
||
// Other system classes will break Parse.com, so make sure that we don't save anything to _SCHEMA that will
|
||
// break it.
|
||
return ['_User', '_Installation', '_Role', '_Session', '_Product'].indexOf(className) >= 0;
|
||
}
|
||
}});
|
||
});
|
||
})
|
||
.then(() => Parse.User.logOut())
|
||
.then(afterLogOut, afterLogOut)
|
||
});
|
||
|
||
var TestObject = Parse.Object.extend({
|
||
className: "TestObject"
|
||
});
|
||
var Item = Parse.Object.extend({
|
||
className: "Item"
|
||
});
|
||
var Container = Parse.Object.extend({
|
||
className: "Container"
|
||
});
|
||
|
||
// Convenience method to create a new TestObject with a callback
|
||
function create(options, callback) {
|
||
var t = new TestObject(options);
|
||
t.save(null, { success: callback });
|
||
}
|
||
|
||
function createTestUser(success, error) {
|
||
var user = new Parse.User();
|
||
user.set('username', 'test');
|
||
user.set('password', 'moon-y');
|
||
var promise = user.signUp();
|
||
if (success || error) {
|
||
promise.then(function(user) {
|
||
if (success) {
|
||
success(user);
|
||
}
|
||
}, function(err) {
|
||
if (error) {
|
||
error(err);
|
||
}
|
||
});
|
||
} else {
|
||
return promise;
|
||
}
|
||
}
|
||
|
||
// Shims for compatibility with the old qunit tests.
|
||
function ok(bool, message) {
|
||
expect(bool).toBeTruthy(message);
|
||
}
|
||
function equal(a, b, message) {
|
||
expect(a).toEqual(b, message);
|
||
}
|
||
function strictEqual(a, b, message) {
|
||
expect(a).toBe(b, message);
|
||
}
|
||
function notEqual(a, b, message) {
|
||
expect(a).not.toEqual(b, message);
|
||
}
|
||
function expectSuccess(params, done) {
|
||
return {
|
||
success: params.success,
|
||
error: function(e) {
|
||
fail('failure happened in expectSuccess');
|
||
done ? done() : null;
|
||
},
|
||
}
|
||
}
|
||
function expectError(errorCode, callback) {
|
||
return {
|
||
success: function(result) {
|
||
console.log('got result', result);
|
||
fail('expected error but got success');
|
||
},
|
||
error: function(obj, e) {
|
||
// Some methods provide 2 parameters.
|
||
e = e || obj;
|
||
if (!e) {
|
||
fail('expected a specific error but got a blank error');
|
||
return;
|
||
}
|
||
expect(e.code).toEqual(errorCode, e.message);
|
||
if (callback) {
|
||
callback(e);
|
||
}
|
||
},
|
||
}
|
||
}
|
||
|
||
// Because node doesn't have Parse._.contains
|
||
function arrayContains(arr, item) {
|
||
return -1 != arr.indexOf(item);
|
||
}
|
||
|
||
// Normalizes a JSON object.
|
||
function normalize(obj) {
|
||
if (obj === null || typeof obj !== 'object') {
|
||
return JSON.stringify(obj);
|
||
}
|
||
if (obj instanceof Array) {
|
||
return '[' + obj.map(normalize).join(', ') + ']';
|
||
}
|
||
var answer = '{';
|
||
for (var key of Object.keys(obj).sort()) {
|
||
answer += key + ': ';
|
||
answer += normalize(obj[key]);
|
||
answer += ', ';
|
||
}
|
||
answer += '}';
|
||
return answer;
|
||
}
|
||
|
||
// Asserts two json structures are equal.
|
||
function jequal(o1, o2) {
|
||
expect(normalize(o1)).toEqual(normalize(o2));
|
||
}
|
||
|
||
function range(n) {
|
||
var answer = [];
|
||
for (var i = 0; i < n; i++) {
|
||
answer.push(i);
|
||
}
|
||
return answer;
|
||
}
|
||
|
||
function mockFacebookAuthenticator(id, token) {
|
||
var facebook = {};
|
||
facebook.validateAuthData = function(authData) {
|
||
if (authData.id === id && authData.access_token.startsWith(token)) {
|
||
return Promise.resolve();
|
||
} else {
|
||
throw undefined;
|
||
}
|
||
};
|
||
facebook.validateAppId = function(appId, authData) {
|
||
if (authData.access_token.startsWith(token)) {
|
||
return Promise.resolve();
|
||
} else {
|
||
throw undefined;
|
||
}
|
||
};
|
||
return facebook;
|
||
}
|
||
|
||
function mockFacebook() {
|
||
return mockFacebookAuthenticator('8675309', 'jenny');
|
||
}
|
||
|
||
|
||
|
||
// This is polluting, but, it makes it way easier to directly port old tests.
|
||
global.Parse = Parse;
|
||
global.TestObject = TestObject;
|
||
global.Item = Item;
|
||
global.Container = Container;
|
||
global.create = create;
|
||
global.createTestUser = createTestUser;
|
||
global.ok = ok;
|
||
global.equal = equal;
|
||
global.strictEqual = strictEqual;
|
||
global.notEqual = notEqual;
|
||
global.expectSuccess = expectSuccess;
|
||
global.expectError = expectError;
|
||
global.arrayContains = arrayContains;
|
||
global.jequal = jequal;
|
||
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.indexOf(process.env.PARSE_SERVER_TEST_DB) >= 0) {
|
||
return xit;
|
||
} else {
|
||
return it;
|
||
}
|
||
}
|
||
|
||
global.fit_exclude_dbs = excluded => {
|
||
if (excluded.indexOf(process.env.PARSE_SERVER_TEST_DB) >= 0) {
|
||
return xit;
|
||
} else {
|
||
return fit;
|
||
}
|
||
}
|
||
|
||
global.describe_only_db = db => {
|
||
if (process.env.PARSE_SERVER_TEST_DB == db) {
|
||
return describe;
|
||
} else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') {
|
||
return describe;
|
||
} else {
|
||
return () => {};
|
||
}
|
||
}
|
||
|
||
|
||
var libraryCache = {};
|
||
jasmine.mockLibrary = function(library, name, mock) {
|
||
var original = require(library)[name];
|
||
if (!libraryCache[library]) {
|
||
libraryCache[library] = {};
|
||
}
|
||
require(library)[name] = mock;
|
||
libraryCache[library][name] = original;
|
||
}
|
||
|
||
jasmine.restoreLibrary = function(library, name) {
|
||
if (!libraryCache[library] || !libraryCache[library][name]) {
|
||
throw 'Can not find library ' + library + ' ' + name;
|
||
}
|
||
require(library)[name] = libraryCache[library][name];
|
||
}
|