mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 09:19:34 +05:30
feat(updater): electron-updater wiring + IPC bridge
electron-updater integration so users get fixes automatically:
- new dependency electron-updater@^6.6.2 in package.json
- electron-builder.config.js publishes to GitHub releases
(owner: concreteinfo, repo: markdownconverter)
- new src/main/auto-updater.js wraps autoUpdater: wires the six
lifecycle events to a 'updates:status' IPC channel, exposes
check() and install() helpers, dev-gates via isDev(), and
swallows the 'missing app-update.yml' error that dev runs hit
- main.js: ensureAutoUpdater() forwards status to the renderer
via mainWindow.webContents.send; ipcMain handlers for
'updates:check' (invoke) and 'updates:install' (invoke)
- preload.js: 'updates:check' / 'updates:install' added to
ALLOWED_SEND_CHANNELS; 'updates:status' added to receive
channels; electronAPI.updates.{check, install, onStatus}
exposed
7 new tests cover event registration, dev-gate behaviour,
'not-available' fallback for missing app-update.yml, typed event
payloads, error forwarding, and install() quitAndInstall.
Amit Haridas
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @jest-environment node
|
||||
*
|
||||
* Auto-updater — unit test the controller without bringing up electron.
|
||||
* The electron-updater module is mocked because the real one requires the
|
||||
* Electron app to be initialised.
|
||||
*/
|
||||
|
||||
const mockAutoUpdater = {
|
||||
on: jest.fn(),
|
||||
autoDownload: false,
|
||||
autoInstallOnAppQuit: false,
|
||||
checkForUpdates: jest.fn().mockResolvedValue(null),
|
||||
quitAndInstall: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('electron-updater', () => ({ autoUpdater: mockAutoUpdater }), { virtual: true });
|
||||
|
||||
const { setupAutoUpdater } = require('../src/main/auto-updater');
|
||||
|
||||
describe('setupAutoUpdater', () => {
|
||||
let send;
|
||||
let updater;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockAutoUpdater.on.mockReset();
|
||||
send = jest.fn();
|
||||
updater = setupAutoUpdater({ send });
|
||||
});
|
||||
|
||||
test('registers all six event handlers', () => {
|
||||
const events = mockAutoUpdater.on.mock.calls.map((c) => c[0]);
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
'checking-for-update',
|
||||
'update-available',
|
||||
'update-not-available',
|
||||
'download-progress',
|
||||
'update-downloaded',
|
||||
'error',
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('enables autoDownload and autoInstallOnAppQuit', () => {
|
||||
expect(mockAutoUpdater.autoDownload).toBe(true);
|
||||
expect(mockAutoUpdater.autoInstallOnAppQuit).toBe(true);
|
||||
});
|
||||
|
||||
test('check() forwards "not-available" when app-update.yml is missing (dev)', async () => {
|
||||
mockAutoUpdater.checkForUpdates.mockRejectedValueOnce(
|
||||
new Error('Cannot find any update manifest (app-update.yml) in resources')
|
||||
);
|
||||
await updater.check();
|
||||
expect(send).toHaveBeenCalledWith('updates:status', { state: 'not-available' });
|
||||
});
|
||||
|
||||
test('check() forwards "error" for non-benign failures', async () => {
|
||||
mockAutoUpdater.checkForUpdates.mockRejectedValueOnce(new Error('network down'));
|
||||
await updater.check();
|
||||
expect(send).toHaveBeenCalledWith('updates:status', {
|
||||
state: 'error',
|
||||
message: 'network down',
|
||||
});
|
||||
});
|
||||
|
||||
test('check() respects isDev() and does not invoke autoUpdater', async () => {
|
||||
const isDev = jest.fn(() => true);
|
||||
const u2 = setupAutoUpdater({ send, isDev });
|
||||
await u2.check();
|
||||
expect(isDev).toHaveBeenCalled();
|
||||
expect(mockAutoUpdater.checkForUpdates).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('install() calls quitAndInstall', () => {
|
||||
updater.install();
|
||||
expect(mockAutoUpdater.quitAndInstall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('forwarded events carry typed payloads', () => {
|
||||
// Find each handler and invoke it; assert what got sent.
|
||||
const map = new Map();
|
||||
for (const [event, cb] of mockAutoUpdater.on.mock.calls) map.set(event, cb);
|
||||
|
||||
send.mockClear();
|
||||
map.get('checking-for-update')();
|
||||
expect(send).toHaveBeenLastCalledWith('updates:status', { state: 'checking' });
|
||||
|
||||
map.get('update-available')({ version: '4.13.0' });
|
||||
expect(send).toHaveBeenLastCalledWith('updates:status', {
|
||||
state: 'available',
|
||||
version: '4.13.0',
|
||||
});
|
||||
|
||||
map.get('download-progress')({ percent: 42.7 });
|
||||
expect(send).toHaveBeenLastCalledWith('updates:status', {
|
||||
state: 'downloading',
|
||||
percent: 43,
|
||||
});
|
||||
|
||||
map.get('update-downloaded')({ version: '4.13.0' });
|
||||
expect(send).toHaveBeenLastCalledWith('updates:status', {
|
||||
state: 'downloaded',
|
||||
version: '4.13.0',
|
||||
});
|
||||
|
||||
map.get('error')(new Error('boom'));
|
||||
expect(send).toHaveBeenLastCalledWith('updates:status', {
|
||||
state: 'error',
|
||||
message: 'boom',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user