From 6ec971d4b5d62754ef009885f3819a341a8db50d Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Fri, 12 Jan 2024 23:04:05 -0300 Subject: [PATCH] Trying to migrate update-manager test --- __tests__/__main__/{menus.js => menus.mjs} | 172 ++++++++++----------- js/import-export.mjs | 16 +- js/notification.mjs | 6 +- js/windows.mjs | 13 +- src/configs/i18next.config.mjs | 9 +- 5 files changed, 109 insertions(+), 107 deletions(-) rename __tests__/__main__/{menus.js => menus.mjs} (82%) diff --git a/__tests__/__main__/menus.js b/__tests__/__main__/menus.mjs similarity index 82% rename from __tests__/__main__/menus.js rename to __tests__/__main__/menus.mjs index b2e82f98..13edf9ed 100644 --- a/__tests__/__main__/menus.js +++ b/__tests__/__main__/menus.mjs @@ -1,88 +1,74 @@ 'use strict'; -const { getContextMenuTemplate, getDockMenuTemplate, getEditMenuTemplate, getHelpMenuTemplate, getMainMenuTemplate, getViewMenuTemplate} = require('../../js/menus.js'); +import { createStubInstance, stub } from 'sinon'; -jest.mock('../../src/configs/i18next.config.js', () => ({ - getCurrentTranslation: jest.fn().mockImplementation((key) => key) -})); +import { + getContextMenuTemplate, + getDockMenuTemplate, + getEditMenuTemplate, + getHelpMenuTemplate, + getMainMenuTemplate, + getViewMenuTemplate +} from '../../js/menus.mjs'; -jest.mock('../../js/windows', () => ({ - openWaiverManagerWindow: jest.fn(), - prefWindow: jest.fn(), - getDialogCoordinates: jest.fn() -})); +import { i18nMock } from '../../src/configs/i18next.config.mjs'; +i18nMock.mock('getCurrentTranslation', stub().callsFake((code) => code)); -jest.mock('electron', () => -{ - const originalModule = jest.requireActual('electron'); - return { - __esModule: true, - ...originalModule, +import { windowsMock } from '../../js/windows.mjs'; +windowsMock.mock('openWaiverManagerWindow', stub()); +windowsMock.mock('getDialogCoordinates', stub()); + +import electron from 'electron'; +const { app, BrowserWindow, shell, dialog, clipboard } = electron; + +const electronStub = createStubInstance(electron, + { ipcRenderer: { - ...originalModule.ipcRenderer, - invoke: jest.fn().mockResolvedValueOnce('./').mockResolvedValue('./dummy_file.txt'), + invoke: stub().onFirstCall().returns('./').onSecondCall().returns('./dummy_file.txt'), }, app: { - ...originalModule.app, - quit: jest.fn() + quit: stub() }, BrowserWindow: { - ...originalModule.BrowserWindow, getFocusedWindow: () => { return { - reload: jest.fn() + reload: stub() }; } }, shell: { - ...originalModule.shell, - openExternal: jest.fn() + openExternal: stub() }, dialog: { - ...originalModule.dialog, - showSaveDialogSync: jest.fn(), - showMessageBox: jest.fn(), - showMessageBoxSync: jest.fn(), - showOpenDialogSync: jest.fn() + showSaveDialogSync: stub(), + showMessageBox: stub(), + showMessageBoxSync: stub(), + showOpenDialogSync: stub() }, clipboard: { - ...originalModule.clipboard, - writeText: jest.fn() + writeText: stub() } - }; -}); + } +); -jest.mock('../../js/notification', () => ({ - createNotification: jest.fn().mockImplementation(() => ({ - show: jest.fn() +import { notificationMock } from '../../js/notification.mjs'; +notificationMock.mock('createNotification', stub().callsFake(() => ({ + show: stub() })) -})); +); -jest.mock('../../js/update-manager', () => ({ - checkForUpdates: jest.fn() -})); +import { updateManagerMock } from '../../js/update-manager.mjs'; +updateManagerMock.mock('checkForUpdates', stub()); -jest.mock('../../js/import-export', () => ({ - exportDatabaseToFile: jest.fn(), - importDatabaseFromFile: jest.fn() -})); +import { importExportMock } from '../../js/import-export.mjs'; +importExportMock.mock('exportDatabaseToFile', stub()); +importExportMock.mock('importDatabaseFromFile', stub()); + +import Store from 'electron-store'; +const storeStub = stub(Store, 'constructor'); +const storeClearStub = stub(Store, 'clear'); -jest.mock('electron-store', () => -{ - class Store - { - constructor() { } - clear() { } - } - return Store; -}); - -const updateManager = require('../../js/update-manager'); -const notification = require('../../js/notification'); -const windows = require('../../js/windows'); -const importExport = require('../../js/import-export.js'); -const {app, BrowserWindow, shell, dialog, clipboard} = require('electron'); const ElectronStore = require('electron-store'); describe('menus.js', () => { @@ -90,14 +76,14 @@ describe('menus.js', () => describe('getMainMenuTemplate', () => { - test('Should have 3 options', () => + it('Should have 3 options', () => { expect(getMainMenuTemplate().length).toBe(3); }); getMainMenuTemplate().forEach((menu) => { - test('Should be a separator or valid field', () => + it('Should be a separator or valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -126,7 +112,7 @@ describe('menus.js', () => }); }); - test('Should open waiver window', (done) => + it('Should open waiver window', (done) => { mocks.waiver = jest.spyOn(windows, 'openWaiverManagerWindow').mockImplementationOnce( () => { @@ -135,7 +121,7 @@ describe('menus.js', () => getMainMenuTemplate()[0].click(); }); - test('Should close app', (done) => + it('Should close app', (done) => { mocks.quit = jest.spyOn(app, 'quit').mockImplementationOnce(() => { @@ -147,14 +133,14 @@ describe('menus.js', () => describe('getContextMenuTemplate', () => { - test('Should have 3 options', () => + it('Should have 3 options', () => { expect(getContextMenuTemplate().length).toBe(3); }); getContextMenuTemplate().forEach((menu) => { - test('Should be a valid field', () => + it('Should be a valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -169,7 +155,7 @@ describe('menus.js', () => }); - test('Should quit on click', () => + it('Should quit on click', () => { const mainWindow = { webContents: { @@ -184,7 +170,7 @@ describe('menus.js', () => expect(mocks.createNotificationSpy).toBeCalledTimes(1); }); - test('Should create notification on click', (done) => + it('Should create notification on click', (done) => { const mainWindow = { show: done @@ -192,7 +178,7 @@ describe('menus.js', () => getContextMenuTemplate(mainWindow)[1].click(); }); - test('Should show window on click', (done) => + it('Should show window on click', (done) => { mocks.quit = jest.spyOn(app, 'quit').mockImplementationOnce(() => { @@ -205,14 +191,14 @@ describe('menus.js', () => describe('getDockMenuTemplate', () => { - test('Should have 1 option', () => + it('Should have 1 option', () => { expect(getDockMenuTemplate().length).toBe(1); }); getDockMenuTemplate().forEach((menu) => { - test('Should be a valid field', () => + it('Should be a valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -226,7 +212,7 @@ describe('menus.js', () => }); }); - test('Should create notification on click', (done) => + it('Should create notification on click', (done) => { const mainWindow = { webContents: { @@ -246,14 +232,14 @@ describe('menus.js', () => describe('getViewMenuTemplate', () => { - test('Should have 2 option', () => + it('Should have 2 option', () => { expect(getViewMenuTemplate().length).toBe(2); }); getViewMenuTemplate().forEach((menu) => { - test('Should be a valid field', () => + it('Should be a valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -267,7 +253,7 @@ describe('menus.js', () => }); }); - test('Should reload window', (done) => + it('Should reload window', (done) => { mocks.window = jest.spyOn(BrowserWindow, 'getFocusedWindow').mockImplementation(() => { @@ -280,7 +266,7 @@ describe('menus.js', () => expect(mocks.window).toBeCalledTimes(1); }); - test('Should toggle devtools', (done) => + it('Should toggle devtools', (done) => { mocks.window = jest.spyOn(BrowserWindow, 'getFocusedWindow').mockImplementation(() => { @@ -296,14 +282,14 @@ describe('menus.js', () => describe('getHelpMenuTemplate', () => { - test('Should have 5 option', () => + it('Should have 5 option', () => { expect(getHelpMenuTemplate().length).toBe(5); }); getHelpMenuTemplate().forEach((menu) => { - test('Should be a valid field', () => + it('Should be a valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -324,7 +310,7 @@ describe('menus.js', () => }); }); - test('Should open github', (done) => + it('Should open github', (done) => { mocks.window = jest.spyOn(shell, 'openExternal').mockImplementation((key) => { @@ -334,7 +320,7 @@ describe('menus.js', () => getHelpMenuTemplate()[0].click(); }); - test('Should open github', (done) => + it('Should open github', (done) => { mocks.window = jest.spyOn(updateManager, 'checkForUpdates').mockImplementation((key) => { @@ -344,7 +330,7 @@ describe('menus.js', () => getHelpMenuTemplate()[1].click(); }); - test('Should open feedback', (done) => + it('Should open feedback', (done) => { mocks.window = jest.spyOn(shell, 'openExternal').mockImplementation((key) => { @@ -354,7 +340,7 @@ describe('menus.js', () => getHelpMenuTemplate()[2].click(); }); - test('Should show about message box and writ to clipboard', () => + it('Should show about message box and writ to clipboard', () => { mocks.writeText = jest.spyOn(clipboard, 'writeText').mockImplementation(() => {}); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockResolvedValue({response: 0}); @@ -365,7 +351,7 @@ describe('menus.js', () => expect(mocks.writeText).toHaveBeenCalledTimes(1); }, 1000); }); - test('Should show about message box', () => + it('Should show about message box', () => { mocks.writeText = jest.spyOn(clipboard, 'writeText').mockImplementation(() => {}); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockResolvedValue({response: 1}); @@ -373,7 +359,7 @@ describe('menus.js', () => expect(mocks.showMessageBox).toHaveBeenCalledTimes(1); expect(mocks.writeText).toHaveBeenCalledTimes(0); }); - test('Should show about message box', (done) => + it('Should show about message box', (done) => { mocks.consoleLog = jest.spyOn(console, 'log').mockImplementation(); mocks.writeText = jest.spyOn(clipboard, 'writeText').mockImplementation(() => {}); @@ -393,14 +379,14 @@ describe('menus.js', () => describe('getEditMenuTemplate', () => { - test('Should have 10 options', () => + it('Should have 10 options', () => { expect(getEditMenuTemplate().length).toBe(10); }); getEditMenuTemplate().forEach((menu) => { - test('Should be a separator or valid field', () => + it('Should be a separator or valid field', () => { const tests = [ {field : 'label', type: 'string'}, @@ -436,7 +422,7 @@ describe('menus.js', () => }); }); - test('Should show dialog for exporting db', () => + it('Should show dialog for exporting db', () => { mocks.showSaveDialogSync = jest.spyOn(dialog, 'showSaveDialogSync').mockImplementation(() => true); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockImplementation(() =>{ }); @@ -447,7 +433,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(1); }); - test('Should not show dialog for exporting db', () => + it('Should not show dialog for exporting db', () => { mocks.showSaveDialogSync = jest.spyOn(dialog, 'showSaveDialogSync').mockImplementation(() => false); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockImplementation(() =>{ }); @@ -458,7 +444,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(0); }); - test('Should show dialog for importing db', () => + it('Should show dialog for importing db', () => { expect.assertions(5); const mainWindow = { @@ -483,7 +469,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(1); }); - test('Should show fail dialog for importing db', () => + it('Should show fail dialog for importing db', () => { expect.assertions(5); const mainWindow = { @@ -508,7 +494,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(1); }); - test('Should show fail dialog for importing db', () => + it('Should show fail dialog for importing db', () => { expect.assertions(5); const mainWindow = { @@ -533,7 +519,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(1); }); - test('Should not show dialog for importing db', () => + it('Should not show dialog for importing db', () => { mocks.showOpenDialogSync = jest.spyOn(dialog, 'showOpenDialogSync').mockImplementation(() => false); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockImplementation(() =>{ }); @@ -546,7 +532,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(0); }); - test('Should not show dialog for importing db', () => + it('Should not show dialog for importing db', () => { mocks.showOpenDialogSync = jest.spyOn(dialog, 'showOpenDialogSync').mockImplementation(() => true); mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockImplementation(() =>{ }); @@ -559,7 +545,7 @@ describe('menus.js', () => expect(mocks.export).toHaveBeenCalledTimes(0); }); - test('Should not show dialog for clearing db', () => + it('Should not show dialog for clearing db', () => { mocks.showMessageBox = jest.spyOn(dialog, 'showMessageBox').mockImplementation(() =>{ }); mocks.showMessageBoxSync = jest.spyOn(dialog, 'showMessageBoxSync').mockImplementation(() => 0); @@ -568,7 +554,7 @@ describe('menus.js', () => expect(mocks.showMessageBox).toHaveBeenCalledTimes(0); }); - test('Should not show dialog for clearing db', () => + it('Should not show dialog for clearing db', () => { const mainWindow = { webContents: { diff --git a/js/import-export.mjs b/js/import-export.mjs index cbd7993b..a76e9eee 100644 --- a/js/import-export.mjs +++ b/js/import-export.mjs @@ -6,6 +6,7 @@ import fs from 'fs'; import { generateKey } from './date-db-formatter.mjs'; import { validateTime } from './time-math.mjs'; +import { MockClass } from '../__mocks__/Mock.mjs'; /** * Returns the database (only flexible calendar entries) as an array of: @@ -54,7 +55,7 @@ function _getWaivedEntries() return output; } -function exportDatabaseToFile(filename) +function _exportDatabaseToFile(filename) { let information = _getFlexibleEntries(); information = information.concat(_getWaivedEntries()); @@ -65,7 +66,8 @@ function exportDatabaseToFile(filename) catch (err) { return false; - } return true; + } + return true; } function _validateDate(dateStr) @@ -120,7 +122,7 @@ function mergeOldStoreDataIntoFlexibleStore(flexibleEntry, oldStoreHours) return flexibleEntry; } -function importDatabaseFromFile(filename) +function _importDatabaseFromFile(filename) { const flexibleStore = new Store({name: 'flexible-store'}); const waivedWorkdays = new Store({name: 'waived-workdays'}); @@ -220,9 +222,13 @@ function migrateFixedDbToFlexible() return {'result': true, 'err': ''}; } +// Enable mocking for some methods, export the mocked versions +const mocks = {'exportDatabaseToFile': _exportDatabaseToFile, 'importDatabaseFromFile': _importDatabaseFromFile}; +export const exportDatabaseToFile = (filename) => mocks['exportDatabaseToFile'](filename); +export const importDatabaseFromFile = (filename) => mocks['importDatabaseFromFile'](filename); +export const importExportMock = new MockClass(mocks); + export { - exportDatabaseToFile, - importDatabaseFromFile, migrateFixedDbToFlexible, validEntry, }; diff --git a/js/notification.mjs b/js/notification.mjs index ac35fe74..b604126c 100644 --- a/js/notification.mjs +++ b/js/notification.mjs @@ -17,7 +17,7 @@ const { rootDir } = require('./app-config.cjs'); let dismissToday = null; -function createNotification(msg, actions = []) +function _createNotification(msg, actions = []) { const appPath = process.env.NODE_ENV === 'production' ? `${process.resourcesPath}/app` @@ -126,12 +126,12 @@ function getDismiss() } // Enable mocking for some methods, export the mocked versions -const mocks = {'createLeaveNotification': _createLeaveNotification}; +const mocks = {'createNotification': _createNotification, 'createLeaveNotification': _createLeaveNotification}; +export const createNotification = (msg, actions = []) => mocks['createNotification'](msg, actions); export const createLeaveNotification = (timeToLeave) => mocks['createLeaveNotification'](timeToLeave); export const notificationMock = new MockClass(mocks); export { - createNotification, getDismiss, updateDismiss }; diff --git a/js/windows.mjs b/js/windows.mjs index 1afbea2b..28bc3b17 100644 --- a/js/windows.mjs +++ b/js/windows.mjs @@ -4,6 +4,7 @@ import { BrowserWindow } from 'electron'; import path from 'path'; import { getDateStr } from './date-aux.mjs'; +import { MockClass } from '../__mocks__/Mock.mjs'; // Allow require() import { createRequire } from 'module'; @@ -18,7 +19,7 @@ global.prefWindow = null; global.tray = null; global.contextMenu = null; -function openWaiverManagerWindow(mainWindow, event) +function _openWaiverManagerWindow(mainWindow, event) { if (global.waiverWindow !== null) { @@ -70,7 +71,7 @@ function openWaiverManagerWindow(mainWindow, event) * @param {number} dialogHeight * @param {object} mainWindow */ -function getDialogCoordinates(dialogWidth, dialogHeight, mainWindow) +function _getDialogCoordinates(dialogWidth, dialogHeight, mainWindow) { return { x : Math.round(mainWindow.getBounds().x + mainWindow.getBounds().width/2 - dialogWidth/2), @@ -91,9 +92,13 @@ function getWaiverWindow() return global.waiverWindow; } +// Enable mocking for some methods, export the mocked versions +const mocks = {'openWaiverManagerWindow': _openWaiverManagerWindow, 'getDialogCoordinates': _getDialogCoordinates}; +export const openWaiverManagerWindow = (mainWindow, event) => mocks['openWaiverManagerWindow'](mainWindow, event); +export const getDialogCoordinates = (dialogWidth, dialogHeight, mainWindow) => mocks['getDialogCoordinates'](dialogWidth, dialogHeight, mainWindow); +export const windowsMock = new MockClass(mocks); + export { - getDialogCoordinates, getWaiverWindow, - openWaiverManagerWindow, resetWindowsElements, }; diff --git a/src/configs/i18next.config.mjs b/src/configs/i18next.config.mjs index 57a177b5..d1c99fae 100644 --- a/src/configs/i18next.config.mjs +++ b/src/configs/i18next.config.mjs @@ -5,6 +5,7 @@ import i18nextBackend from 'i18next-node-fs-backend'; import path from 'path'; import { fallbackLng, getLanguagesCodes } from './app.config.mjs'; +import { MockClass } from '../__mocks__/Mock.mjs'; // Allow require() import { createRequire } from 'module'; @@ -97,14 +98,18 @@ ipcMain.handle('GET_LANGUAGE_DATA', () => }; }); -function getCurrentTranslation(code) +function _getCurrentTranslation(code) { return i18n.t(code); } +// Enable mocking for some methods, export the mocked versions +const mocks = {'getCurrentTranslation': _getCurrentTranslation}; +export const getCurrentTranslation = (code) => mocks['getCurrentTranslation'](code); +export const i18nMock = new MockClass(mocks); + export { changeLanguage, - getCurrentTranslation, setLanguageChangedCallback, setupI18n, };