From 0e26631fd4f0632ffb84f439a464c4f7f0d66a7e Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Tue, 25 Oct 2022 19:52:00 -0300 Subject: [PATCH 1/3] Organizing calendar files to renderer folders --- index.js | 10 --------- js/main-window.js | 4 ++-- {js => renderer}/classes/BaseCalendar.js | 16 +++++++------- {js => renderer}/classes/CalendarFactory.js | 2 +- .../classes/FlexibleDayCalendar.js | 16 +++++++------- .../classes/FlexibleMonthCalendar.js | 22 +++++++++---------- index.html => src/calendar.html | 12 +++++----- {js => src}/calendar.js | 4 ++-- 8 files changed, 38 insertions(+), 48 deletions(-) delete mode 100644 index.js rename {js => renderer}/classes/BaseCalendar.js (97%) rename {js => renderer}/classes/CalendarFactory.js (95%) rename {js => renderer}/classes/FlexibleDayCalendar.js (96%) rename {js => renderer}/classes/FlexibleMonthCalendar.js (96%) rename index.html => src/calendar.html (50%) rename {js => src}/calendar.js (90%) diff --git a/index.js b/index.js deleted file mode 100644 index a42ded612..000000000 --- a/index.js +++ /dev/null @@ -1,10 +0,0 @@ -/*eslint-disable no-global-assign*/ -// File used by index.html, which loads the main window of TTL -'use strict'; - -// Using esm module to be able to mix node 'require' and ES6 'import' statements -// while we don't move to a newer electron+node system that has this by default -// See https://github.com/electron/electron/issues/21457. - -require = require('esm')(module); -require('electron'); diff --git a/js/main-window.js b/js/main-window.js index ff8513a42..9cc01c4fa 100644 --- a/js/main-window.js +++ b/js/main-window.js @@ -89,8 +89,8 @@ function createWindow() // Prevents flickering from maximize mainWindow.show(); - // and load the index.html of the app. - mainWindow.loadFile(path.join(__dirname, '../index.html')); + // and load the main html of the app as the default window + mainWindow.loadFile(path.join(__dirname, '../src/calendar.html')); ipcMain.on('TOGGLE_TRAY_PUNCH_TIME', (_event, arg) => { diff --git a/js/classes/BaseCalendar.js b/renderer/classes/BaseCalendar.js similarity index 97% rename from js/classes/BaseCalendar.js rename to renderer/classes/BaseCalendar.js index c4fd22c4e..8f0243e66 100644 --- a/js/classes/BaseCalendar.js +++ b/renderer/classes/BaseCalendar.js @@ -9,16 +9,16 @@ import { subtractTime, sumTime, validateTime -} from '../time-math.js'; +} from '../../js/time-math.js'; import { formatDayId, displayWaiverWindow -} from '../../renderer/workday-waiver-aux.js'; -import { showDay, switchCalendarView } from '../user-preferences.js'; -import { getDateStr, getMonthLength } from '../date-aux.js'; -import { computeAllTimeBalanceUntilAsync } from '../time-balance.js'; -import { generateKey } from '../date-db-formatter.js'; -import { getTranslationInLanguageData } from '../../renderer/i18n-translator.js'; +} from '../workday-waiver-aux.js'; +import { showDay, switchCalendarView } from '../../js/user-preferences.js'; +import { getDateStr, getMonthLength } from '../../js/date-aux.js'; +import { computeAllTimeBalanceUntilAsync } from '../../js/time-balance.js'; +import { generateKey } from '../../js/date-db-formatter.js'; +import { getTranslationInLanguageData } from '../i18n-translator.js'; // Global values for calendar const flexibleStore = new Store({name: 'flexible-store'}); @@ -142,7 +142,7 @@ class BaseCalendar _generateTableFooter() { return '\n'; } diff --git a/js/classes/CalendarFactory.js b/renderer/classes/CalendarFactory.js similarity index 95% rename from js/classes/CalendarFactory.js rename to renderer/classes/CalendarFactory.js index af30a270d..9fe64dfad 100644 --- a/js/classes/CalendarFactory.js +++ b/renderer/classes/CalendarFactory.js @@ -2,7 +2,7 @@ const { ipcRenderer } = require('electron'); -import { getDefaultWidthHeight} from '../user-preferences.js'; +import { getDefaultWidthHeight} from '../../js/user-preferences.js'; import { FlexibleMonthCalendar } from './FlexibleMonthCalendar.js'; import { FlexibleDayCalendar } from './FlexibleDayCalendar.js'; diff --git a/js/classes/FlexibleDayCalendar.js b/renderer/classes/FlexibleDayCalendar.js similarity index 96% rename from js/classes/FlexibleDayCalendar.js rename to renderer/classes/FlexibleDayCalendar.js index e575f32fb..d252914ab 100644 --- a/js/classes/FlexibleDayCalendar.js +++ b/renderer/classes/FlexibleDayCalendar.js @@ -6,9 +6,9 @@ import { subtractTime, sumTime, validateTime -} from '../time-math.js'; -import { getDateStr, getMonthLength } from '../date-aux.js'; -import { generateKey } from '../date-db-formatter.js'; +} from '../../js/time-math.js'; +import { getDateStr, getMonthLength } from '../../js/date-aux.js'; +import { generateKey } from '../../js/date-db-formatter.js'; import { BaseCalendar } from './BaseCalendar.js'; /// Compatiblity block - to be removed in the migration of calendar to non-remote electron @@ -79,13 +79,13 @@ class FlexibleDayCalendar extends BaseCalendar */ _getPageHeader() { - const switchView = ``; - const todayBut = ``; - const leftBut = ``; - const rightBut = ``; + const switchView = ``; + const todayBut = ``; + const leftBut = ``; + const rightBut = ``; const title = 'Time to Leave'; return '
'+ - '
' + + '
' + `
${title}
` + '
' + '
' + diff --git a/js/classes/FlexibleMonthCalendar.js b/renderer/classes/FlexibleMonthCalendar.js similarity index 96% rename from js/classes/FlexibleMonthCalendar.js rename to renderer/classes/FlexibleMonthCalendar.js index b9ebd01b0..5f54fe9ec 100644 --- a/js/classes/FlexibleMonthCalendar.js +++ b/renderer/classes/FlexibleMonthCalendar.js @@ -6,14 +6,14 @@ import { subtractTime, sumTime, validateTime -} from '../time-math.js'; -import { getMonthLength } from '../date-aux.js'; -import { generateKey } from '../date-db-formatter.js'; +} from '../../js/time-math.js'; +import { getMonthLength } from '../../js/date-aux.js'; +import { generateKey } from '../../js/date-db-formatter.js'; import { formatDayId, displayWaiverWindow -} from '../../renderer/workday-waiver-aux.js'; -import { getMonthName, getDayAbbr } from '../date-to-string-util.js'; +} from '../workday-waiver-aux.js'; +import { getMonthName, getDayAbbr } from '../../js/date-to-string-util.js'; import { BaseCalendar } from './BaseCalendar.js'; /// Compatiblity block - to be removed in the migration of calendar to non-remote electron @@ -112,13 +112,13 @@ class FlexibleMonthCalendar extends BaseCalendar */ _getPageHeader() { - const switchView = ``; - const todayBut = ``; - const leftBut = ``; - const rightBut = ``; + const switchView = ``; + const todayBut = ``; + const leftBut = ``; + const rightBut = ``; const title = 'Time to Leave'; return '
'+ - '
' + + '
' + `
${title}
` + '
' + '
' + @@ -233,7 +233,7 @@ class FlexibleMonthCalendar extends BaseCalendar `
` + getDayAbbr(this._languageData.data, weekDay) + '
' + '
' + ' ' + day + ' ' + - '' + + '' + '
' + '
' + '-' + diff --git a/index.html b/src/calendar.html similarity index 50% rename from index.html rename to src/calendar.html index 3d3decf55..530253684 100644 --- a/index.html +++ b/src/calendar.html @@ -7,18 +7,18 @@ Time to Leave - - + + - - + + - - + + diff --git a/js/calendar.js b/src/calendar.js similarity index 90% rename from js/calendar.js rename to src/calendar.js index f1782b9c1..22c4a8d7e 100644 --- a/js/calendar.js +++ b/src/calendar.js @@ -2,8 +2,8 @@ const { ipcRenderer } = require('electron'); -import { getUserPreferences } from './user-preferences.js'; -import { CalendarFactory } from './classes/CalendarFactory.js'; +import { getUserPreferences } from '../js/user-preferences.js'; +import { CalendarFactory } from '../renderer/classes/CalendarFactory.js'; import { applyTheme } from '../renderer/themes.js'; // Global values for calendar From 647c9c0a2caac3145c949821d2904f099645e98a Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Tue, 25 Oct 2022 21:55:43 -0300 Subject: [PATCH 2/3] Fix #889: Adapting calendar window to electron isolated environment --- .../__renderer__/notification-channel.js | 2 +- __tests__/__renderer__/window-aux.js | 4 +- esm-main.js | 2 + js/main-window.js | 17 ++-- js/menus.js | 4 +- js/notification-channel.js | 14 --- js/time-balance.js | 1 + main/calendar-aux.js | 43 +++++++++ renderer/classes/BaseCalendar.js | 54 ++++------- renderer/classes/CalendarFactory.js | 12 +-- renderer/classes/FlexibleDayCalendar.js | 25 +---- renderer/classes/FlexibleMonthCalendar.js | 25 +---- renderer/notification-channel.js | 9 ++ renderer/preload-scripts/calendar-api.js | 93 +++++++++++++++++++ renderer/preload-scripts/calendar-bridge.js | 9 ++ .../preload-scripts/esm-calendar-bridge.js | 8 ++ renderer/workday-waiver-aux.js | 6 +- src/calendar.html | 8 +- src/calendar.js | 37 +++++--- 19 files changed, 233 insertions(+), 140 deletions(-) delete mode 100644 js/notification-channel.js create mode 100644 main/calendar-aux.js create mode 100644 renderer/notification-channel.js create mode 100644 renderer/preload-scripts/calendar-api.js create mode 100644 renderer/preload-scripts/calendar-bridge.js create mode 100644 renderer/preload-scripts/esm-calendar-bridge.js diff --git a/__tests__/__renderer__/notification-channel.js b/__tests__/__renderer__/notification-channel.js index 54ae77107..6026fd508 100644 --- a/__tests__/__renderer__/notification-channel.js +++ b/__tests__/__renderer__/notification-channel.js @@ -1,4 +1,4 @@ -const notificationChannel = require('../../js/notification-channel.js'); +const notificationChannel = require('../../renderer/notification-channel.js'); describe('Notifications channel', () => { diff --git a/__tests__/__renderer__/window-aux.js b/__tests__/__renderer__/window-aux.js index a74994aa2..6564bcaa3 100644 --- a/__tests__/__renderer__/window-aux.js +++ b/__tests__/__renderer__/window-aux.js @@ -89,7 +89,7 @@ describe('window-aux.js Testing', function() // }); // }); - describe('showDialogSync(options, successCallback)', function() + describe('showDialogSync(options)', function() { test('Does not crash', async() => { @@ -104,7 +104,7 @@ describe('window-aux.js Testing', function() const options = { title: 'Time to Leave', }; - windowAux.showDialogSync(options, () => + windowAux.showDialogSync(options).then(() => { return; }); diff --git a/esm-main.js b/esm-main.js index c41c0d069..7321c9d20 100644 --- a/esm-main.js +++ b/esm-main.js @@ -10,6 +10,7 @@ const { handleSquirrelEvent } = require('./js/squirrel.js'); const { showAlert, showDialogSync } = require('./js/window-aux.js'); import { appConfig } from './js/app-config.js'; +import { setupCalendarStore } from './main/calendar-aux.js'; if (appConfig.win32) { @@ -134,6 +135,7 @@ app.on('ready', () => } createWindow(); createMenu(); + setupCalendarStore(); setLanguageChangedCallback(createMenu); triggerStartupDialogs(); setInterval(refreshOnDayChange, 60 * 60 * 1000); diff --git a/js/main-window.js b/js/main-window.js index 9cc01c4fa..ae56928b9 100644 --- a/js/main-window.js +++ b/js/main-window.js @@ -17,7 +17,7 @@ const { const { getCurrentTranslation } = require('../src/configs/i18next.config'); let { contextMenu, tray } = require('./windows.js'); -import { getDefaultWidthHeight, getUserPreferences } from './user-preferences.js'; +import { getDefaultWidthHeight, getUserPreferences, switchCalendarView } from './user-preferences.js'; import { appConfig, getDetails } from './app-config.js'; import { createLeaveNotification } from './notification.js'; @@ -80,7 +80,8 @@ function createWindow() show: false, webPreferences: { nodeIntegration: true, - enableRemoteModule: true + preload: path.join(__dirname, '../renderer/preload-scripts/calendar-bridge.js'), + contextIsolation: true } }); @@ -100,14 +101,16 @@ function createWindow() tray.setContextMenu(contextMenu); }); - ipcMain.on('RESIZE_MAIN_WINDOW', (event, width, height) => + ipcMain.on('RESIZE_MAIN_WINDOW', () => { - mainWindow.setSize(width, height); + const widthHeight = getDefaultWidthHeight(); + mainWindow.setSize(widthHeight.width, widthHeight.height); }); - ipcMain.on('VIEW_CHANGED', (event, savedPreferences) => + ipcMain.on('SWITCH_VIEW', () => { - mainWindow.webContents.send('PREFERENCE_SAVED', savedPreferences); + const preferences = switchCalendarView(); + mainWindow.webContents.send('PREFERENCES_SAVED', preferences); }); ipcMain.on('RECEIVE_LEAVE_BY', (event, element) => @@ -186,7 +189,7 @@ function proposeFlexibleDbMigration() if (response === 0 /*migrate*/) { const migrateResult = migrateFixedDbToFlexible(); - getMainWindow().webContents.send('RELOAD_CALENDAR'); + mainWindow.webContents.send('RELOAD_CALENDAR'); if (migrateResult['result'] === true) { dialog.showMessageBox(BrowserWindow.getFocusedWindow(), diff --git a/js/menus.js b/js/menus.js index 9876b15d2..de66265d5 100644 --- a/js/menus.js +++ b/js/menus.js @@ -1,6 +1,6 @@ 'use strict'; -const { app, BrowserWindow, clipboard, dialog, shell } = require('electron'); +const { app, BrowserWindow, clipboard, dialog, shell, ipcMain } = require('electron'); const path = require('path'); const Store = require('electron-store'); @@ -145,7 +145,7 @@ function getEditMenuTemplate(mainWindow) if (savedPreferences !== null) { savePreferences(savedPreferences); - mainWindow.webContents.send('PREFERENCE_SAVED', savedPreferences); + mainWindow.webContents.send('PREFERENCES_SAVED', savedPreferences); } }); prefWindow.webContents.on('before-input-event', (event, input) => diff --git a/js/notification-channel.js b/js/notification-channel.js deleted file mode 100644 index 38dd5028b..000000000 --- a/js/notification-channel.js +++ /dev/null @@ -1,14 +0,0 @@ -const { ipcRenderer } = require('electron'); - -const searchLeaveByElement = (event) => -{ - const leaveByElement = $('#leave-by').val(); - event.sender.send('RECEIVE_LEAVE_BY', leaveByElement); -}; - -// Event handler to search for #leave-by element, not accesible through main process -ipcRenderer.on('GET_LEAVE_BY', searchLeaveByElement); - -module.exports = { - searchLeaveByElement -}; \ No newline at end of file diff --git a/js/time-balance.js b/js/time-balance.js index 67dbbb63b..422ec23f3 100644 --- a/js/time-balance.js +++ b/js/time-balance.js @@ -203,6 +203,7 @@ async function computeAllTimeBalanceUntilAsync(limitDate) }, 1); }); } + export { computeAllTimeBalanceUntilAsync, computeAllTimeBalanceUntil, diff --git a/main/calendar-aux.js b/main/calendar-aux.js new file mode 100644 index 000000000..724fe0086 --- /dev/null +++ b/main/calendar-aux.js @@ -0,0 +1,43 @@ +'use strict'; + +const { ipcMain } = require('electron'); + +import { computeAllTimeBalanceUntilAsync } from '../js/time-balance.js'; + +const Store = require('electron-store'); + +const flexibleStore = new Store({name: 'flexible-store'}); + +function getFlexibleStore() +{ + return flexibleStore.store; +} + +function setupCalendarStore() +{ + ipcMain.handle('GET_FLEXIBLE_STORE_CONTENTS', () => + { + return getFlexibleStore(); + }); + + ipcMain.handle('SET_FLEXIBLE_STORE_DATA', (event, key, contents) => + { + flexibleStore.set(key, contents); + return true; + }); + + ipcMain.handle('DELETE_FLEXIBLE_STORE_DATA', (event, key) => + { + flexibleStore.delete(key); + return true; + }); + + ipcMain.handle('COMPUTE_ALL_TIME_BALANCE_UNTIL', (event, targetDate) => + { + return computeAllTimeBalanceUntilAsync(targetDate); + }); +} + +export { + setupCalendarStore +}; diff --git a/renderer/classes/BaseCalendar.js b/renderer/classes/BaseCalendar.js index 8f0243e66..d25237b0f 100644 --- a/renderer/classes/BaseCalendar.js +++ b/renderer/classes/BaseCalendar.js @@ -1,8 +1,5 @@ 'use strict'; -const Store = require('electron-store'); -const { ipcRenderer } = require('electron'); - import { hourMinToHourFormatted, isNegative, @@ -10,20 +7,10 @@ import { sumTime, validateTime } from '../../js/time-math.js'; -import { - formatDayId, - displayWaiverWindow -} from '../workday-waiver-aux.js'; -import { showDay, switchCalendarView } from '../../js/user-preferences.js'; import { getDateStr, getMonthLength } from '../../js/date-aux.js'; -import { computeAllTimeBalanceUntilAsync } from '../../js/time-balance.js'; import { generateKey } from '../../js/date-db-formatter.js'; import { getTranslationInLanguageData } from '../i18n-translator.js'; -// Global values for calendar -const flexibleStore = new Store({name: 'flexible-store'}); -const waivedWorkdays = new Store({name: 'waived-workdays'}); - // Holds the calendar information and manipulation functions class BaseCalendar { @@ -34,8 +21,6 @@ class BaseCalendar { this._calendarDate = new Date(); this.updateLanguageData(languageData); - this.loadInternalStore(); - this.loadInternalWaiveStore(); this.updatePreferences(preferences); this._initCalendar(); } @@ -74,7 +59,7 @@ class BaseCalendar _updateAllTimeBalance() { const targetDate = this._getTargetDayForAllTimeBalance(); - computeAllTimeBalanceUntilAsync(targetDate) + window.mainApi.computeAllTimeBalanceUntilPromise(targetDate) .then(balance => { const balanceElement = $('#overall-balance'); @@ -158,10 +143,10 @@ class BaseCalendar /** * Reloads internal DBs based on external DBs and then redraws the calendar. */ - reload() + async reload() { - this.loadInternalStore(); - this.loadInternalWaiveStore(); + await this.loadInternalStore(); + await this.loadInternalWaiveStore(); this.redraw(); } @@ -192,14 +177,6 @@ class BaseCalendar calendar._updateTimeDayCallback($(this).attr('data-date')); }); - $('.waiver-trigger').off('click').on('click', function() - { - // deepcode ignore no-invalid-this: jQuery use - const dayId = $(this).closest('tr').attr('id').substr(3); - const waiverDay = formatDayId(dayId); - displayWaiverWindow(waiverDay); - }); - this._updateAllTimeBalance(); } @@ -408,11 +385,12 @@ class BaseCalendar /** * Stores year data in memory to make operations faster */ - loadInternalStore() + async loadInternalStore() { this._internalStore = {}; - for (const entry of flexibleStore) + const flexibleStore = await window.mainApi.getFlexibleStoreContents(); + for (const entry of Object.entries(flexibleStore)) { const key = entry[0]; const value = entry[1]; @@ -424,11 +402,12 @@ class BaseCalendar /** * Stores waiver data in memory to make operations faster */ - loadInternalWaiveStore() + async loadInternalWaiveStore() { this._internalWaiverStore = {}; - for (const entry of waivedWorkdays) + const waivedWorkdays = await window.mainApi.getWaiverStoreContents(); + for (const entry of Object.entries(waivedWorkdays)) { const date = entry[0]; const reason = entry[1]['reason']; @@ -455,7 +434,7 @@ class BaseCalendar _setStore(key, newValues) { this._internalStore[key] = { values: newValues }; - flexibleStore.set(key, this._internalStore[key]); + window.mainApi.setFlexibleStoreData(key, this._internalStore[key]); } /* @@ -464,11 +443,11 @@ class BaseCalendar _removeStore(key) { this._internalStore[key] = undefined; - flexibleStore.delete(key); + window.mainApi.deleteFlexibleStoreData(key); } /** - * Calls showDay from user-preferences.js passing the last preferences set. + * Checks based on last set preferences if the day can be shown. * @param {number} year * @param {number} month * @param {number} day @@ -476,7 +455,7 @@ class BaseCalendar */ _showDay(year, month, day) { - return showDay(year, month, day, this._preferences); + return window.mainApi.showDay(year, month, day, this._preferences); } /** @@ -722,7 +701,7 @@ class BaseCalendar _togglePunchButton(enable) { $('#punch-button').prop('disabled', !enable); - ipcRenderer.send('TOGGLE_TRAY_PUNCH_TIME', enable); + window.mainApi.toggleTrayPunchTime(enable); } /** @@ -730,8 +709,7 @@ class BaseCalendar */ _switchView() { - const preferences = switchCalendarView(); - ipcRenderer.send('VIEW_CHANGED', preferences); + window.mainApi.switchView(); } } diff --git a/renderer/classes/CalendarFactory.js b/renderer/classes/CalendarFactory.js index 9fe64dfad..48ca59458 100644 --- a/renderer/classes/CalendarFactory.js +++ b/renderer/classes/CalendarFactory.js @@ -1,17 +1,13 @@ 'use strict'; -const { ipcRenderer } = require('electron'); - -import { getDefaultWidthHeight} from '../../js/user-preferences.js'; import { FlexibleMonthCalendar } from './FlexibleMonthCalendar.js'; import { FlexibleDayCalendar } from './FlexibleDayCalendar.js'; class CalendarFactory { - static getInstance(preferences, languageData, calendar = undefined) + static async getInstance(preferences, languageData, calendar = undefined) { const view = preferences['view']; - const widthHeight = getDefaultWidthHeight(); if (view !== 'day' && view !== 'month') { throw new Error(`Could not instantiate ${view}`); @@ -23,9 +19,11 @@ class CalendarFactory { if (calendar !== undefined && calendar.constructor.name !== constructorName) { - ipcRenderer.send('RESIZE_MAIN_WINDOW', widthHeight.width, widthHeight.height); + window.mainApi.resizeMainWindow(); } - return new CalendarClass(preferences, languageData); + calendar = new CalendarClass(preferences, languageData); + await calendar.reload(); + return calendar; } else { diff --git a/renderer/classes/FlexibleDayCalendar.js b/renderer/classes/FlexibleDayCalendar.js index d252914ab..6baa64e2c 100644 --- a/renderer/classes/FlexibleDayCalendar.js +++ b/renderer/classes/FlexibleDayCalendar.js @@ -11,27 +11,6 @@ import { getDateStr, getMonthLength } from '../../js/date-aux.js'; import { generateKey } from '../../js/date-db-formatter.js'; import { BaseCalendar } from './BaseCalendar.js'; -/// Compatiblity block - to be removed in the migration of calendar to non-remote electron -const { remote } = require('electron'); -const { BrowserWindow, dialog } = remote; - -/** - * Opens an electron dialog, based on the options, and performs the successCallback after promise is resolved. - * @param {Object.} options - * @param {function} successCallback - */ -function showDialog(options, successCallback) -{ - options['title'] = options['title'] || 'Time to Leave'; - dialog.showMessageBox(BrowserWindow.getFocusedWindow(), options) - .then(successCallback) - .catch(err => - { - console.log(err); - }); -} -//// - class FlexibleDayCalendar extends BaseCalendar { /** @@ -59,8 +38,6 @@ class FlexibleDayCalendar extends BaseCalendar const [year, month, day] = $(event.target).val().split('-'); this._goToDate(new Date(year, month-1, day)); }); - - this._draw(); } /** @@ -341,7 +318,7 @@ class FlexibleDayCalendar extends BaseCalendar const len = getInputs.length; if (getInputs.get(len-1).value !== '' || getInputs.get(len-2).value !== '') { - showDialog(removeEntriesDialogOptions, (result) => + window.mainApi.showDialogSync(removeEntriesDialogOptions).then((result) => { const buttonId = result.response; if (buttonId === 1) diff --git a/renderer/classes/FlexibleMonthCalendar.js b/renderer/classes/FlexibleMonthCalendar.js index 5f54fe9ec..4bb413de1 100644 --- a/renderer/classes/FlexibleMonthCalendar.js +++ b/renderer/classes/FlexibleMonthCalendar.js @@ -16,27 +16,6 @@ import { import { getMonthName, getDayAbbr } from '../../js/date-to-string-util.js'; import { BaseCalendar } from './BaseCalendar.js'; -/// Compatiblity block - to be removed in the migration of calendar to non-remote electron -const { remote } = require('electron'); -const { BrowserWindow, dialog } = remote; - -/** - * Opens an electron dialog, based on the options, and performs the successCallback after promise is resolved. - * @param {Object.} options - * @param {function} successCallback - */ -function showDialog(options, successCallback) -{ - options['title'] = options['title'] || 'Time to Leave'; - dialog.showMessageBox(BrowserWindow.getFocusedWindow(), options) - .then(successCallback) - .catch(err => - { - console.log(err); - }); -} -//// - class FlexibleMonthCalendar extends BaseCalendar { /** @@ -58,8 +37,6 @@ class FlexibleMonthCalendar extends BaseCalendar $('#prev-month').on('click', () => { this._prevMonth(); }); $('#current-month').on('click', () => { this._goToCurrentDate(); }); $('#switch-view').on('click', () => { this._switchView(); }); - - this._draw(); } /** @@ -441,7 +418,7 @@ class FlexibleMonthCalendar extends BaseCalendar const len = getInputs.length; if (getInputs.get(len-1).value !== '' || getInputs.get(len-2).value !== '') { - showDialog(removeEntriesDialogOptions, (result) => + window.mainApi.showDialogSync(removeEntriesDialogOptions).then((result) => { const buttonId = result.response; if (buttonId === 1) diff --git a/renderer/notification-channel.js b/renderer/notification-channel.js new file mode 100644 index 000000000..b014d3198 --- /dev/null +++ b/renderer/notification-channel.js @@ -0,0 +1,9 @@ +const searchLeaveByElement = (event) => +{ + const leaveByElement = $('#leave-by').val(); + event.sender.send('RECEIVE_LEAVE_BY', leaveByElement); +}; + +export { + searchLeaveByElement +}; \ No newline at end of file diff --git a/renderer/preload-scripts/calendar-api.js b/renderer/preload-scripts/calendar-api.js new file mode 100644 index 000000000..41b9cef8b --- /dev/null +++ b/renderer/preload-scripts/calendar-api.js @@ -0,0 +1,93 @@ +'use strict'; + +const { ipcRenderer } = require('electron'); +import * as config from '../../src/configs/app.config.js'; +import { getUserPreferencesPromise, showDay } from '../../js/user-preferences.js'; + +function getLanguageDataPromise() +{ + return ipcRenderer.invoke('GET_LANGUAGE_DATA'); +} + +function resizeMainWindow() +{ + ipcRenderer.send('RESIZE_MAIN_WINDOW'); +} + +function switchView() +{ + ipcRenderer.send('SWITCH_VIEW'); +} + +function toggleTrayPunchTime(enable) +{ + ipcRenderer.send('TOGGLE_TRAY_PUNCH_TIME', enable); +} + +function showDayByPreferences(year, month, day, preferences) +{ + return showDay(year, month, day, preferences); +} + +function displayWaiverWindow(waiverDay) +{ + ipcRenderer.send('SET_WAIVER_DAY', waiverDay); +} + +function showDialogSync(dialogOptions) +{ + return ipcRenderer.invoke('SHOW_DIALOG', dialogOptions); +} + +function getWaiverStoreContents() +{ + return ipcRenderer.invoke('GET_WAIVER_STORE_CONTENTS'); +} + +function getFlexibleStoreContents() +{ + return ipcRenderer.invoke('GET_FLEXIBLE_STORE_CONTENTS'); +} + +function setFlexibleStoreData(key, contents) +{ + return ipcRenderer.invoke('SET_FLEXIBLE_STORE_DATA', key, contents); +} + +function deleteFlexibleStoreData(key) +{ + return ipcRenderer.invoke('DELETE_FLEXIBLE_STORE_DATA', key); +} + +function computeAllTimeBalanceUntilPromise(targetDate) +{ + return ipcRenderer.invoke('COMPUTE_ALL_TIME_BALANCE_UNTIL', targetDate); +} + +const calendarApi = { + getLanguageMap: () => config.getLanguageMap(), + getUserPreferencesPromise: () => getUserPreferencesPromise(), + getLanguageDataPromise: () => getLanguageDataPromise(), + handleRefreshOnDayChange: (callback) => ipcRenderer.on('REFRESH_ON_DAY_CHANGE', callback), + handlePreferencesSaved: (callback) => ipcRenderer.on('PREFERENCES_SAVED', callback), + handleWaiverSaved: (callback) => ipcRenderer.on('WAIVER_SAVED', callback), + handleCalendarReload: (callback) => ipcRenderer.on('RELOAD_CALENDAR', callback), + handlePunchDate: (callback) => ipcRenderer.on('PUNCH_DATE', callback), + handleReloadCalendar: (callback) => ipcRenderer.on('RELOAD_CALENDAR', callback), + handleLeaveBy: (callback) => ipcRenderer.on('GET_LEAVE_BY', callback), + resizeMainWindow: () => resizeMainWindow(), + switchView: () => switchView(), + toggleTrayPunchTime: (enable) => toggleTrayPunchTime(enable), + showDay: (year, month, day, userPreferences) => showDayByPreferences(year, month, day, userPreferences), + displayWaiverWindow: (waiverDay) => displayWaiverWindow(waiverDay), + showDialogSync: (dialogOptions) => showDialogSync(dialogOptions), + getWaiverStoreContents: () => getWaiverStoreContents(), + getFlexibleStoreContents: () => getFlexibleStoreContents(), + setFlexibleStoreData: (key, contents) => setFlexibleStoreData(key, contents), + deleteFlexibleStoreData: (key) => deleteFlexibleStoreData(key), + computeAllTimeBalanceUntilPromise: (targetDate) => computeAllTimeBalanceUntilPromise(targetDate), +}; + +module.exports = { + calendarApi +}; diff --git a/renderer/preload-scripts/calendar-bridge.js b/renderer/preload-scripts/calendar-bridge.js new file mode 100644 index 000000000..efefb3381 --- /dev/null +++ b/renderer/preload-scripts/calendar-bridge.js @@ -0,0 +1,9 @@ +/*eslint-disable no-global-assign*/ +'use strict'; + +// Using esm module to be able to mix node 'require' and ES6 'import' statements +// while we don't move to a newer electron+node system that has this by default +// See https://github.com/electron/electron/issues/21457. + +require = require('esm')(module); +module.exports = require('./esm-calendar-bridge.js'); diff --git a/renderer/preload-scripts/esm-calendar-bridge.js b/renderer/preload-scripts/esm-calendar-bridge.js new file mode 100644 index 000000000..effad1149 --- /dev/null +++ b/renderer/preload-scripts/esm-calendar-bridge.js @@ -0,0 +1,8 @@ +'use strict'; + +const { contextBridge } = require('electron'); +const { calendarApi } = require('./calendar-api.js'); + +contextBridge.exposeInMainWorld( + 'mainApi', calendarApi +); diff --git a/renderer/workday-waiver-aux.js b/renderer/workday-waiver-aux.js index 26e32d9b2..2a69ab819 100644 --- a/renderer/workday-waiver-aux.js +++ b/renderer/workday-waiver-aux.js @@ -1,7 +1,5 @@ 'use strict'; -const { ipcRenderer } = require('electron'); - /** * @param {string} dayId - day in '--' format * @returns {string} - day in 'YYYY-MM-DD' format @@ -15,13 +13,13 @@ function formatDayId(dayId) } /** - * Sends waiverDay value through SET_WAIVER_DAY event, which triggers open window event on main process. + * Sends waiverDay value to the main process, which triggers the waiver manager window. * * @param {string} waiverDay - day in 'YYYY-MM-DD' format */ function displayWaiverWindow(waiverDay) { - ipcRenderer.send('SET_WAIVER_DAY', waiverDay); + window.mainApi.displayWaiverWindow(waiverDay); } export { diff --git a/src/calendar.html b/src/calendar.html index 530253684..ecccf00b1 100644 --- a/src/calendar.html +++ b/src/calendar.html @@ -12,13 +12,13 @@ - + + - - diff --git a/src/calendar.js b/src/calendar.js index 22c4a8d7e..04a91de24 100644 --- a/src/calendar.js +++ b/src/calendar.js @@ -1,27 +1,33 @@ 'use strict'; -const { ipcRenderer } = require('electron'); - -import { getUserPreferences } from '../js/user-preferences.js'; import { CalendarFactory } from '../renderer/classes/CalendarFactory.js'; import { applyTheme } from '../renderer/themes.js'; +import { searchLeaveByElement } from '../renderer/notification-channel.js'; // Global values for calendar let calendar = undefined; function setupCalendar(preferences) { - ipcRenderer.invoke('GET_LANGUAGE_DATA').then(languageData => + window.mainApi.getLanguageDataPromise().then(async languageData => { - calendar = CalendarFactory.getInstance(preferences, languageData, calendar); + calendar = await CalendarFactory.getInstance(preferences, languageData, calendar); applyTheme(preferences.theme); }); } +/* + * Reload the calendar upon request from main + */ +window.mainApi.handleCalendarReload(async() => +{ + await calendar.reload(); +}); + /* * Update the calendar after a day has passed */ -ipcRenderer.on('REFRESH_ON_DAY_CHANGE', (event, oldDate, oldMonth, oldYear) => +window.mainApi.handleRefreshOnDayChange((event, oldDate, oldMonth, oldYear) => { calendar.refreshOnDayChange(oldDate, oldMonth, oldYear); }); @@ -29,7 +35,7 @@ ipcRenderer.on('REFRESH_ON_DAY_CHANGE', (event, oldDate, oldMonth, oldYear) => /* * Get notified when preferences has been updated. */ -ipcRenderer.on('PREFERENCE_SAVED', function(event, prefs) +window.mainApi.handlePreferencesSaved((event, prefs) => { setupCalendar(prefs); }); @@ -37,16 +43,16 @@ ipcRenderer.on('PREFERENCE_SAVED', function(event, prefs) /* * Get notified when waivers get updated. */ -ipcRenderer.on('WAIVER_SAVED', function() +window.mainApi.handleWaiverSaved(async() => { - calendar.loadInternalWaiveStore(); + await calendar.loadInternalWaiveStore(); calendar.redraw(); }); /* * Punch the date and time as requested by user. */ -ipcRenderer.on('PUNCH_DATE', function() +window.mainApi.handlePunchDate(() => { calendar.punchDate(); }); @@ -54,14 +60,19 @@ ipcRenderer.on('PUNCH_DATE', function() /* * Reload calendar, used after database altering actions. */ -ipcRenderer.on('RELOAD_CALENDAR', function() +window.mainApi.handleReloadCalendar(() => { calendar.reload(); }); +/* + * Returns value of "leave by" for notifications. + */ +window.mainApi.handleLeaveBy(searchLeaveByElement); + // On page load, create the calendar and setup notification -$(() => +$(async() => { - const preferences = getUserPreferences(); + const preferences = await window.mainApi.getUserPreferencesPromise(); setupCalendar(preferences); }); From cc32c2ae66bd47a5b1f983585b76cb4e1a0365a3 Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Wed, 26 Oct 2022 21:54:16 -0300 Subject: [PATCH 3/3] Fix #889: Adapting calendar tests to new format --- __tests__/__main__/main-window.js | 22 ++++--- .../__renderer__/classes/BaseCalendar.js | 57 ++++++++++++++++--- .../__renderer__/classes/CalendarFactory.js | 54 +++++++++++------- .../classes/FlexibleDayCalendar.js | 53 ++++++++++++----- .../classes/FlexibleMonthCalendar.js | 47 +++++++++++---- __tests__/__renderer__/workday-waiver-aux.js | 6 ++ renderer/classes/BaseCalendar.js | 12 +++- renderer/classes/CalendarFactory.js | 2 +- 8 files changed, 188 insertions(+), 65 deletions(-) diff --git a/__tests__/__main__/main-window.js b/__tests__/__main__/main-window.js index 8ccb77b20..cbdaf244c 100644 --- a/__tests__/__main__/main-window.js +++ b/__tests__/__main__/main-window.js @@ -51,7 +51,7 @@ describe('main-window.js', () => expect(mainWindow).toBeInstanceOf(BrowserWindow); expect(ipcMain.listenerCount('TOGGLE_TRAY_PUNCH_TIME')).toBe(1); expect(ipcMain.listenerCount('RESIZE_MAIN_WINDOW')).toBe(1); - expect(ipcMain.listenerCount('VIEW_CHANGED')).toBe(1); + expect(ipcMain.listenerCount('SWITCH_VIEW')).toBe(1); expect(ipcMain.listenerCount('RECEIVE_LEAVE_BY')).toBe(1); expect(mainWindow.listenerCount('minimize')).toBe(2); expect(mainWindow.listenerCount('close')).toBe(1); @@ -73,13 +73,17 @@ describe('main-window.js', () => const mainWindow = getMainWindow(); mainWindow.on('ready-to-show', () => { - ipcMain.emit('RESIZE_MAIN_WINDOW', {}, 500, 600); - expect(mainWindow.getSize()).toEqual([500, 600]); + ipcMain.emit('RESIZE_MAIN_WINDOW'); + expect(mainWindow.getSize()).toEqual([1010, 800]); done(); }); }); test('It should not resize window if values are smaller than minimum', (done) => { + savePreferences({ + ...defaultPreferences, + ['view']: 'day' + }); createWindow(); /** * @type {BrowserWindow} @@ -87,16 +91,16 @@ describe('main-window.js', () => const mainWindow = getMainWindow(); mainWindow.on('ready-to-show', () => { - ipcMain.emit('RESIZE_MAIN_WINDOW', {}, 100, 100); - expect(mainWindow.getSize()).toEqual([450, 450]); + ipcMain.emit('RESIZE_MAIN_WINDOW'); + expect(mainWindow.getSize()).toEqual([500, 500]); done(); }); }); }); - describe('emit VIEW_CHANGED', () => + describe('emit SWITCH_VIEW', () => { - test('It should send new event to ipcRendered', (done) => + test('It should send new event to ipcRenderer', (done) => { createWindow(); /** @@ -117,10 +121,10 @@ describe('main-window.js', () => ipcMain.on('FINISH_TEST', (event, savedPreferences) => { expect(windowSpy).toBeCalledTimes(1); - expect(savedPreferences).toEqual({ new: 'prefrences' }); + expect(savedPreferences['view']).toEqual('day'); done(); }); - ipcMain.emit('VIEW_CHANGED', {}, { new: 'prefrences' }); + ipcMain.emit('SWITCH_VIEW'); windowSpy.mockRestore(); }); }); diff --git a/__tests__/__renderer__/classes/BaseCalendar.js b/__tests__/__renderer__/classes/BaseCalendar.js index f1d61371a..97cdbb35c 100644 --- a/__tests__/__renderer__/classes/BaseCalendar.js +++ b/__tests__/__renderer__/classes/BaseCalendar.js @@ -1,9 +1,10 @@ import ElectronStore from 'electron-store'; -import { BaseCalendar } from '../../../js/classes/BaseCalendar.js'; +import { BaseCalendar } from '../../../renderer/classes/BaseCalendar.js'; import { generateKey } from '../../../js/date-db-formatter.js'; -import { getUserPreferences, resetPreferences, savePreferences } from '../../../js/user-preferences.js'; +import { getUserPreferences, resetPreferences, savePreferences, switchCalendarView } from '../../../js/user-preferences.js'; const Store = require('electron-store'); const timeBalance = require('../../../js/time-balance'); +import { calendarApi } from '../../../renderer/preload-scripts/calendar-api.js'; jest.mock('../../../js/time-math', () => { @@ -17,6 +18,19 @@ jest.mock('../../../js/time-math', () => const timeMath = require('../../../js/time-math'); window.$ = require('jquery'); +// Mocked APIs from the preload script of the calendar window +window.mainApi = calendarApi; + +window.mainApi.computeAllTimeBalanceUntilPromise = (targetDate) => +{ + return timeBalance.computeAllTimeBalanceUntilAsync(targetDate); +}; + +window.mainApi.switchView = () => +{ + switchCalendarView(); +}; + describe('BaseCalendar.js', () => { class ExtendedClass extends BaseCalendar @@ -39,6 +53,15 @@ describe('BaseCalendar.js', () => waivedWorkdays.clear(); ExtendedClass.prototype._initCalendar = () => {}; ExtendedClass.prototype._getTargetDayForAllTimeBalance = () => {}; + + window.mainApi.getFlexibleStoreContents = () => + { + return flexibleStore.store; + }; + window.mainApi.getWaiverStoreContents = () => + { + return waivedWorkdays.store; + }; }); describe('constructor', () => @@ -60,7 +83,7 @@ describe('BaseCalendar.js', () => expect(() => new ExtendedClass(preferences, languageData)._getTargetDayForAllTimeBalance()).toThrow('Please implement this.'); }); - test('Should build with default values', (done) => + test('Should build with default values', async(done) => { ExtendedClass.prototype._initCalendar = () => { done(); }; const preferences = {view: 'day'}; @@ -68,12 +91,19 @@ describe('BaseCalendar.js', () => const calendar = new ExtendedClass(preferences, languageData); expect(calendar._calendarDate).toBeInstanceOf(Date); expect(calendar._languageData).toEqual(languageData); + expect(calendar._preferences).toEqual(preferences); + + // These no longer get set in the constructor + expect(calendar._internalStore).toEqual(undefined); + expect(calendar._internalWaiverStore).toEqual(undefined); + + // But are set after awaiting for initialization + await calendar.initializeStores(); expect(calendar._internalStore).toEqual({}); expect(calendar._internalWaiverStore).toEqual({}); - expect(calendar._preferences).toEqual(preferences); }); - test('Should build with default internal store values', (done) => + test('Should build with default internal store values', async(done) => { ExtendedClass.prototype._initCalendar = () => { done(); }; const flexibleStore = new ElectronStore({name: 'flexible-store'}); @@ -90,6 +120,14 @@ describe('BaseCalendar.js', () => const calendar = new ExtendedClass(preferences, languageData); expect(calendar._calendarDate).toBeInstanceOf(Date); expect(calendar._languageData).toEqual(languageData); + expect(calendar._preferences).toEqual(preferences); + + // These no longer get set in the constructor + expect(calendar._internalStore).toEqual(undefined); + expect(calendar._internalWaiverStore).toEqual(undefined); + + // But are set after awaiting for initialization + await calendar.initializeStores(); expect(calendar._internalStore).toEqual({ flexible: 'store' }); @@ -99,7 +137,6 @@ describe('BaseCalendar.js', () => hours: '10:00' } }); - expect(calendar._preferences).toEqual(preferences); }); }); @@ -116,7 +153,7 @@ describe('BaseCalendar.js', () => expect(mocks.compute).toHaveBeenCalledTimes(0); }); - test('Should not update value because of rejection', () => + test('Should not update value because of rejection', async() => { mocks.compute = jest.spyOn(timeBalance, 'computeAllTimeBalanceUntilAsync').mockImplementation(() => Promise.reject()); const preferences = {view: 'day'}; @@ -388,20 +425,21 @@ describe('BaseCalendar.js', () => describe('_updateDayTotal()', () => { - test('Should not update when day has not ended', () => + test('Should not update when day has not ended', async() => { const newDate = new Date(); const key = generateKey(newDate.getFullYear(), newDate.getMonth(), newDate.getDate()); $('body').append(`
`); $(`#${key}`).append(''); const calendar = new ExtendedClass(getUserPreferences(), {}); + await calendar.initializeStores(); calendar._updateDayTotal(key); const dayTotalSpan = $('#' + key).parent().find('.day-total-cell span'); $(`#${key}`).remove(); expect(dayTotalSpan.text()).toBe(''); }); - test('Should update when day has ended', () => + test('Should update when day has ended', async() => { const flexibleStore = new Store({name: 'flexible-store'}); const newDate = new Date(); @@ -413,6 +451,7 @@ describe('BaseCalendar.js', () => $(`#${key}`).append(''); $(`#${key}`).append(''); const calendar = new ExtendedClass(getUserPreferences(), {}); + await calendar.initializeStores(); calendar._setStore(key, ['08:00', '16:30']); calendar._updateDayTotal(key); const dayTotalSpan = $('#' + key).parent().find('.day-total-cell span'); diff --git a/__tests__/__renderer__/classes/CalendarFactory.js b/__tests__/__renderer__/classes/CalendarFactory.js index 229576a4f..895734e4a 100644 --- a/__tests__/__renderer__/classes/CalendarFactory.js +++ b/__tests__/__renderer__/classes/CalendarFactory.js @@ -1,12 +1,19 @@ -import { CalendarFactory } from '../../../js/classes/CalendarFactory.js'; -import { FlexibleDayCalendar } from '../../../js/classes/FlexibleDayCalendar.js'; -import { FlexibleMonthCalendar } from '../../../js/classes/FlexibleMonthCalendar.js'; +import { CalendarFactory } from '../../../renderer/classes/CalendarFactory.js'; +import { FlexibleDayCalendar } from '../../../renderer/classes/FlexibleDayCalendar.js'; +import { FlexibleMonthCalendar } from '../../../renderer/classes/FlexibleMonthCalendar.js'; -jest.mock('../../../js/classes/BaseCalendar.js', () => +import { calendarApi } from '../../../renderer/preload-scripts/calendar-api.js'; + +// Mocked APIs from the preload script of the calendar window +window.mainApi = calendarApi; + +jest.mock('../../../renderer/classes/BaseCalendar.js', () => { class BaseCalendar { constructor() { } + + async reload() { } } return { BaseCalendar }; @@ -29,16 +36,21 @@ const { ipcRenderer } = require('electron'); describe('CalendarFactory', () => { - test('Should fail wrong view', () => + test('Should fail wrong view', async() => { - expect(() => CalendarFactory.getInstance({ + const promise = CalendarFactory.getInstance({ view: 'not_supported' - })).toThrow('Could not instantiate not_supported'); + }, {}); + expect(promise).toBeInstanceOf(Promise); + promise.then(() => {}).catch((reason) => + { + expect(reason).toBe('Could not instantiate not_supported'); + }); }); describe('FlexibleDayCalendar', () => { - test('Should fail wrong view', () => + test('Should fail wrong view', async() => { let calls = 0; const testCalendar = { @@ -49,14 +61,14 @@ describe('CalendarFactory', () => updatePreferences: () => { calls++; }, redraw: () => { calls++; }, }; - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'day', }, {}, testCalendar); expect(calendar).toEqual(testCalendar); expect(calls).toBe(3); }); - test('Should return new calendar without resizing', () => + test('Should return new calendar without resizing', async() => { let calls = 0; const testCalendar = { @@ -67,28 +79,28 @@ describe('CalendarFactory', () => updatePreferences: () => { calls++; }, redraw: () => { calls++; }, }; - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'day', }, {}, testCalendar); expect(calendar).toBeInstanceOf(FlexibleDayCalendar); expect(calls).toBe(0); }); - test('Should return new calendar without resizing', () => + test('Should return new calendar without resizing', async() => { let calls = 0; jest.spyOn(ipcRenderer, 'send').mockImplementation(() => { calls++; }); - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'day', }, {}, undefined); expect(calendar).toBeInstanceOf(FlexibleDayCalendar); expect(calls).toBe(0); }); - test('Should return new calendar with resizing', () => + test('Should return new calendar with resizing', async() => { let calls = 0; const testCalendar = { @@ -103,7 +115,7 @@ describe('CalendarFactory', () => { calls++; }); - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'day', }, {}, testCalendar); expect(calendar).toBeInstanceOf(FlexibleDayCalendar); @@ -113,7 +125,7 @@ describe('CalendarFactory', () => describe('FlexibleMonthCalendar', () => { - test('Should fail wrong view', () => + test('Should fail wrong view', async() => { let calls = 0; const testCalendar = { @@ -124,28 +136,28 @@ describe('CalendarFactory', () => updatePreferences: () => { calls++; }, redraw: () => { calls++; }, }; - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'month', }, {}, testCalendar); expect(calendar).toEqual(testCalendar); expect(calls).toBe(3); }); - test('Should return new calendar without resizing', () => + test('Should return new calendar without resizing', async() => { let calls = 0; jest.spyOn(ipcRenderer, 'send').mockImplementation(() => { calls++; }); - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'month', }, {}, undefined); expect(calendar).toBeInstanceOf(FlexibleMonthCalendar); expect(calls).toBe(0); }); - test('Should return new calendar with resizing', () => + test('Should return new calendar with resizing', async() => { let calls = 0; const testCalendar = { @@ -160,7 +172,7 @@ describe('CalendarFactory', () => { calls++; }); - const calendar = CalendarFactory.getInstance({ + const calendar = await CalendarFactory.getInstance({ view: 'month', }, {}, testCalendar); expect(calendar).toBeInstanceOf(FlexibleMonthCalendar); diff --git a/__tests__/__renderer__/classes/FlexibleDayCalendar.js b/__tests__/__renderer__/classes/FlexibleDayCalendar.js index 62d78f55f..9e0fdfd90 100644 --- a/__tests__/__renderer__/classes/FlexibleDayCalendar.js +++ b/__tests__/__renderer__/classes/FlexibleDayCalendar.js @@ -2,7 +2,8 @@ const Store = require('electron-store'); import { defaultPreferences } from '../../../js/user-preferences.js'; -import { CalendarFactory } from '../../../js/classes/CalendarFactory.js'; +import { CalendarFactory } from '../../../renderer/classes/CalendarFactory.js'; +import { calendarApi } from '../../../renderer/preload-scripts/calendar-api.js'; window.$ = window.jQuery = require('jquery'); @@ -18,6 +19,9 @@ window.$.fn.extend({ } }); +// APIs from the preload script of the calendar window +window.mainApi = calendarApi; + jest.mock('../../../renderer/i18n-translator.js', () => ({ translatePage: jest.fn().mockReturnThis(), getTranslationInLanguageData: jest.fn().mockReturnThis() @@ -25,13 +29,32 @@ jest.mock('../../../renderer/i18n-translator.js', () => ({ const languageData = {'language': 'en', 'data': {'dummy_string': 'dummy_string_translated'}}; +const flexibleStore = new Store({name: 'flexible-store'}); +const waivedWorkdays = new Store({name: 'waived-workdays'}); + +window.mainApi.getFlexibleStoreContents = () => { return new Promise((resolve) => { resolve(flexibleStore.store); }); }; +window.mainApi.getWaiverStoreContents = () => { return new Promise((resolve) => resolve(waivedWorkdays.store)); }; +window.mainApi.setFlexibleStoreData = (key, contents) => +{ + return new Promise((resolve) => + { + flexibleStore.set(key, contents); + resolve(true); + }); +}; +window.mainApi.deleteFlexibleStoreData = (key) => +{ + return new Promise((resolve) => + { + flexibleStore.delete(key); + resolve(true); + }); +}; + describe('FlexibleDayCalendar class Tests', () => { process.env.NODE_ENV = 'test'; - const flexibleStore = new Store({name: 'flexible-store'}); - const waivedWorkdays = new Store({name: 'waived-workdays'}); - flexibleStore.clear(); const regularEntries = { '2020-3-1': {'values': ['08:00', '12:00', '13:00', '17:00']}, @@ -51,7 +74,11 @@ describe('FlexibleDayCalendar class Tests', () => const testPreferences = defaultPreferences; testPreferences['view'] = 'day'; - const calendar = CalendarFactory.getInstance(testPreferences, languageData); + let calendar; + beforeAll(() => + { + CalendarFactory.getInstance(testPreferences, languageData).then((_c) => { calendar = _c; }); + }); test('FlexibleDayCalendar starts with today\'s date', () => { @@ -94,7 +121,7 @@ describe('FlexibleDayCalendar class Tests', () => expect(flexibleStore.size).toStrictEqual(2); }); - test('FlexibleDayCalendar internal waiver storage correct loading', () => + test('FlexibleDayCalendar internal waiver storage correct loading', async() => { // Waiver Store internally saves the human month index, but the calendar methods use JS month index expect(calendar._internalWaiverStore['2019-12-31']).toStrictEqual({ reason: 'New Year\'s eve', hours: '08:00' }); @@ -113,7 +140,7 @@ describe('FlexibleDayCalendar class Tests', () => expect(calendar._internalWaiverStore['2010-12-31']).toStrictEqual(undefined); expect(calendar._getWaiverStore(2010, 11, 31)).toStrictEqual(undefined); - calendar.loadInternalWaiveStore(); + await calendar.loadInternalWaiveStore(); expect(Object.keys(calendar._internalWaiverStore).length).toStrictEqual(4); @@ -142,7 +169,7 @@ describe('FlexibleDayCalendar class Tests', () => expect(calendar._getDayTotal(2010, 3, 1)).toStrictEqual(undefined); }); - test('getDayTotal on waived days', () => + test('getDayTotal on waived days', async() => { // Original dates expect(calendar._getDayTotal(2019, 11, 31)).toStrictEqual('08:00'); @@ -158,14 +185,14 @@ describe('FlexibleDayCalendar class Tests', () => }; waivedWorkdays.set(newWaivedEntry); - calendar.loadInternalWaiveStore(); + await calendar.loadInternalWaiveStore(); expect(calendar._getWaiverStore(2010, 2, 1)).toStrictEqual({ reason: 'Test', hours: '06:00' }); expect(calendar._getDayTotal(2010, 2, 1)).toStrictEqual('06:00'); // Clearing entry - back to undefined value waivedWorkdays.clear(); waivedWorkdays.set(waivedEntries); - calendar.loadInternalWaiveStore(); + await calendar.loadInternalWaiveStore(); expect(calendar._getDayTotal(2010, 2, 1)).toStrictEqual(undefined); }); }); @@ -297,15 +324,15 @@ describe('FlexibleDayCalendar class Tests', () => }); }); - test('FlexibleMonthCalendar to FlexibleDayCalendar', () => + test('FlexibleMonthCalendar to FlexibleDayCalendar', async() => { const testPreferences = defaultPreferences; testPreferences['view'] = 'month'; - let calendar = CalendarFactory.getInstance(testPreferences, languageData); + let calendar = await CalendarFactory.getInstance(testPreferences, languageData); expect(calendar.constructor.name).toBe('FlexibleMonthCalendar'); testPreferences['view'] = 'day'; - calendar = CalendarFactory.getInstance(testPreferences, languageData, calendar); + calendar = await CalendarFactory.getInstance(testPreferences, languageData, calendar); expect(calendar.constructor.name).toBe('FlexibleDayCalendar'); }); diff --git a/__tests__/__renderer__/classes/FlexibleMonthCalendar.js b/__tests__/__renderer__/classes/FlexibleMonthCalendar.js index 0b767f98e..2d4e26c26 100644 --- a/__tests__/__renderer__/classes/FlexibleMonthCalendar.js +++ b/__tests__/__renderer__/classes/FlexibleMonthCalendar.js @@ -3,7 +3,8 @@ const Store = require('electron-store'); import { defaultPreferences } from '../../../js/user-preferences.js'; -import { CalendarFactory } from '../../../js/classes/CalendarFactory.js'; +import { CalendarFactory } from '../../../renderer/classes/CalendarFactory.js'; +import { calendarApi } from '../../../renderer/preload-scripts/calendar-api.js'; window.$ = window.jQuery = require('jquery'); @@ -19,6 +20,9 @@ window.$.fn.extend({ } }); +// APIs from the preload script of the calendar window +window.mainApi = calendarApi; + jest.mock('../../../renderer/i18n-translator.js', () => ({ translatePage: jest.fn().mockReturnThis(), getTranslationInLanguageData: jest.fn().mockReturnThis() @@ -26,13 +30,32 @@ jest.mock('../../../renderer/i18n-translator.js', () => ({ const languageData = {'language': 'en', 'data': {'dummy_string': 'dummy_string_translated'}}; +const flexibleStore = new Store({name: 'flexible-store'}); +const waivedWorkdays = new Store({name: 'waived-workdays'}); + +window.mainApi.getFlexibleStoreContents = () => { return new Promise((resolve) => { resolve(flexibleStore.store); }); }; +window.mainApi.getWaiverStoreContents = () => { return new Promise((resolve) => resolve(waivedWorkdays.store)); }; +window.mainApi.setFlexibleStoreData = (key, contents) => +{ + return new Promise((resolve) => + { + flexibleStore.set(key, contents); + resolve(true); + }); +}; +window.mainApi.deleteFlexibleStoreData = (key) => +{ + return new Promise((resolve) => + { + flexibleStore.delete(key); + resolve(true); + }); +}; + describe('FlexibleMonthCalendar class Tests', () => { process.env.NODE_ENV = 'test'; - const flexibleStore = new Store({name: 'flexible-store'}); - const waivedWorkdays = new Store({name: 'waived-workdays'}); - flexibleStore.clear(); const regularEntries = { '2020-3-1': {'values': ['08:00', '12:00', '13:00', '17:00']}, @@ -51,7 +74,11 @@ describe('FlexibleMonthCalendar class Tests', () => const today = new Date(); const testPreferences = defaultPreferences; - const calendar = CalendarFactory.getInstance(testPreferences, languageData); + let calendar; + beforeAll(async() => + { + calendar = await CalendarFactory.getInstance(testPreferences, languageData); + }); test('FlexibleMonthCalendar starts with today\'s date', () => { @@ -94,7 +121,7 @@ describe('FlexibleMonthCalendar class Tests', () => expect(flexibleStore.size).toStrictEqual(2); }); - test('FlexibleMonthCalendar internal waiver storage correct loading', () => + test('FlexibleMonthCalendar internal waiver storage correct loading', async() => { // Waiver Store internally saves the human month index, but the calendar methods use JS month index expect(calendar._internalWaiverStore['2019-12-31']).toStrictEqual({ reason: 'New Year\'s eve', hours: '08:00' }); @@ -113,7 +140,7 @@ describe('FlexibleMonthCalendar class Tests', () => expect(calendar._internalWaiverStore['2010-12-31']).toStrictEqual(undefined); expect(calendar._getWaiverStore(2010, 11, 31)).toStrictEqual(undefined); - calendar.loadInternalWaiveStore(); + await calendar.loadInternalWaiveStore(); expect(Object.keys(calendar._internalWaiverStore).length).toStrictEqual(4); @@ -197,15 +224,15 @@ describe('FlexibleMonthCalendar class Tests', () => }); }); - test('FlexibleDayCalendar to FlexibleMonthCalendar', () => + test('FlexibleDayCalendar to FlexibleMonthCalendar', async() => { const testPreferences = defaultPreferences; testPreferences['view'] = 'day'; - let calendar = CalendarFactory.getInstance(testPreferences, languageData); + let calendar = await CalendarFactory.getInstance(testPreferences, languageData); expect(calendar.constructor.name).toBe('FlexibleDayCalendar'); testPreferences['view'] = 'month'; - calendar = CalendarFactory.getInstance(testPreferences, languageData, calendar); + calendar = await CalendarFactory.getInstance(testPreferences, languageData, calendar); expect(calendar.constructor.name).toBe('FlexibleMonthCalendar'); }); }); diff --git a/__tests__/__renderer__/workday-waiver-aux.js b/__tests__/__renderer__/workday-waiver-aux.js index 285023d0e..18c790907 100644 --- a/__tests__/__renderer__/workday-waiver-aux.js +++ b/__tests__/__renderer__/workday-waiver-aux.js @@ -3,6 +3,12 @@ import { formatDayId, displayWaiverWindow } from '../../renderer/workday-waiver-aux.js'; +// Mocking call +// TODO: find a better way to mock this or even really test it +window.mainApi = { + displayWaiverWindow: () => {} +}; + describe('Workday Waiver Aux', function() { process.env.NODE_ENV = 'test'; diff --git a/renderer/classes/BaseCalendar.js b/renderer/classes/BaseCalendar.js index d25237b0f..1c1ed0d67 100644 --- a/renderer/classes/BaseCalendar.js +++ b/renderer/classes/BaseCalendar.js @@ -33,6 +33,15 @@ class BaseCalendar throw Error('Please implement this.'); } + /** + * Loads internal stores. Required to start and used by the factory. + */ + async initializeStores() + { + await this.loadInternalStore(); + await this.loadInternalWaiveStore(); + } + /** * Returns a date object for which the all time balance will be calculated. * If current month, returns the actual day. If not, first day of following month. @@ -145,8 +154,7 @@ class BaseCalendar */ async reload() { - await this.loadInternalStore(); - await this.loadInternalWaiveStore(); + await this.initializeStores(); this.redraw(); } diff --git a/renderer/classes/CalendarFactory.js b/renderer/classes/CalendarFactory.js index 48ca59458..80771de38 100644 --- a/renderer/classes/CalendarFactory.js +++ b/renderer/classes/CalendarFactory.js @@ -10,7 +10,7 @@ class CalendarFactory const view = preferences['view']; if (view !== 'day' && view !== 'month') { - throw new Error(`Could not instantiate ${view}`); + return Promise.reject(`Could not instantiate ${view}`); } const constructorName = view === 'day' ? 'FlexibleDayCalendar': 'FlexibleMonthCalendar';