diff --git a/spec/Parse.Push.spec.js b/spec/Parse.Push.spec.js index b0fd60e8..df2b0028 100644 --- a/spec/Parse.Push.spec.js +++ b/spec/Parse.Push.spec.js @@ -2,327 +2,230 @@ const request = require('../lib/request'); -const delayPromise = delay => { - return new Promise(resolve => { - setTimeout(resolve, delay); +const pushCompleted = async pushId => { + let result = await Parse.Push.getPushStatus(pushId); + while (!(result && result.get('status') === 'succeeded')) { + result = await Parse.Push.getPushStatus(pushId); + } +}; + +const successfulAny = function (body, installations) { + const promises = installations.map(device => { + return Promise.resolve({ + transmitted: true, + device: device, + }); }); + + return Promise.all(promises); +}; + +const provideInstallations = function (num) { + if (!num) { + num = 2; + } + + const installations = []; + while (installations.length !== num) { + // add Android installations + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('deviceType', 'android'); + installations.push(installation); + } + + return installations; +}; + +const losingAdapter = { + send: function (body, installations) { + // simulate having lost an installation before this was called + // thus invalidating our 'count' in _PushStatus + installations.pop(); + + return successfulAny(body, installations); + }, + getValidPushTypes: function () { + return ['android']; + }, +}; + +const setup = function () { + const sendToInstallationSpy = jasmine.createSpy(); + + const pushAdapter = { + send: function (body, installations) { + const badge = body.data.badge; + const promises = installations.map(installation => { + sendToInstallationSpy(installation); + + if (installation.deviceType == 'ios') { + expect(installation.badge).toEqual(badge); + expect(installation.originalBadge + 1).toEqual(installation.badge); + } else { + expect(installation.badge).toBeUndefined(); + } + return Promise.resolve({ + err: null, + device: installation, + transmitted: true, + }); + }); + return Promise.all(promises); + }, + getValidPushTypes: function () { + return ['ios', 'android']; + }, + }; + + return reconfigureServer({ + appId: Parse.applicationId, + masterKey: Parse.masterKey, + serverURL: Parse.serverURL, + push: { + adapter: pushAdapter, + }, + }) + .then(() => { + const installations = []; + while (installations.length != 10) { + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('badge', installations.length); + installation.set('originalBadge', installations.length); + installation.set('deviceType', 'ios'); + installations.push(installation); + } + return Parse.Object.saveAll(installations); + }) + .then(() => { + return { + sendToInstallationSpy, + }; + }); }; describe('Parse.Push', () => { - const setup = function () { - const sendToInstallationSpy = jasmine.createSpy(); - - const pushAdapter = { - send: function (body, installations) { - const badge = body.data.badge; - const promises = installations.map(installation => { - sendToInstallationSpy(installation); - - if (installation.deviceType == 'ios') { - expect(installation.badge).toEqual(badge); - expect(installation.originalBadge + 1).toEqual(installation.badge); - } else { - expect(installation.badge).toBeUndefined(); - } - return Promise.resolve({ - err: null, - device: installation, - transmitted: true, - }); - }); - return Promise.all(promises); + it('should properly send push', async () => { + const { sendToInstallationSpy } = await setup(); + const pushStatusId = await Parse.Push.send({ + where: { + deviceType: 'ios', }, - getValidPushTypes: function () { - return ['ios', 'android']; + data: { + badge: 'Increment', + alert: 'Hello world!', }, - }; - - return reconfigureServer({ - appId: Parse.applicationId, - masterKey: Parse.masterKey, - serverURL: Parse.serverURL, - push: { - adapter: pushAdapter, - }, - }) - .then(() => { - const installations = []; - while (installations.length != 10) { - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('badge', installations.length); - installation.set('originalBadge', installations.length); - installation.set('deviceType', 'ios'); - installations.push(installation); - } - return Parse.Object.saveAll(installations); - }) - .then(() => { - return { - sendToInstallationSpy, - }; - }) - .catch(err => { - console.error(err); - - throw err; - }); - }; - - it('should properly send push', done => { - return setup() - .then(({ sendToInstallationSpy }) => { - return Parse.Push.send( - { - where: { - deviceType: 'ios', - }, - data: { - badge: 'Increment', - alert: 'Hello world!', - }, - }, - { useMasterKey: true } - ) - .then(() => { - return delayPromise(500); - }) - .then(() => { - expect(sendToInstallationSpy.calls.count()).toEqual(10); - }); - }) - .then(() => { - done(); - }) - .catch(err => { - jfail(err); - done(); - }); - }); - - it('should properly send push with lowercaseIncrement', done => { - return setup() - .then(() => { - return Parse.Push.send( - { - where: { - deviceType: 'ios', - }, - data: { - badge: 'increment', - alert: 'Hello world!', - }, - }, - { useMasterKey: true } - ); - }) - .then(() => { - return delayPromise(500); - }) - .then(() => { - done(); - }) - .catch(err => { - jfail(err); - done(); - }); - }); - - it('should not allow clients to query _PushStatus', done => { - setup() - .then(() => - Parse.Push.send( - { - where: { - deviceType: 'ios', - }, - data: { - badge: 'increment', - alert: 'Hello world!', - }, - }, - { useMasterKey: true } - ) - ) - .then(() => delayPromise(500)) - .then(() => { - request({ - url: 'http://localhost:8378/1/classes/_PushStatus', - json: true, - headers: { - 'X-Parse-Application-Id': 'test', - }, - }).then(fail, response => { - expect(response.data.error).toEqual('unauthorized'); - done(); - }); - }) - .catch(err => { - jfail(err); - done(); - }); - }); - - it('should allow master key to query _PushStatus', done => { - setup() - .then(() => - Parse.Push.send( - { - where: { - deviceType: 'ios', - }, - data: { - badge: 'increment', - alert: 'Hello world!', - }, - }, - { useMasterKey: true } - ) - ) - .then(() => delayPromise(500)) // put a delay as we keep writing - .then(() => { - request({ - url: 'http://localhost:8378/1/classes/_PushStatus', - json: true, - headers: { - 'X-Parse-Application-Id': 'test', - 'X-Parse-Master-Key': 'test', - }, - }).then(response => { - const body = response.data; - 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('should throw error if missing push configuration', done => { - reconfigureServer({ push: null }) - .then(() => { - return Parse.Push.send( - { - where: { - deviceType: 'ios', - }, - data: { - badge: 'increment', - alert: 'Hello world!', - }, - }, - { useMasterKey: true } - ); - }) - .then( - () => { - fail('should not succeed'); - }, - err => { - expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED); - done(); - } - ) - .catch(err => { - jfail(err); - done(); - }); - }); - - const successfulAny = function (body, installations) { - const promises = installations.map(device => { - return Promise.resolve({ - transmitted: true, - device: device, - }); }); + await pushCompleted(pushStatusId); + expect(sendToInstallationSpy.calls.count()).toEqual(10); + }); - return Promise.all(promises); - }; + it('should properly send push with lowercaseIncrement', async () => { + await setup(); + const pushStatusId = await Parse.Push.send({ + where: { + deviceType: 'ios', + }, + data: { + badge: 'increment', + alert: 'Hello world!', + }, + }); + await pushCompleted(pushStatusId); + }); - const provideInstallations = function (num) { - if (!num) { - num = 2; + it('should not allow clients to query _PushStatus', async () => { + await setup(); + const pushStatusId = await Parse.Push.send({ + where: { + deviceType: 'ios', + }, + data: { + badge: 'increment', + alert: 'Hello world!', + }, + }); + await pushCompleted(pushStatusId); + try { + await request({ + url: 'http://localhost:8378/1/classes/_PushStatus', + json: true, + headers: { + 'X-Parse-Application-Id': 'test', + }, + }); + fail(); + } catch (response) { + expect(response.data.error).toEqual('unauthorized'); } + }); - const installations = []; - while (installations.length !== num) { - // add Android installations - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('deviceType', 'android'); - installations.push(installation); + it('should allow master key to query _PushStatus', async () => { + await setup(); + const pushStatusId = await Parse.Push.send({ + where: { + deviceType: 'ios', + }, + data: { + badge: 'increment', + alert: 'Hello world!', + }, + }); + await pushCompleted(pushStatusId); + const response = await request({ + url: 'http://localhost:8378/1/classes/_PushStatus', + json: true, + headers: { + 'X-Parse-Application-Id': 'test', + 'X-Parse-Master-Key': 'test', + }, + }); + const body = response.data; + 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!"}'); + }); + + it('should throw error if missing push configuration', async () => { + await reconfigureServer({ push: null }); + try { + await Parse.Push.send({ + where: { + deviceType: 'ios', + }, + data: { + badge: 'increment', + alert: 'Hello world!', + }, + }); + fail(); + } catch (err) { + expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED); } - - return installations; - }; - - const losingAdapter = { - send: function (body, installations) { - // simulate having lost an installation before this was called - // thus invalidating our 'count' in _PushStatus - installations.pop(); - - return successfulAny(body, installations); - }, - getValidPushTypes: function () { - return ['android']; - }, - }; + }); /** * Verifies that _PushStatus cannot get stuck in a 'running' state * Simulates a simple push where 1 installation is removed between _PushStatus * count being set and the pushes being sent */ - it("does not get stuck with _PushStatus 'running' on 1 installation lost", done => { - reconfigureServer({ + it("does not get stuck with _PushStatus 'running' on 1 installation lost", async () => { + await reconfigureServer({ push: { adapter: losingAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(provideInstallations()); - }) - .then(() => { - return Parse.Push.send( - { - data: { alert: 'We fixed our status!' }, - where: { deviceType: 'android' }, - }, - { useMasterKey: true } - ); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // query for push status - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - // verify status is NOT broken - expect(results.length).toBe(1); - const result = results[0]; - expect(result.get('status')).toEqual('succeeded'); - expect(result.get('numSent')).toEqual(1); - expect(result.get('count')).toEqual(undefined); - done(); - }); + }); + await Parse.Object.saveAll(provideInstallations()); + const pushStatusId = await Parse.Push.send({ + data: { alert: 'We fixed our status!' }, + where: { deviceType: 'android' }, + }); + await pushCompleted(pushStatusId); + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result.get('status')).toEqual('succeeded'); + expect(result.get('numSent')).toEqual(1); + expect(result.get('count')).toEqual(undefined); }); /** @@ -330,7 +233,7 @@ describe('Parse.Push', () => { * Simulates a simple push where 1 installation is added between _PushStatus * count being set and the pushes being sent */ - it("does not get stuck with _PushStatus 'running' on 1 installation added", done => { + it("does not get stuck with _PushStatus 'running' on 1 installation added", async () => { const installations = provideInstallations(); // add 1 iOS installation which we will omit & add later on @@ -340,14 +243,13 @@ describe('Parse.Push', () => { iOSInstallation.set('deviceType', 'ios'); installations.push(iOSInstallation); - reconfigureServer({ + await reconfigureServer({ push: { adapter: { send: function (body, installations) { // simulate having added an installation before this was called // thus invalidating our 'count' in _PushStatus installations.push(iOSInstallation); - return successfulAny(body, installations); }, getValidPushTypes: function () { @@ -355,41 +257,17 @@ describe('Parse.Push', () => { }, }, }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return Parse.Push.send( - { - data: { alert: 'We fixed our status!' }, - where: { deviceType: { $ne: 'random' } }, - }, - { useMasterKey: true } - ); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // query for push status - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - // verify status is NOT broken - expect(results.length).toBe(1); - const result = results[0]; - expect(result.get('status')).toEqual('succeeded'); - expect(result.get('numSent')).toEqual(3); - expect(result.get('count')).toEqual(undefined); - done(); - }); + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await Parse.Push.send({ + data: { alert: 'We fixed our status!' }, + where: { deviceType: { $ne: 'random' } }, + }); + await pushCompleted(pushStatusId); + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result.get('status')).toEqual('succeeded'); + expect(result.get('numSent')).toEqual(3); + expect(result.get('count')).toEqual(undefined); }); /** @@ -397,48 +275,24 @@ describe('Parse.Push', () => { * Simulates an extended push, where some installations may be removed, * resulting in a non-zero count */ - it("does not get stuck with _PushStatus 'running' on many installations removed", done => { + it("does not get stuck with _PushStatus 'running' on many installations removed", async () => { const devices = 1000; const installations = provideInstallations(devices); - reconfigureServer({ + await reconfigureServer({ push: { adapter: losingAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return Parse.Push.send( - { - data: { alert: 'We fixed our status!' }, - where: { deviceType: 'android' }, - }, - { useMasterKey: true } - ); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // query for push status - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - // verify status is NOT broken - expect(results.length).toBe(1); - const result = results[0]; - expect(result.get('status')).toEqual('succeeded'); - // expect # less than # of batches used, assuming each batch is 100 pushes - expect(result.get('numSent')).toEqual(devices - devices / 100); - expect(result.get('count')).toEqual(undefined); - done(); - }); + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await Parse.Push.send({ + data: { alert: 'We fixed our status!' }, + where: { deviceType: 'android' }, + }); + await pushCompleted(pushStatusId); + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result.get('status')).toEqual('succeeded'); + // expect # less than # of batches used, assuming each batch is 100 pushes + expect(result.get('numSent')).toEqual(devices - devices / 100); + expect(result.get('count')).toEqual(undefined); }); /** @@ -446,13 +300,12 @@ describe('Parse.Push', () => { * Simulates an extended push, where some installations may be added, * resulting in a non-zero count */ - it("does not get stuck with _PushStatus 'running' on many installations added", done => { + it("does not get stuck with _PushStatus 'running' on many installations added", async () => { const devices = 1000; const installations = provideInstallations(devices); // add 1 iOS installation which we will omit & add later on const iOSInstallations = []; - while (iOSInstallations.length !== devices / 100) { const iOSInstallation = new Parse.Object('_Installation'); iOSInstallation.set('installationId', 'installation_' + installations.length); @@ -461,15 +314,13 @@ describe('Parse.Push', () => { installations.push(iOSInstallation); iOSInstallations.push(iOSInstallation); } - - reconfigureServer({ + await reconfigureServer({ push: { adapter: { send: function (body, installations) { // simulate having added an installation before this was called // thus invalidating our 'count' in _PushStatus installations.push(iOSInstallations.pop()); - return successfulAny(body, installations); }, getValidPushTypes: function () { @@ -477,41 +328,18 @@ describe('Parse.Push', () => { }, }, }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return Parse.Push.send( - { - data: { alert: 'We fixed our status!' }, - where: { deviceType: { $ne: 'random' } }, - }, - { useMasterKey: true } - ); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // query for push status - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - // verify status is NOT broken - expect(results.length).toBe(1); - const result = results[0]; - expect(result.get('status')).toEqual('succeeded'); - // expect # less than # of batches used, assuming each batch is 100 pushes - expect(result.get('numSent')).toEqual(devices + devices / 100); - expect(result.get('count')).toEqual(undefined); - done(); - }); + }); + await Parse.Object.saveAll(installations); + + const pushStatusId = await Parse.Push.send({ + data: { alert: 'We fixed our status!' }, + where: { deviceType: { $ne: 'random' } }, + }); + await pushCompleted(pushStatusId); + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result.get('status')).toEqual('succeeded'); + // expect # less than # of batches used, assuming each batch is 100 pushes + expect(result.get('numSent')).toEqual(devices + devices / 100); + expect(result.get('count')).toEqual(undefined); }); }); diff --git a/spec/PushController.spec.js b/spec/PushController.spec.js index 251f2422..873116bc 100644 --- a/spec/PushController.spec.js +++ b/spec/PushController.spec.js @@ -26,6 +26,20 @@ const successfulIOS = function (body, installations) { return Promise.all(promises); }; +const pushCompleted = async pushId => { + let result = await Parse.Push.getPushStatus(pushId); + while (!(result && result.get('status') === 'succeeded')) { + result = await Parse.Push.getPushStatus(pushId); + } +}; + +const sendPush = (body, where, config, auth, now) => { + const pushController = new PushController(); + return new Promise((resolve, reject) => { + pushController.sendPush(body, where, config, auth, resolve, now).catch(reject); + }); +}; + describe('PushController', () => { it('can validate device type when no device type is set', done => { // Make query condition @@ -151,7 +165,7 @@ describe('PushController', () => { done(); }); - it('properly increment badges', done => { + it('properly increment badges', async () => { const pushAdapter = { send: function (body, installations) { const badge = body.data.badge; @@ -195,55 +209,28 @@ describe('PushController', () => { const auth = { isMaster: true, }; - - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // Check we actually sent 15 pushes. - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(15); - }) - .then(() => { - // Check that the installations were actually updated. - const query = new Parse.Query('_Installation'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(15); - for (let i = 0; i < 15; i++) { - const installation = results[i]; - expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 1); - } - done(); - }) - .catch(err => { - jfail(err); - done(); - }); + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + + // Check we actually sent 15 pushes. + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(15); + + // Check that the installations were actually updated. + const query = new Parse.Query('_Installation'); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(15); + for (let i = 0; i < 15; i++) { + const installation = results[i]; + expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 1); + } }); - it('properly increment badges by more than 1', done => { + it('properly increment badges by more than 1', async () => { const pushAdapter = { send: function (body, installations) { const badge = body.data.badge; @@ -287,55 +274,25 @@ describe('PushController', () => { const auth = { isMaster: true, }; - - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // Check we actually sent 15 pushes. - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(15); - }) - .then(() => { - // Check that the installations were actually updated. - const query = new Parse.Query('_Installation'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(15); - for (let i = 0; i < 15; i++) { - const installation = results[i]; - expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 3); - } - done(); - }) - .catch(err => { - jfail(err); - done(); - }); + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(15); + // Check that the installations were actually updated. + const query = new Parse.Query('_Installation'); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(15); + for (let i = 0; i < 15; i++) { + const installation = results[i]; + expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 3); + } }); - it('properly set badges to 1', done => { + it('properly set badges to 1', async () => { const pushAdapter = { send: function (body, installations) { const badge = body.data.badge; @@ -371,55 +328,26 @@ describe('PushController', () => { const auth = { isMaster: true, }; - - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - // Check we actually sent the pushes. - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(10); - }) - .then(() => { - // Check that the installations were actually updated. - const query = new Parse.Query('_Installation'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(10); - for (let i = 0; i < 10; i++) { - const installation = results[i]; - expect(installation.get('badge')).toBe(1); - } - done(); - }) - .catch(err => { - jfail(err); - done(); - }); + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(10); + + // Check that the installations were actually updated. + const query = new Parse.Query('_Installation'); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(10); + for (let i = 0; i < 10; i++) { + const installation = results[i]; + expect(installation.get('badge')).toBe(1); + } }); - it('properly set badges to 1 with complex query #2903 #3022', done => { + it('properly set badges to 1 with complex query #2903 #3022', async () => { const payload = { data: { alert: 'Hello World!', @@ -456,46 +384,26 @@ describe('PushController', () => { const auth = { isMaster: true, }; - const pushController = new PushController(); - reconfigureServer({ - push: { - adapter: pushAdapter, - }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(installations => { - const objectIds = installations.map(installation => { - return installation.id; - }); - const where = { - objectId: { $in: objectIds.slice(0, 5) }, - }; - return pushController.sendPush(payload, where, config, auth); - }) - .then(() => { - return new Promise(res => { - setTimeout(res, 300); - }); - }) - .then(() => { - expect(matchedInstallationsCount).toBe(5); - const query = new Parse.Query(Parse.Installation); - query.equalTo('badge', 1); - return query.find({ useMasterKey: true }); - }) - .then(installations => { - expect(installations.length).toBe(5); - done(); - }) - .catch(() => { - fail('should not fail'); - done(); - }); + await reconfigureServer({ + push: { adapter: pushAdapter }, + }); + await Parse.Object.saveAll(installations); + const objectIds = installations.map(installation => { + return installation.id; + }); + const where = { + objectId: { $in: objectIds.slice(0, 5) }, + }; + const pushStatusId = await sendPush(payload, where, config, auth); + await pushCompleted(pushStatusId); + expect(matchedInstallationsCount).toBe(5); + const query = new Parse.Query(Parse.Installation); + query.equalTo('badge', 1); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(5); }); - it('properly creates _PushStatus', done => { + it('properly creates _PushStatus', async () => { const pushStatusAfterSave = { handler: function () {}, }; @@ -539,87 +447,78 @@ describe('PushController', () => { const auth = { isMaster: true, }; - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const result = results[0]; - expect(result.createdAt instanceof Date).toBe(true); - expect(result.updatedAt instanceof Date).toBe(true); - expect(result.id.length).toBe(10); - expect(result.get('source')).toEqual('rest'); - expect(result.get('query')).toEqual(JSON.stringify({})); - expect(typeof result.get('payload')).toEqual('string'); - expect(JSON.parse(result.get('payload'))).toEqual(payload.data); - expect(result.get('status')).toEqual('succeeded'); - expect(result.get('numSent')).toEqual(10); - expect(result.get('sentPerType')).toEqual({ - ios: 10, // 10 ios - }); - expect(result.get('numFailed')).toEqual(5); - expect(result.get('failedPerType')).toEqual({ - android: 5, // android - }); - // Try to get it without masterKey - const query = new Parse.Query('_PushStatus'); - return query.find(); - }) - .catch(error => { - expect(error.code).toBe(119); - }) - .then(() => { - function getPushStatus(callIndex) { - return spy.calls.all()[callIndex].args[0].object; - } - expect(spy).toHaveBeenCalled(); - expect(spy.calls.count()).toBe(4); - const allCalls = spy.calls.all(); - allCalls.forEach(call => { - expect(call.args.length).toBe(1); - const object = call.args[0].object; - expect(object instanceof Parse.Object).toBe(true); - }); - expect(getPushStatus(0).get('status')).toBe('pending'); - expect(getPushStatus(1).get('status')).toBe('running'); - expect(getPushStatus(1).get('numSent')).toBe(0); - expect(getPushStatus(2).get('status')).toBe('running'); - expect(getPushStatus(2).get('numSent')).toBe(10); - expect(getPushStatus(2).get('numFailed')).toBe(5); - // Those are updated from a nested . operation, this would - // not render correctly before - expect(getPushStatus(2).get('failedPerType')).toEqual({ + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result.createdAt instanceof Date).toBe(true); + expect(result.updatedAt instanceof Date).toBe(true); + expect(result.id.length).toBe(10); + expect(result.get('source')).toEqual('rest'); + expect(result.get('query')).toEqual(JSON.stringify({})); + expect(typeof result.get('payload')).toEqual('string'); + expect(JSON.parse(result.get('payload'))).toEqual(payload.data); + expect(result.get('status')).toEqual('succeeded'); + expect(result.get('numSent')).toEqual(10); + expect(result.get('sentPerType')).toEqual({ + ios: 10, // 10 ios + }); + expect(result.get('numFailed')).toEqual(5); + expect(result.get('failedPerType')).toEqual({ + android: 5, // android + }); + try { + // Try to get it without masterKey + const query = new Parse.Query('_PushStatus'); + await query.find(); + fail(); + } catch (error) { + expect(error.code).toBe(119); + } + + function getPushStatus(callIndex) { + return spy.calls.all()[callIndex].args[0].object; + } + expect(spy).toHaveBeenCalled(); + expect(spy.calls.count()).toBe(4); + const allCalls = spy.calls.all(); + let pendingCount = 0; + let runningCount = 0; + let succeedCount = 0; + allCalls.forEach((call, index) => { + expect(call.args.length).toBe(1); + const object = call.args[0].object; + expect(object instanceof Parse.Object).toBe(true); + const pushStatus = getPushStatus(index); + if (pushStatus.get('status') === 'pending') { + pendingCount += 1; + } + if (pushStatus.get('status') === 'running') { + runningCount += 1; + } + if (pushStatus.get('status') === 'succeeded') { + succeedCount += 1; + } + if (pushStatus.get('status') === 'running' && pushStatus.get('numSent') > 0) { + expect(pushStatus.get('numSent')).toBe(10); + expect(pushStatus.get('numFailed')).toBe(5); + expect(pushStatus.get('failedPerType')).toEqual({ android: 5, }); - expect(getPushStatus(2).get('sentPerType')).toEqual({ + expect(pushStatus.get('sentPerType')).toEqual({ ios: 10, }); - expect(getPushStatus(3).get('status')).toBe('succeeded'); - }) - .then(done) - .catch(done.fail); + } + }); + expect(pendingCount).toBe(1); + expect(runningCount).toBe(2); + expect(succeedCount).toBe(1); }); - it('properly creates _PushStatus without serverURL', done => { + it('properly creates _PushStatus without serverURL', async () => { const pushStatusAfterSave = { handler: function () {}, }; @@ -651,36 +550,22 @@ describe('PushController', () => { const auth = { isMaster: true, }; - const pushController = new PushController(); - return installation - .save() - .then(() => { - return reconfigureServer({ - serverURL: 'http://localhost:8378/', // server with borked URL - push: { adapter: pushAdapter }, - }); - }) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => { - // it is enqueued so it can take time - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - Parse.serverURL = 'http://localhost:8378/1'; // GOOD url - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - }) - .then(done) - .catch(done.fail); + await installation.save(); + await reconfigureServer({ + serverURL: 'http://localhost:8378/', // server with borked URL + push: { adapter: pushAdapter }, + }); + const pushStatusId = await sendPush(payload, {}, config, auth); + // it is enqueued so it can take time + await new Promise(resolve => { + setTimeout(() => { + resolve(); + }, 1000); + }); + Parse.serverURL = 'http://localhost:8378/1'; // GOOD url + const result = await Parse.Push.getPushStatus(pushStatusId); + expect(result).toBeDefined(); + await pushCompleted(pushStatusId); }); it('should properly report failures in _PushStatus', done => { @@ -696,6 +581,7 @@ describe('PushController', () => { return ['ios']; }, }; + // $ins is invalid query const where = { channels: { $ins: ['Giants', 'Mets'], @@ -733,7 +619,7 @@ describe('PushController', () => { }); }); - it('should support full RESTQuery for increment', done => { + it('should support full RESTQuery for increment', async () => { const payload = { data: { alert: 'Hello World!', @@ -759,52 +645,27 @@ describe('PushController', () => { $in: ['device_token_0', 'device_token_1', 'device_token_2'], }, }; - - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - const installations = []; - while (installations.length != 5) { - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('badge', installations.length); - installation.set('originalBadge', installations.length); - installation.set('deviceType', 'ios'); - installations.push(installation); - } - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, where, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(3); - done(); - }) - .catch(err => { - jfail(err); - done(); - }); + }); + const installations = []; + while (installations.length != 5) { + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('badge', installations.length); + installation.set('originalBadge', installations.length); + installation.set('deviceType', 'ios'); + installations.push(installation); + } + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, where, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(3); }); - it('should support object type for alert', done => { + it('should support object type for alert', async () => { const payload = { data: { alert: { @@ -826,53 +687,27 @@ describe('PushController', () => { const auth = { isMaster: true, }; - const where = { deviceType: 'ios', }; - - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - const installations = []; - while (installations.length != 5) { - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('badge', installations.length); - installation.set('originalBadge', installations.length); - installation.set('deviceType', 'ios'); - installations.push(installation); - } - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, where, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(5); - done(); - }) - .catch(() => { - fail('should not fail'); - done(); - }); + }); + const installations = []; + while (installations.length != 5) { + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('badge', installations.length); + installation.set('originalBadge', installations.length); + installation.set('deviceType', 'ios'); + installations.push(installation); + } + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, where, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(5); }); it('should flatten', () => { @@ -1012,7 +847,6 @@ describe('PushController', () => { return ['ios']; }, }; - const pushController = new PushController(); const payload = { data: { @@ -1020,7 +854,6 @@ describe('PushController', () => { }, push_time: new Date().getTime() / 1000, }; - const installations = []; while (installations.length != 10) { const installation = new Parse.Object('_Installation'); @@ -1031,7 +864,6 @@ describe('PushController', () => { installation.set('deviceType', 'ios'); installations.push(installation); } - reconfigureServer({ push: { adapter: pushAdapter }, scheduledPush: true, @@ -1056,7 +888,7 @@ describe('PushController', () => { .catch(done.err); }); - it('should not enqueue push when device token is not set', done => { + it('should not enqueue push when device token is not set', async () => { const auth = { isMaster: true, }; @@ -1079,15 +911,12 @@ describe('PushController', () => { return ['ios']; }, }; - - const pushController = new PushController(); const payload = { data: { alert: 'hello', }, push_time: new Date().getTime() / 1000, }; - const installations = []; while (installations.length != 5) { const installation = new Parse.Object('_Installation'); @@ -1098,7 +927,6 @@ describe('PushController', () => { installation.set('deviceType', 'ios'); installations.push(installation); } - while (installations.length != 15) { const installation = new Parse.Object('_Installation'); installation.set('installationId', 'installation_' + installations.length); @@ -1107,36 +935,19 @@ describe('PushController', () => { installation.set('deviceType', 'ios'); installations.push(installation); } - - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - const config = Config.get(Parse.applicationId); - return Parse.Object.saveAll(installations) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => new Promise(resolve => setTimeout(resolve, 100))); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }).then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(5); - expect(pushStatus.get('status')).toBe('succeeded'); - done(); - }); - }) - .catch(err => { - console.error(err); - fail('should not fail'); - done(); - }); + }); + const config = Config.get(Parse.applicationId); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('numSent')).toBe(5); + expect(pushStatus.get('status')).toBe('succeeded'); }); - it('should not mark the _PushStatus as failed when audience has no deviceToken', done => { + it('should not mark the _PushStatus as failed when audience has no deviceToken', async () => { const auth = { isMaster: true, }; @@ -1159,15 +970,12 @@ describe('PushController', () => { return ['ios']; }, }; - - const pushController = new PushController(); const payload = { data: { alert: 'hello', }, push_time: new Date().getTime() / 1000, }; - const installations = []; while (installations.length != 5) { const installation = new Parse.Object('_Installation'); @@ -1177,36 +985,18 @@ describe('PushController', () => { installation.set('deviceType', 'ios'); installations.push(installation); } - - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - const config = Config.get(Parse.applicationId); - return Parse.Object.saveAll(installations) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => new Promise(resolve => setTimeout(resolve, 100))); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }).then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('numSent')).toBe(0); - expect(pushStatus.get('status')).toBe('succeeded'); - done(); - }); - }) - .catch(err => { - console.error(err); - fail('should not fail'); - done(); - }); + }); + const config = Config.get(Parse.applicationId); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, {}, config, auth); + await pushCompleted(pushStatusId); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('status')).toBe('succeeded'); }); - it('should support localized payload data', done => { + it('should support localized payload data', async () => { const payload = { data: { alert: 'Hello!', @@ -1214,7 +1004,6 @@ describe('PushController', () => { 'alert-es': 'Ola', }, }; - const pushAdapter = { send: function (body, installations) { return successfulTransmissions(body, installations); @@ -1223,67 +1012,51 @@ describe('PushController', () => { return ['ios']; }, }; - const config = Config.get(Parse.applicationId); const auth = { isMaster: true, }; - const where = { deviceType: 'ios', }; - spyOn(pushAdapter, 'send').and.callThrough(); - const pushController = new PushController(); - reconfigureServer({ - push: { adapter: pushAdapter }, - }) - .then(() => { - const installations = []; - while (installations.length != 5) { - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('badge', installations.length); - installation.set('originalBadge', installations.length); - installation.set('deviceType', 'ios'); - installations.push(installation); - } - installations[0].set('localeIdentifier', 'fr-CA'); - installations[1].set('localeIdentifier', 'fr-FR'); - installations[2].set('localeIdentifier', 'en-US'); - return Parse.Object.saveAll(installations); - }) - .then(() => { - return pushController.sendPush(payload, where, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - expect(pushAdapter.send.calls.count()).toBe(2); - const firstCall = pushAdapter.send.calls.first(); - expect(firstCall.args[0].data).toEqual({ - alert: 'Hello!', - }); - expect(firstCall.args[1].length).toBe(3); // 3 installations + const installations = []; + while (installations.length != 5) { + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('badge', installations.length); + installation.set('originalBadge', installations.length); + installation.set('deviceType', 'ios'); + installations.push(installation); + } + installations[0].set('localeIdentifier', 'fr-CA'); + installations[1].set('localeIdentifier', 'fr-FR'); + installations[2].set('localeIdentifier', 'en-US'); - const lastCall = pushAdapter.send.calls.mostRecent(); - expect(lastCall.args[0].data).toEqual({ - alert: 'Bonjour', - }); - expect(lastCall.args[1].length).toBe(2); // 2 installations - // No installation is in es so only 1 call for fr, and another for default - done(); - }) - .catch(done.fail); + spyOn(pushAdapter, 'send').and.callThrough(); + await reconfigureServer({ + push: { adapter: pushAdapter }, + }); + await Parse.Object.saveAll(installations); + const pushStatusId = await sendPush(payload, where, config, auth); + await pushCompleted(pushStatusId); + + expect(pushAdapter.send.calls.count()).toBe(2); + const firstCall = pushAdapter.send.calls.first(); + expect(firstCall.args[0].data).toEqual({ + alert: 'Hello!', + }); + expect(firstCall.args[1].length).toBe(3); // 3 installations + + const lastCall = pushAdapter.send.calls.mostRecent(); + expect(lastCall.args[0].data).toEqual({ + alert: 'Bonjour', + }); + expect(lastCall.args[1].length).toBe(2); // 2 installations + // No installation is in es so only 1 call for fr, and another for default }); - it('should update audiences', done => { + it('should update audiences', async () => { const pushAdapter = { send: function (body, installations) { return successfulTransmissions(body, installations); @@ -1297,92 +1070,68 @@ describe('PushController', () => { const auth = { isMaster: true, }; - let audienceId = null; const now = new Date(); let timesUsed = 0; - const where = { deviceType: 'ios', }; + const installations = []; + while (installations.length != 5) { + const installation = new Parse.Object('_Installation'); + installation.set('installationId', 'installation_' + installations.length); + installation.set('deviceToken', 'device_token_' + installations.length); + installation.set('badge', installations.length); + installation.set('originalBadge', installations.length); + installation.set('deviceType', 'ios'); + installations.push(installation); + } spyOn(pushAdapter, 'send').and.callThrough(); - const pushController = new PushController(); - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - const installations = []; - while (installations.length != 5) { - const installation = new Parse.Object('_Installation'); - installation.set('installationId', 'installation_' + installations.length); - installation.set('deviceToken', 'device_token_' + installations.length); - installation.set('badge', installations.length); - installation.set('originalBadge', installations.length); - installation.set('deviceType', 'ios'); - installations.push(installation); + }); + await Parse.Object.saveAll(installations); + + // Create an audience + const query = new Parse.Query('_Audience'); + query.descending('createdAt'); + query.equalTo('query', JSON.stringify(where)); + const parseResults = results => { + if (results.length > 0) { + audienceId = results[0].id; + timesUsed = results[0].get('timesUsed'); + if (!isFinite(timesUsed)) { + timesUsed = 0; } - return Parse.Object.saveAll(installations); - }) - .then(() => { - // Create an audience - const query = new Parse.Query('_Audience'); - query.descending('createdAt'); - query.equalTo('query', JSON.stringify(where)); - const parseResults = results => { - if (results.length > 0) { - audienceId = results[0].id; - timesUsed = results[0].get('timesUsed'); - if (!isFinite(timesUsed)) { - timesUsed = 0; - } - } - }; - const audience = new Parse.Object('_Audience'); - audience.set('name', 'testAudience'); - audience.set('query', JSON.stringify(where)); - return Parse.Object.saveAll(audience).then(() => { - return query.find({ useMasterKey: true }).then(parseResults); - }); - }) - .then(() => { - const body = { - data: { alert: 'hello' }, - audience_id: audienceId, - }; - return pushController.sendPush(body, where, config, auth); - }) - .then(() => { - // Wait so the push is completed. - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); - }) - .then(() => { - expect(pushAdapter.send.calls.count()).toBe(1); - const firstCall = pushAdapter.send.calls.first(); - expect(firstCall.args[0].data).toEqual({ - alert: 'hello', - }); - expect(firstCall.args[1].length).toBe(5); - }) - .then(() => { - // Get the audience we used above. - const query = new Parse.Query('_Audience'); - query.equalTo('objectId', audienceId); - return query.find({ useMasterKey: true }); - }) - .then(results => { - const audience = results[0]; - expect(audience.get('query')).toBe(JSON.stringify(where)); - expect(audience.get('timesUsed')).toBe(timesUsed + 1); - expect(audience.get('lastUsed')).not.toBeLessThan(now); - }) - .then(() => { - done(); - }) - .catch(done.fail); + } + }; + const audience = new Parse.Object('_Audience'); + audience.set('name', 'testAudience'); + audience.set('query', JSON.stringify(where)); + await Parse.Object.saveAll(audience); + await query.find({ useMasterKey: true }).then(parseResults); + + const body = { + data: { alert: 'hello' }, + audience_id: audienceId, + }; + const pushStatusId = await sendPush(body, where, config, auth); + await pushCompleted(pushStatusId); + expect(pushAdapter.send.calls.count()).toBe(1); + const firstCall = pushAdapter.send.calls.first(); + expect(firstCall.args[0].data).toEqual({ + alert: 'hello', + }); + expect(firstCall.args[1].length).toBe(5); + + // Get the audience we used above. + const audienceQuery = new Parse.Query('_Audience'); + audienceQuery.equalTo('objectId', audienceId); + const results = await audienceQuery.find({ useMasterKey: true }); + + expect(results[0].get('query')).toBe(JSON.stringify(where)); + expect(results[0].get('timesUsed')).toBe(timesUsed + 1); + expect(results[0].get('lastUsed')).not.toBeLessThan(now); }); describe('pushTimeHasTimezoneComponent', () => { @@ -1446,7 +1195,7 @@ describe('PushController', () => { }); describe('Scheduling pushes in local time', () => { - it('should preserve the push time', done => { + it('should preserve the push time', async () => { const auth = { isMaster: true }; const pushAdapter = { send(body, installations) { @@ -1456,7 +1205,6 @@ describe('PushController', () => { return ['ios']; }, }; - const pushTime = '2017-09-06T17:14:01.048'; let expectedHour = 17 + new Date(pushTime).getTimezoneOffset() / 60; let day = '06'; @@ -1464,43 +1212,24 @@ describe('PushController', () => { expectedHour = expectedHour - 24; day = '07'; } - - reconfigureServer({ + const payload = { + data: { + alert: 'Hello World!', + badge: 'Increment', + }, + push_time: pushTime, + }; + await reconfigureServer({ push: { adapter: pushAdapter }, scheduledPush: true, - }) - .then(() => { - const config = Config.get(Parse.applicationId); - return new Promise((resolve, reject) => { - const pushController = new PushController(); - pushController - .sendPush( - { - data: { - alert: 'Hello World!', - badge: 'Increment', - }, - push_time: pushTime, - }, - {}, - config, - auth, - resolve - ) - .catch(reject); - }); - }) - .then(pushStatusId => { - const q = new Parse.Query('_PushStatus'); - return q.get(pushStatusId, { useMasterKey: true }); - }) - .then(pushStatus => { - expect(pushStatus.get('status')).toBe('scheduled'); - expect(pushStatus.get('pushTime')).toBe( - `2017-09-${day}T${expectedHour.toString().padStart(2, '0')}:14:01.048` - ); - }) - .then(done, done.fail); + }); + const config = Config.get(Parse.applicationId); + const pushStatusId = await sendPush(payload, {}, config, auth); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('status')).toBe('scheduled'); + expect(pushStatus.get('pushTime')).toBe( + `2017-09-${day}T${expectedHour.toString().padStart(2, '0')}:14:01.048` + ); }); }); @@ -1579,47 +1308,32 @@ describe('PushController', () => { }); describe('For immediate pushes', () => { - it('should transform the expiration_interval into an absolute time', done => { + it('should transform the expiration_interval into an absolute time', async () => { const now = new Date('2017-09-25T13:30:10.452Z'); - - reconfigureServer({ + const payload = { + data: { + alert: 'immediate push', + }, + expiration_interval: 20 * 60, // twenty minutes + }; + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then( - () => - new Promise(resolve => { - pushController.sendPush( - { - data: { - alert: 'immediate push', - }, - expiration_interval: 20 * 60, // twenty minutes - }, - {}, - Config.get(Parse.applicationId), - auth, - resolve, - now - ); - }) - ) - .then(pushStatusId => { - const p = new Parse.Object('_PushStatus'); - p.id = pushStatusId; - return p.fetch({ useMasterKey: true }); - }) - .then(pushStatus => { - expect(pushStatus.get('expiry')).toBeDefined('expiry must be set'); - expect(pushStatus.get('expiry')).toEqual( - new Date('2017-09-25T13:50:10.452Z').valueOf() - ); + }); + const pushStatusId = await sendPush( + payload, + {}, + Config.get(Parse.applicationId), + auth, + now + ); + const pushStatus = await Parse.Push.getPushStatus(pushStatusId); + expect(pushStatus.get('expiry')).toBeDefined('expiry must be set'); + expect(pushStatus.get('expiry')).toEqual(new Date('2017-09-25T13:50:10.452Z').valueOf()); - expect(pushStatus.get('expiration_interval')).toBeDefined( - 'expiration_interval must be defined' - ); - expect(pushStatus.get('expiration_interval')).toBe(20 * 60); - }) - .then(done, done.fail); + expect(pushStatus.get('expiration_interval')).toBeDefined( + 'expiration_interval must be defined' + ); + expect(pushStatus.get('expiration_interval')).toBe(20 * 60); }); }); });