mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 00:55:16 -07:00
fix(updater): handle unsupported macOS app updates
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createUpdateDialogPresenter, type ShowMessageBox } from './update-dialogs';
|
||||
import {
|
||||
createUpdateDialogPresenter,
|
||||
showManualUpdateRequiredDialog,
|
||||
type ShowMessageBox,
|
||||
} from './update-dialogs';
|
||||
|
||||
test('update dialog presenter focuses app before showing macOS dialogs', async () => {
|
||||
const calls: string[] = [];
|
||||
@@ -35,3 +39,26 @@ test('update dialog presenter does not focus app before showing non-macOS dialog
|
||||
|
||||
assert.deepEqual(calls, ['dialog:SubMiner is up to date (v0.14.0)']);
|
||||
});
|
||||
|
||||
test('manual update required dialog explains that automatic install is unavailable', async () => {
|
||||
let shown:
|
||||
| {
|
||||
type?: string;
|
||||
title?: string;
|
||||
message: string;
|
||||
detail?: string;
|
||||
buttons?: string[];
|
||||
}
|
||||
| undefined;
|
||||
const showMessageBox: ShowMessageBox = async (options) => {
|
||||
shown = options;
|
||||
return { response: 0 };
|
||||
};
|
||||
|
||||
await showManualUpdateRequiredDialog(showMessageBox, '0.15.0-beta.1');
|
||||
|
||||
assert.equal(shown?.type, 'warning');
|
||||
assert.equal(shown?.message, 'Manual install required');
|
||||
assert.match(shown?.detail ?? '', /SubMiner v0\.15\.0-beta\.1 is available/);
|
||||
assert.match(shown?.detail ?? '', /cannot install app updates automatically/);
|
||||
});
|
||||
|
||||
@@ -50,6 +50,8 @@ export function createUpdateDialogPresenter(deps: UpdateDialogPresenterDeps) {
|
||||
showUpdateAvailableDialog(showFocusedMessageBox, version),
|
||||
showUpdateFailedDialog: (message: string) =>
|
||||
showUpdateFailedDialog(showFocusedMessageBox, message),
|
||||
showManualUpdateRequiredDialog: (version: string) =>
|
||||
showManualUpdateRequiredDialog(showFocusedMessageBox, version),
|
||||
showRestartDialog: () => showRestartDialog(showFocusedMessageBox),
|
||||
};
|
||||
}
|
||||
@@ -81,6 +83,19 @@ export async function showRestartDialog(showMessageBox: ShowMessageBox): Promise
|
||||
return result.response === 0 ? 'restart' : 'later';
|
||||
}
|
||||
|
||||
export async function showManualUpdateRequiredDialog(
|
||||
showMessageBox: ShowMessageBox,
|
||||
version: string,
|
||||
): Promise<void> {
|
||||
await showMessageBox({
|
||||
type: 'warning',
|
||||
title: 'SubMiner Updates',
|
||||
message: 'Manual install required',
|
||||
detail: `SubMiner v${version} is available, but this build cannot install app updates automatically. Download and install the latest release, then reopen SubMiner.`,
|
||||
buttons: ['Close'],
|
||||
});
|
||||
}
|
||||
|
||||
export async function showUpdateFailedDialog(
|
||||
showMessageBox: ShowMessageBox,
|
||||
message: string,
|
||||
|
||||
@@ -37,6 +37,9 @@ function createDeps(overrides: Partial<UpdateServiceDeps> = {}) {
|
||||
showUpdateFailedDialog: async (message) => {
|
||||
calls.push(`failed:${message}`);
|
||||
},
|
||||
showManualUpdateRequiredDialog: async (version) => {
|
||||
calls.push(`manual-install:${version}`);
|
||||
},
|
||||
downloadAppUpdate: async () => {
|
||||
calls.push('download');
|
||||
},
|
||||
@@ -115,7 +118,44 @@ test('manual update check reports available when no update asset was applied', a
|
||||
const result = await service.checkForUpdates({ source: 'manual' });
|
||||
|
||||
assert.equal(result.status, 'update-available');
|
||||
assert.deepEqual(calls, ['available-dialog:0.15.0', 'launcher:stable']);
|
||||
assert.deepEqual(calls, ['available-dialog:0.15.0', 'launcher:stable', 'manual-install:0.15.0']);
|
||||
});
|
||||
|
||||
test('manual update check does not prompt restart when only launcher updates', async () => {
|
||||
const { deps, calls } = createDeps({
|
||||
checkAppUpdate: async () => ({ available: false, version: '0.14.0', canUpdate: false }),
|
||||
fetchLatestStableRelease: async () => ({
|
||||
tag_name: 'v0.15.0',
|
||||
prerelease: false,
|
||||
draft: false,
|
||||
assets: [],
|
||||
}),
|
||||
showUpdateAvailableDialog: async (version) => {
|
||||
calls.push(`available-dialog:${version}`);
|
||||
return 'update';
|
||||
},
|
||||
updateLauncher: async (_launcherPath, channel) => {
|
||||
calls.push(`launcher:${channel}`);
|
||||
return { status: 'updated' };
|
||||
},
|
||||
showRestartDialog: async () => {
|
||||
calls.push('restart-dialog');
|
||||
return 'restart';
|
||||
},
|
||||
quitAndInstall: () => {
|
||||
calls.push('quit-install');
|
||||
},
|
||||
});
|
||||
const service = createUpdateService(deps);
|
||||
|
||||
const result = await service.checkForUpdates({ source: 'manual' });
|
||||
|
||||
assert.equal(result.status, 'update-available');
|
||||
assert.deepEqual(calls, [
|
||||
'available-dialog:0.15.0',
|
||||
'launcher:stable',
|
||||
'manual-install:0.15.0',
|
||||
]);
|
||||
});
|
||||
|
||||
test('automatic update check skips inside configured interval', async () => {
|
||||
|
||||
@@ -48,6 +48,7 @@ export interface UpdateServiceDeps {
|
||||
showNoUpdateDialog: (version: string) => Promise<void>;
|
||||
showUpdateAvailableDialog: (version: string) => Promise<'update' | 'close'>;
|
||||
showUpdateFailedDialog: (message: string) => Promise<void>;
|
||||
showManualUpdateRequiredDialog: (version: string) => Promise<void>;
|
||||
downloadAppUpdate: () => Promise<void>;
|
||||
showRestartDialog: () => Promise<'restart' | 'later'>;
|
||||
quitAndInstall: () => void | Promise<void>;
|
||||
@@ -158,8 +159,9 @@ export function createUpdateService(deps: UpdateServiceDeps) {
|
||||
return { status: 'update-available', version: latest.version };
|
||||
}
|
||||
|
||||
const canInstallAppUpdate = appUpdate.available && appUpdate.canUpdate !== false;
|
||||
let appUpdateApplied = false;
|
||||
if (appUpdate.available && appUpdate.canUpdate !== false) {
|
||||
if (canInstallAppUpdate) {
|
||||
await deps.downloadAppUpdate();
|
||||
appUpdateApplied = true;
|
||||
}
|
||||
@@ -168,8 +170,8 @@ export function createUpdateService(deps: UpdateServiceDeps) {
|
||||
deps.log(`Launcher update requires manual command: ${launcherResult.command}`);
|
||||
}
|
||||
|
||||
const launcherUpdateApplied = launcherResult.status === 'updated';
|
||||
if (!appUpdateApplied && !launcherUpdateApplied) {
|
||||
if (!appUpdateApplied) {
|
||||
await deps.showManualUpdateRequiredDialog(latest.version);
|
||||
return { status: 'update-available', version: latest.version };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user