From ec9729de081000fcdc9bed288b8da5c0ee3b77c8 Mon Sep 17 00:00:00 2001 From: Sebastian Barry Date: Thu, 14 Dec 2023 17:02:58 -0700 Subject: [PATCH] Add test for updateScheduledNotifs to test if notifs successfully get scheduled - There were many places where I used to/fromMillis instead of to/fromJSDate, causing a type difference that was causing errors - Added a i18n mock because not having a language code return was messing with the debugScheduledNotifs log outputs - Added a funcitonality for mockNotifs in the test, so that it can be adjusted, cleared, added to, etc. so that we can test with getScheduledNotifs if it successfully scheduled the notifs --- www/__tests__/notifScheduler.test.ts | 82 +++++++++++++++++----------- www/js/splash/notifScheduler.ts | 12 ++-- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/www/__tests__/notifScheduler.test.ts b/www/__tests__/notifScheduler.test.ts index fca4a03d4..8b74fe7ba 100644 --- a/www/__tests__/notifScheduler.test.ts +++ b/www/__tests__/notifScheduler.test.ts @@ -1,5 +1,6 @@ import { mockReminders } from '../__mocks__/cordovaMocks'; import { mockLogger } from '../__mocks__/globalMocks'; +import i18next from 'i18next'; import { logDebug } from '../js/plugin/logger'; import { DateTime } from 'luxon'; import { getUser, updateUser } from '../js/services/commHelper'; @@ -62,6 +63,10 @@ const exampleReminderSchemes = { mockLogger(); mockReminders(); +jest.mock('i18next', () => ({ + resolvedLanguage: 'en', +})); + jest.mock('../js/services/commHelper', () => ({ getUser: jest.fn(), updateUser: jest.fn(), @@ -98,12 +103,12 @@ describe('getScheduledNotifs', () => { const isScheduling = false; const scheduledPromise = Promise.resolve(); // create the mock notifs from cordova plugin - const mockNotifs = [{ trigger: { at: DateTime.now().toMillis() } }]; + const mockNotifs = [{ trigger: { at: DateTime.now().toJSDate() } }]; // create the expected result const expectedResult = [ { - key: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[0].trigger.at).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[0].trigger.at).toFormat('t'), }, ]; @@ -122,12 +127,12 @@ describe('getScheduledNotifs', () => { const isScheduling = true; const scheduledPromise = Promise.resolve(); // create the mock notifs from cordova plugin - const mockNotifs = [{ trigger: { at: DateTime.now().toMillis() } }]; + const mockNotifs = [{ trigger: { at: DateTime.now().toJSDate() } }]; // create the expected result const expectedResult = [ { - key: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[0].trigger.at).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[0].trigger.at).toFormat('t'), }, ]; @@ -166,36 +171,36 @@ describe('getScheduledNotifs', () => { const scheduledPromise = Promise.resolve(); // create the mock notifs from cordova plugin (greater than 5 notifications) const mockNotifs = [ - { trigger: { at: DateTime.now().toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 1 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 2 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 3 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 4 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 5 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 6 }).toMillis() } }, - { trigger: { at: DateTime.now().plus({ weeks: 7 }).toMillis() } }, + { trigger: { at: DateTime.now().toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 1 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 2 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 3 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 4 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 5 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 6 }).toJSDate() } }, + { trigger: { at: DateTime.now().plus({ weeks: 7 }).toJSDate() } }, ]; // create the expected result (only the first 5 notifications) const expectedResult = [ { - key: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[0].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[0].trigger.at as Date).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[0].trigger.at as Date).toFormat('t'), }, { - key: DateTime.fromMillis(mockNotifs[1].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[1].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[1].trigger.at as Date).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[1].trigger.at as Date).toFormat('t'), }, { - key: DateTime.fromMillis(mockNotifs[2].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[2].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[2].trigger.at as Date).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[2].trigger.at as Date).toFormat('t'), }, { - key: DateTime.fromMillis(mockNotifs[3].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[3].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[3].trigger.at as Date).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[3].trigger.at as Date).toFormat('t'), }, { - key: DateTime.fromMillis(mockNotifs[4].trigger.at).toFormat('DDD'), - val: DateTime.fromMillis(mockNotifs[4].trigger.at).toFormat('t'), + key: DateTime.fromJSDate(mockNotifs[4].trigger.at as Date).toFormat('DDD'), + val: DateTime.fromJSDate(mockNotifs[4].trigger.at as Date).toFormat('t'), }, ]; @@ -237,7 +242,7 @@ describe('updateScheduledNotifs', () => { const setIsScheduling: Function = jest.fn((val: boolean) => (isScheduling = val)); const scheduledPromise: Promise = Promise.resolve(); // create an empty array of mock notifs from cordova plugin - const mockNotifs = []; + let mockNotifs = []; // mock the cordova plugin jest @@ -245,17 +250,30 @@ describe('updateScheduledNotifs', () => { .mockImplementation((callback) => callback(mockNotifs)); jest .spyOn(window['cordova'].plugins.notification.local, 'cancelAll') - .mockImplementation((callback) => callback()); + .mockImplementation((callback) => { + mockNotifs = []; + callback(); + }); jest .spyOn(window['cordova'].plugins.notification.local, 'schedule') - .mockImplementation((arg, callback) => callback(arg)); + .mockImplementation((arg, callback) => { + arg.forEach((notif) => { + mockNotifs.push(notif); + }); + console.log('called mockNotifs.concat(arg)', mockNotifs); + callback(arg); + }); // call the function await updateScheduledNotifs(reminderSchemes, isScheduling, setIsScheduling, scheduledPromise); + const scheduledNotifs = await getScheduledNotifs(isScheduling, scheduledPromise); expect(setIsScheduling).toHaveBeenCalledWith(true); expect(logDebug).toHaveBeenCalledWith('After cancelling, there are no scheduled notifications'); - expect(logDebug).toHaveBeenCalledWith('After scheduling, there are no scheduled notifications'); + expect(logDebug).toHaveBeenCalledWith( + 'After scheduling, there are 4 scheduled notifications at 21:00 first is November 19, 2023 at 9:00 PM', + ); expect(setIsScheduling).toHaveBeenCalledWith(false); + expect(scheduledNotifs).toHaveLength(4); }); it('should resolve without scheduling if notifications are already scheduled', async () => { @@ -267,10 +285,10 @@ describe('updateScheduledNotifs', () => { // create the mock notifs from cordova plugin (must match the notifs that will generate from the reminder scheme above... // in this case: exampleReminderSchemes.weekly, because getUser is mocked to return reminder_assignment: 'weekly') const mockNotifs = [ - { trigger: { at: DateTime.fromFormat('2023-11-14 21:00', 'yyyy-MM-dd HH:mm').toMillis() } }, - { trigger: { at: DateTime.fromFormat('2023-11-15 21:00', 'yyyy-MM-dd HH:mm').toMillis() } }, - { trigger: { at: DateTime.fromFormat('2023-11-17 21:00', 'yyyy-MM-dd HH:mm').toMillis() } }, - { trigger: { at: DateTime.fromFormat('2023-11-19 21:00', 'yyyy-MM-dd HH:mm').toMillis() } }, + { trigger: { at: DateTime.fromFormat('2023-11-14 21:00', 'yyyy-MM-dd HH:mm').toJSDate() } }, + { trigger: { at: DateTime.fromFormat('2023-11-15 21:00', 'yyyy-MM-dd HH:mm').toJSDate() } }, + { trigger: { at: DateTime.fromFormat('2023-11-17 21:00', 'yyyy-MM-dd HH:mm').toJSDate() } }, + { trigger: { at: DateTime.fromFormat('2023-11-19 21:00', 'yyyy-MM-dd HH:mm').toJSDate() } }, ]; // mock the cordova plugin diff --git a/www/js/splash/notifScheduler.ts b/www/js/splash/notifScheduler.ts index 0111dba26..15adb2521 100644 --- a/www/js/splash/notifScheduler.ts +++ b/www/js/splash/notifScheduler.ts @@ -33,7 +33,7 @@ const calcNotifTimes = (scheme, dayZeroDate, timeOfDay): DateTime[] => { // returns true if all expected times are already scheduled const areAlreadyScheduled = (notifs: any[], expectedTimes: DateTime[]) => { for (const t of expectedTimes) { - if (!notifs.some((n) => DateTime.fromMillis(n.trigger.at).equals(t))) { + if (!notifs.some((n) => DateTime.fromJSDate(n.trigger.at).equals(t))) { return false; } } @@ -54,12 +54,12 @@ const areAlreadyScheduled = (notifs: any[], expectedTimes: DateTime[]) => { function debugGetScheduled(prefix) { window['cordova'].plugins.notification.local.getScheduled((notifs) => { if (!notifs?.length) return logDebug(`${prefix}, there are no scheduled notifications`); - const time = DateTime.fromMillis(notifs?.[0].trigger.at).toFormat('HH:mm'); + const time = DateTime.fromJSDate(notifs[0].trigger.at).toFormat('HH:mm'); //was in plugin, changed to scheduler let scheduledNotifs = []; scheduledNotifs = notifs.map((n) => { - const time = DateTime.fromMillis(n.trigger.at).toFormat('t'); - const date = DateTime.fromMillis(n.trigger.at).toFormat('DDD'); + const date = DateTime.fromJSDate(n.trigger.at).toFormat('DDD'); + const time = DateTime.fromJSDate(n.trigger.at).toFormat('t'); return { key: date, val: time, @@ -109,8 +109,8 @@ const getNotifs = function () { const notifSubset = notifs.slice(0, 5); //prevent near-infinite listing let scheduledNotifs = []; scheduledNotifs = notifSubset.map((n) => { - const time: string = DateTime.fromMillis(n.trigger.at).toFormat('t'); - const date: string = DateTime.fromMillis(n.trigger.at).toFormat('DDD'); + const time: string = DateTime.fromJSDate(n.trigger.at).toFormat('t'); + const date: string = DateTime.fromJSDate(n.trigger.at).toFormat('DDD'); return { key: date, val: time,