const auth = require('../lib/Auth'); const Config = require('../lib/Config'); const rest = require('../lib/rest'); const request = require('../lib/request'); const AudiencesRouter = require('../lib/Routers/AudiencesRouter').AudiencesRouter; describe('AudiencesRouter', () => { let loggerErrorSpy; beforeEach(() => { const logger = require('../lib/logger').default; loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); }); it('uses find condition from request.body', done => { const config = Config.get('test'); const androidAudienceRequest = { name: 'Android Users', query: '{ "test": "android" }', }; const iosAudienceRequest = { name: 'Iphone Users', query: '{ "test": "ios" }', }; const request = { config: config, auth: auth.master(config), body: { where: { query: '{ "test": "android" }', }, }, query: {}, info: {}, }; const router = new AudiencesRouter(); rest .create(config, auth.nobody(config), '_Audience', androidAudienceRequest) .then(() => { return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest); }) .then(() => { return router.handleFind(request); }) .then(res => { const 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 => { const config = Config.get('test'); const androidAudienceRequest = { name: 'Android Users', query: '{ "test": "android" }', }; const iosAudienceRequest = { name: 'Iphone Users', query: '{ "test": "ios" }', }; const request = { config: config, auth: auth.master(config), body: {}, query: { where: { query: '{ "test": "android" }', }, }, info: {}, }; const router = new AudiencesRouter(); rest .create(config, auth.nobody(config), '_Audience', androidAudienceRequest) .then(() => { return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest); }) .then(() => { return router.handleFind(request); }) .then(res => { const results = res.response.results; expect(results.length).toEqual(1); done(); }) .catch(err => { fail(err); done(); }); }); it('query installations with limit = 0', done => { const config = Config.get('test'); const androidAudienceRequest = { name: 'Android Users', query: '{ "test": "android" }', }; const iosAudienceRequest = { name: 'Iphone Users', query: '{ "test": "ios" }', }; const request = { config: config, auth: auth.master(config), body: {}, query: { limit: 0, }, info: {}, }; Config.get('test'); const router = new AudiencesRouter(); rest .create(config, auth.nobody(config), '_Audience', androidAudienceRequest) .then(() => { return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest); }) .then(() => { return router.handleFind(request); }) .then(res => { const response = res.response; expect(response.results.length).toEqual(0); done(); }) .catch(err => { fail(JSON.stringify(err)); done(); }); }); it_exclude_dbs(['postgres'])('query installations with count = 1', done => { const config = Config.get('test'); const androidAudienceRequest = { name: 'Android Users', query: '{ "test": "android" }', }; const iosAudienceRequest = { name: 'Iphone Users', query: '{ "test": "ios" }', }; const request = { config: config, auth: auth.master(config), body: {}, query: { count: 1, }, info: {}, }; const router = new AudiencesRouter(); rest .create(config, auth.nobody(config), '_Audience', androidAudienceRequest) .then(() => rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest)) .then(() => router.handleFind(request)) .then(res => { const response = res.response; expect(response.results.length).toEqual(2); expect(response.count).toEqual(2); done(); }) .catch(error => { fail(JSON.stringify(error)); done(); }); }); it_exclude_dbs(['postgres'])('query installations with limit = 0 and count = 1', done => { const config = Config.get('test'); const androidAudienceRequest = { name: 'Android Users', query: '{ "test": "android" }', }; const iosAudienceRequest = { name: 'Iphone Users', query: '{ "test": "ios" }', }; const request = { config: config, auth: auth.master(config), body: {}, query: { limit: 0, count: 1, }, info: {}, }; const router = new AudiencesRouter(); rest .create(config, auth.nobody(config), '_Audience', androidAudienceRequest) .then(() => { return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest); }) .then(() => { return router.handleFind(request); }) .then(res => { const response = res.response; expect(response.results.length).toEqual(0); expect(response.count).toEqual(2); done(); }) .catch(err => { fail(JSON.stringify(err)); done(); }); }); it('should create, read, update and delete audiences throw api', done => { Parse._request( 'POST', 'push_audiences', { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }) }, { useMasterKey: true } ).then(() => { Parse._request('GET', 'push_audiences', {}, { useMasterKey: true }).then(results => { expect(results.results.length).toEqual(1); expect(results.results[0].name).toEqual('My Audience'); expect(results.results[0].query.deviceType).toEqual('ios'); Parse._request( 'GET', `push_audiences/${results.results[0].objectId}`, {}, { useMasterKey: true } ).then(results => { expect(results.name).toEqual('My Audience'); expect(results.query.deviceType).toEqual('ios'); Parse._request( 'PUT', `push_audiences/${results.objectId}`, { name: 'My Audience 2' }, { useMasterKey: true } ).then(() => { Parse._request( 'GET', `push_audiences/${results.objectId}`, {}, { useMasterKey: true } ).then(results => { expect(results.name).toEqual('My Audience 2'); expect(results.query.deviceType).toEqual('ios'); Parse._request( 'DELETE', `push_audiences/${results.objectId}`, {}, { useMasterKey: true } ).then(() => { Parse._request('GET', 'push_audiences', {}, { useMasterKey: true }).then( results => { expect(results.results.length).toEqual(0); done(); } ); }); }); }); }); }); }); }); it('should only create with master key', done => { loggerErrorSpy.calls.reset(); Parse._request('POST', 'push_audiences', { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }), }).then( () => {}, error => { expect(error.message).toEqual('Permission denied'); expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required')); done(); } ); }); it('should only find with master key', done => { loggerErrorSpy.calls.reset(); Parse._request('GET', 'push_audiences', {}).then( () => {}, error => { expect(error.message).toEqual('Permission denied'); expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required')); done(); } ); }); it('should only get with master key', done => { loggerErrorSpy.calls.reset(); Parse._request('GET', `push_audiences/someId`, {}).then( () => {}, error => { expect(error.message).toEqual('Permission denied'); expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required')); done(); } ); }); it('should only update with master key', done => { loggerErrorSpy.calls.reset(); Parse._request('PUT', `push_audiences/someId`, { name: 'My Audience 2', }).then( () => {}, error => { expect(error.message).toEqual('Permission denied'); expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required')); done(); } ); }); it('should only delete with master key', done => { loggerErrorSpy.calls.reset(); Parse._request('DELETE', `push_audiences/someId`, {}).then( () => {}, error => { expect(error.message).toEqual('Permission denied'); expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required')); done(); } ); }); it_id('af1111b5-3251-4b40-8f06-fb0fc624fa91')(it_exclude_dbs(['postgres']))('should support legacy parse.com audience fields', done => { const database = Config.get(Parse.applicationId).database.adapter.database; const now = new Date(); Parse._request( 'POST', 'push_audiences', { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }) }, { useMasterKey: true } ).then(audience => { database .collection('test__Audience') .updateOne( { _id: audience.objectId }, { $set: { times_used: 1, _last_used: now, }, } ) .then(result => { expect(result).toBeTruthy(); database .collection('test__Audience') .find({ _id: audience.objectId }) .toArray() .then(rows => { expect(rows[0]['times_used']).toEqual(1); expect(rows[0]['_last_used']).toEqual(now); Parse._request( 'GET', 'push_audiences/' + audience.objectId, {}, { useMasterKey: true } ) .then(audience => { expect(audience.name).toEqual('My Audience'); expect(audience.query.deviceType).toEqual('ios'); expect(audience.timesUsed).toEqual(1); expect(audience.lastUsed).toEqual(now.toISOString()); done(); }) .catch(error => { done.fail(error); }); }) .catch(error => { done.fail(error); }); }); }); }); it('should be able to search on audiences', done => { Parse._request( 'POST', 'push_audiences', { name: 'neverUsed', query: JSON.stringify({ deviceType: 'ios' }) }, { useMasterKey: true } ).then(() => { const query = { timesUsed: { $exists: false }, lastUsed: { $exists: false }, }; Parse._request( 'GET', 'push_audiences?order=-createdAt&limit=1', { where: query }, { useMasterKey: true } ) .then(results => { expect(results.results.length).toEqual(1); const audience = results.results[0]; expect(audience.name).toEqual('neverUsed'); done(); }) .catch(error => { done.fail(error); }); }); }); it('should handle _Audience invalid fields via rest', async () => { await reconfigureServer({ appId: 'test', restAPIKey: 'test', publicServerURL: 'http://localhost:8378/1', }); try { await request({ method: 'POST', url: 'http://localhost:8378/1/classes/_Audience', body: { lorem: 'ipsum', _method: 'POST' }, headers: { 'X-Parse-Application-Id': 'test', 'X-Parse-REST-API-Key': 'test', 'Content-Type': 'application/json', }, }); expect(true).toBeFalsy(); } catch (e) { expect(e.data.code).toBe(107); expect(e.data.error).toBe('Could not add field lorem'); } }); });