mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-13 04:37:36 +01:00
* begin moving to new fcm library * Add error handling * Add opening notification to correct screen * Fix tests and make async * lint fix * Rename pushNotificationstest..js to pushNotifications.test.js * fix(potions): remove Fungi Potion time banner * 5.24.3 * update(content): add 2024-06 content prebuild (#15231) * update sprites * add 2024-06 content * add 2024-06 enchanted armoire items * update sprites * update sprites * fix errors found in testing * Fix liveliness probes being rate limited (#15236) * Do not rate limit any liveliness probes * update example config * Translated using Weblate (German) Currently translated at 96.2% (181 of 188 strings) Translated using Weblate (Japanese) Currently translated at 99.4% (769 of 773 strings) Translated using Weblate (German) Currently translated at 93.6% (176 of 188 strings) Translated using Weblate (Japanese) Currently translated at 96.2% (2972 of 3089 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (232 of 232 strings) Translated using Weblate (Japanese) Currently translated at 96.8% (841 of 868 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (113 of 113 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (German) Currently translated at 86.7% (163 of 188 strings) Translated using Weblate (German) Currently translated at 85.1% (160 of 188 strings) Translated using Weblate (German) Currently translated at 84.0% (158 of 188 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (German) Currently translated at 83.5% (157 of 188 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (113 of 113 strings) Translated using Weblate (German) Currently translated at 82.9% (156 of 188 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (113 of 113 strings) Translated using Weblate (German) Currently translated at 81.9% (154 of 188 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (113 of 113 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (8 of 8 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (8 of 8 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (German) Currently translated at 79.2% (149 of 188 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (189 of 189 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (8 of 8 strings) Translated using Weblate (German) Currently translated at 90.6% (2799 of 3089 strings) Translated using Weblate (German) Currently translated at 77.6% (146 of 188 strings) Translated using Weblate (German) Currently translated at 90.5% (2797 of 3089 strings) Translated using Weblate (German) Currently translated at 90.4% (2794 of 3089 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (German) Currently translated at 90.1% (2786 of 3089 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (German) Currently translated at 77.1% (145 of 188 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.7% (763 of 773 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (German) Currently translated at 90.0% (2782 of 3089 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (773 of 773 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (378 of 378 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (259 of 259 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (239 of 239 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (French) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (German) Currently translated at 75.0% (141 of 188 strings) Translated using Weblate (Spanish) Currently translated at 99.0% (766 of 773 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (189 of 189 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (Japanese) Currently translated at 98.8% (764 of 773 strings) Translated using Weblate (Japanese) Currently translated at 99.6% (258 of 259 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (378 of 378 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (140 of 140 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (Ukrainian) Currently translated at 62.5% (1931 of 3089 strings) Translated using Weblate (German) Currently translated at 89.8% (2777 of 3089 strings) Translated using Weblate (French) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.5% (762 of 773 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (French) Currently translated at 82.9% (156 of 188 strings) Translated using Weblate (German) Currently translated at 93.0% (241 of 259 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (8 of 8 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (427 of 427 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.5% (762 of 773 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Japanese) Currently translated at 99.2% (257 of 259 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.5% (762 of 773 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (868 of 868 strings) Translated using Weblate (German) Currently translated at 92.2% (239 of 259 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (286 of 286 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (239 of 239 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (188 of 188 strings) Translated using Weblate (German) Currently translated at 91.8% (238 of 259 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (131 of 131 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.5% (762 of 773 strings) Translated using Weblate (German) Currently translated at 90.3% (234 of 259 strings) Co-authored-by: Finrod <963505255@qq.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Kem Kembo <medamamef@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: TOMA Mitsuru <toma0001@gmail.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/ Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/content/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/content/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/inventory/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/overview/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/quests/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/es/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/de/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/settings/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/ Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/ Translation: Habitica/Achievements Translation: Habitica/Backgrounds Translation: Habitica/Character Translation: Habitica/Content Translation: Habitica/Faq Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Groups Translation: Habitica/Inventory Translation: Habitica/Limited Translation: Habitica/Npc Translation: Habitica/Overview Translation: Habitica/Pets Translation: Habitica/Quests Translation: Habitica/Questscontent Translation: Habitica/Settings Translation: Habitica/Subscriber Translation: Habitica/Tasks * 5.25.0 * Fix dockerfile (#15241) * Fix issue with l4p not resetting properly (#15240) * actually clear out seeking field on user. Even when creating a party * Add tests to ensure party.seeking is cleared * fix(lint): don't assign unused const --------- Co-authored-by: Sabe Jones <sabe@habitica.com> --------- Co-authored-by: Sabe Jones <sabe@habitica.com> Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Finrod <963505255@qq.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Kem Kembo <medamamef@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: TOMA Mitsuru <toma0001@gmail.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: Rafał Jagielski <jagielski.rafal.uwm@gmail.com>
355 lines
9.8 KiB
JavaScript
355 lines
9.8 KiB
JavaScript
import apn from '@parse/node-apn';
|
|
import _ from 'lodash';
|
|
import nconf from 'nconf';
|
|
import admin from 'firebase-admin';
|
|
import { model as User } from '../../../../website/server/models/user';
|
|
import {
|
|
MAX_MESSAGE_LENGTH,
|
|
} from '../../../../website/server/libs/pushNotifications';
|
|
|
|
let sendPushNotification;
|
|
|
|
describe('pushNotifications', () => {
|
|
let user;
|
|
let fcmSendSpy;
|
|
let apnSendSpy;
|
|
let updateStub;
|
|
let classStubbedInstance;
|
|
|
|
const identifier = 'identifier';
|
|
const title = 'title';
|
|
const message = 'message';
|
|
|
|
beforeEach(() => {
|
|
user = new User();
|
|
fcmSendSpy = sinon.stub().returns(Promise.resolve('success'));
|
|
apnSendSpy = sinon.stub().returns(Promise.resolve());
|
|
|
|
nconf.set('PUSH_CONFIGS_APN_ENABLED', 'true');
|
|
|
|
classStubbedInstance = sandbox.createStubInstance(apn.Provider, {
|
|
send: apnSendSpy,
|
|
});
|
|
sandbox.stub(apn, 'Provider').returns(classStubbedInstance);
|
|
|
|
delete require.cache[require.resolve('../../../../website/server/libs/pushNotifications')];
|
|
// eslint-disable-next-line global-require
|
|
sendPushNotification = require('../../../../website/server/libs/pushNotifications').sendNotification;
|
|
|
|
updateStub = sandbox.stub(User, 'updateOne').resolves();
|
|
sandbox.stub(admin, 'messaging').get(() => () => ({ send: fcmSendSpy }));
|
|
});
|
|
|
|
afterEach(() => {
|
|
sandbox.restore();
|
|
});
|
|
|
|
describe('validates supplied data', () => {
|
|
it('throws if user is not supplied', () => {
|
|
expect(sendPushNotification).to.throw;
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('throws if user.preferences.pushNotifications.unsubscribeFromAll is true', () => {
|
|
user.preferences.pushNotifications.unsubscribeFromAll = true;
|
|
expect(() => sendPushNotification(user)).to.throw;
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('throws if details.identifier is not supplied', () => {
|
|
expect(() => sendPushNotification(user, {
|
|
title,
|
|
message,
|
|
})).to.throw;
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('throws if details.title is not supplied', () => {
|
|
expect(() => sendPushNotification(user, {
|
|
identifier,
|
|
message,
|
|
})).to.throw;
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('throws if details.message is not supplied', () => {
|
|
expect(() => sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
})).to.throw;
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('returns if no device is registered', () => {
|
|
sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
message,
|
|
});
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
});
|
|
|
|
it('cuts the message to 300 chars', () => {
|
|
const longMessage = `12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345`;
|
|
|
|
expect(longMessage.length > MAX_MESSAGE_LENGTH).to.equal(true);
|
|
|
|
const details = {
|
|
identifier,
|
|
title,
|
|
message: longMessage,
|
|
payload: {
|
|
message: longMessage,
|
|
},
|
|
};
|
|
|
|
sendPushNotification(user, details);
|
|
|
|
expect(details.message).to.equal(_.truncate(longMessage, { length: MAX_MESSAGE_LENGTH }));
|
|
expect(details.payload.message)
|
|
.to.equal(_.truncate(longMessage, { length: MAX_MESSAGE_LENGTH }));
|
|
|
|
expect(details.message.length).to.equal(MAX_MESSAGE_LENGTH);
|
|
expect(details.payload.message.length).to.equal(MAX_MESSAGE_LENGTH);
|
|
});
|
|
|
|
it('cuts the message to 300 chars (no payload)', () => {
|
|
const longMessage = `12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
|
|
12345 12345 12345 12345 12345 12345 12345 12345 12345 12345`;
|
|
|
|
expect(longMessage.length > MAX_MESSAGE_LENGTH).to.equal(true);
|
|
|
|
const details = {
|
|
identifier,
|
|
title,
|
|
message: longMessage,
|
|
};
|
|
|
|
sendPushNotification(user, details);
|
|
|
|
expect(details.message).to.equal(_.truncate(longMessage, { length: MAX_MESSAGE_LENGTH }));
|
|
expect(details.message.length).to.equal(MAX_MESSAGE_LENGTH);
|
|
});
|
|
|
|
describe('sends notifications', () => {
|
|
let details;
|
|
|
|
beforeEach(() => {
|
|
details = {
|
|
identifier,
|
|
title,
|
|
message,
|
|
category: 'fun',
|
|
payload: {
|
|
a: true,
|
|
b: true,
|
|
},
|
|
};
|
|
});
|
|
|
|
it('uses APN for iOS devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'ios',
|
|
regId: '123',
|
|
});
|
|
|
|
const expectedNotification = new apn.Notification({
|
|
alert: {
|
|
title,
|
|
body: message,
|
|
},
|
|
sound: 'default',
|
|
category: 'fun',
|
|
payload: {
|
|
identifier,
|
|
a: true,
|
|
b: true,
|
|
},
|
|
});
|
|
|
|
await sendPushNotification(user, details);
|
|
expect(apnSendSpy).to.have.been.calledOnce;
|
|
expect(apnSendSpy).to.have.been.calledWithMatch(expectedNotification, '123');
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('uses FCM for Android devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'android',
|
|
regId: '123',
|
|
});
|
|
|
|
const expectedMessage = {
|
|
notification: {
|
|
title,
|
|
body: message,
|
|
},
|
|
data: {
|
|
identifier,
|
|
notificationIdentifier: identifier,
|
|
},
|
|
token: '123',
|
|
};
|
|
|
|
await sendPushNotification(user, details);
|
|
expect(fcmSendSpy).to.have.been.calledOnce;
|
|
expect(fcmSendSpy).to.have.been.calledWithMatch(expectedMessage);
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
});
|
|
|
|
it('handles multiple devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'android',
|
|
regId: '123',
|
|
});
|
|
user.pushDevices.push({
|
|
type: 'ios',
|
|
regId: '456',
|
|
});
|
|
user.pushDevices.push({
|
|
type: 'android',
|
|
regId: '789',
|
|
});
|
|
|
|
await sendPushNotification(user, details);
|
|
expect(fcmSendSpy).to.have.been.calledTwice;
|
|
expect(apnSendSpy).to.have.been.calledOnce;
|
|
});
|
|
});
|
|
|
|
describe('handles sending errors', () => {
|
|
let clock;
|
|
|
|
beforeEach(() => {
|
|
clock = sinon.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
clock.restore();
|
|
});
|
|
|
|
it('removes unregistered fcm devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'android',
|
|
regId: '123',
|
|
});
|
|
|
|
const error = new Error();
|
|
error.code = 'messaging/registration-token-not-registered';
|
|
fcmSendSpy.rejects(error);
|
|
|
|
await sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
message,
|
|
});
|
|
|
|
expect(fcmSendSpy).to.have.been.calledOnce;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
await clock.tick(10);
|
|
expect(updateStub).to.have.been.calledOnce;
|
|
});
|
|
|
|
it('removes invalid fcm devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'android',
|
|
regId: '123',
|
|
});
|
|
|
|
const error = new Error();
|
|
error.code = 'messaging/registration-token-not-registered';
|
|
fcmSendSpy.rejects(error);
|
|
|
|
await sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
message,
|
|
});
|
|
|
|
expect(fcmSendSpy).to.have.been.calledOnce;
|
|
expect(apnSendSpy).to.not.have.been.called;
|
|
expect(updateStub).to.have.been.calledOnce;
|
|
});
|
|
|
|
it('removes unregistered apn devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'ios',
|
|
regId: '123',
|
|
});
|
|
|
|
const error = {
|
|
failed: [
|
|
{
|
|
device: '123',
|
|
response: { reason: 'Unregistered' },
|
|
},
|
|
],
|
|
};
|
|
apnSendSpy.resolves(error);
|
|
|
|
await sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
message,
|
|
});
|
|
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.have.been.calledOnce;
|
|
expect(updateStub).to.have.been.calledOnce;
|
|
});
|
|
|
|
it('removes invalid apn devices', async () => {
|
|
user.pushDevices.push({
|
|
type: 'ios',
|
|
regId: '123',
|
|
});
|
|
|
|
const error = {
|
|
failed: [
|
|
{
|
|
device: '123',
|
|
response: { reason: 'BadDeviceToken' },
|
|
},
|
|
],
|
|
};
|
|
apnSendSpy.resolves(error);
|
|
|
|
await sendPushNotification(user, {
|
|
identifier,
|
|
title,
|
|
message,
|
|
});
|
|
|
|
expect(fcmSendSpy).to.not.have.been.called;
|
|
expect(apnSendSpy).to.have.been.calledOnce;
|
|
expect(updateStub).to.have.been.calledOnce;
|
|
});
|
|
});
|
|
});
|