mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
feat(electron): download updates silently
Start stable desktop update downloads in the background during automatic checks, then prompt only after the update is ready to install. Keep manual update checks interactive so users still confirm the download after explicitly checking.
This commit is contained in:
1 parent
f74aae1bb4
commit
ef71543237
2 files changed
+158
-9
No files matched your search
@@ -0,0 +1,131 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { mock, test } from 'node:test'
|
||||
|
||||
class FakeAutoUpdater extends EventEmitter {
|
||||
autoDownload = false
|
||||
autoInstallOnAppQuit = true
|
||||
downloadCalls = 0
|
||||
checkCalls = 0
|
||||
quitInstallCalls = 0
|
||||
feedUrls: unknown[] = []
|
||||
|
||||
setFeedURL(url: unknown): void {
|
||||
this.feedUrls.push(url)
|
||||
}
|
||||
|
||||
async checkForUpdates(): Promise<void> {
|
||||
this.checkCalls++
|
||||
}
|
||||
|
||||
async downloadUpdate(): Promise<void> {
|
||||
this.downloadCalls++
|
||||
}
|
||||
|
||||
quitAndInstall(): void {
|
||||
this.quitInstallCalls++
|
||||
}
|
||||
}
|
||||
|
||||
type DialogCall = {
|
||||
title?: string
|
||||
message?: string
|
||||
detail?: string
|
||||
buttons?: string[]
|
||||
}
|
||||
|
||||
async function loadUpdaterModule() {
|
||||
const autoUpdater = new FakeAutoUpdater()
|
||||
const dialogCalls: DialogCall[] = []
|
||||
const logMessages: string[] = []
|
||||
|
||||
await mock.module('electron', {
|
||||
namedExports: {
|
||||
app: {
|
||||
isPackaged: true,
|
||||
},
|
||||
dialog: {
|
||||
async showMessageBox(options: DialogCall) {
|
||||
dialogCalls.push(options)
|
||||
return { response: 1 }
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
await mock.module('electron-updater', {
|
||||
namedExports: { autoUpdater },
|
||||
})
|
||||
await mock.module('@electron-toolkit/utils', {
|
||||
namedExports: { platform: { isWindows: false } },
|
||||
})
|
||||
await mock.module('./logger', {
|
||||
namedExports: {
|
||||
logger: {
|
||||
info(message: string) {
|
||||
logMessages.push(message)
|
||||
},
|
||||
error(message: string) {
|
||||
logMessages.push(message)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
await mock.module('./network/proxy', {
|
||||
namedExports: {
|
||||
getActiveProxyUrl: () => undefined,
|
||||
},
|
||||
})
|
||||
await mock.module('./worker/workerManager', {
|
||||
namedExports: {
|
||||
closeWorkerAsync: async () => undefined,
|
||||
},
|
||||
})
|
||||
await mock.module('./i18n', {
|
||||
namedExports: {
|
||||
t: (key: string, params?: Record<string, string>) => `${key}${params?.version ? `:${params.version}` : ''}`,
|
||||
},
|
||||
})
|
||||
|
||||
const mod = await import('./update.js')
|
||||
return {
|
||||
autoUpdater,
|
||||
dialogCalls,
|
||||
checkUpdate: mod.checkUpdate as (win: { webContents: { send: (...args: unknown[]) => void } }) => void,
|
||||
manualCheckForUpdates: mod.manualCheckForUpdates as () => void,
|
||||
}
|
||||
}
|
||||
|
||||
test('automatic stable updates download silently before showing install prompt', async () => {
|
||||
const { autoUpdater, dialogCalls, checkUpdate, manualCheckForUpdates } = await loadUpdaterModule()
|
||||
const sent: unknown[][] = []
|
||||
|
||||
checkUpdate({
|
||||
webContents: {
|
||||
send: (...args: unknown[]) => sent.push(args),
|
||||
},
|
||||
})
|
||||
|
||||
autoUpdater.emit('update-available', { version: '0.28.2' })
|
||||
await Promise.resolve()
|
||||
|
||||
assert.equal(autoUpdater.downloadCalls, 1)
|
||||
assert.equal(dialogCalls.length, 0)
|
||||
assert.equal(autoUpdater.autoDownload, false)
|
||||
assert.equal(autoUpdater.autoInstallOnAppQuit, false)
|
||||
|
||||
autoUpdater.emit('update-downloaded', { version: '0.28.2' })
|
||||
await Promise.resolve()
|
||||
|
||||
assert.equal(dialogCalls.length, 1)
|
||||
assert.equal(dialogCalls[0]?.title, 'update.downloadComplete')
|
||||
assert.equal(dialogCalls[0]?.message, 'update.readyToInstall')
|
||||
|
||||
manualCheckForUpdates()
|
||||
autoUpdater.emit('update-available', { version: '0.28.3' })
|
||||
await Promise.resolve()
|
||||
|
||||
assert.equal(dialogCalls.length, 2)
|
||||
assert.equal(dialogCalls[1]?.title, 'update.newVersionTitle:0.28.3')
|
||||
assert.equal(dialogCalls[1]?.message, 'update.newVersionMessage:0.28.3')
|
||||
assert.equal(autoUpdater.downloadCalls, 1)
|
||||
})
|
||||
@@ -129,6 +129,26 @@ const checkUpdate = (win) => {
|
||||
// }
|
||||
|
||||
let showUpdateMessageBox = false
|
||||
let isDownloadingUpdate = false
|
||||
|
||||
// 自动检查走静默下载;手动检查仍由用户确认后再下载。
|
||||
const startDownloadUpdate = (): void => {
|
||||
if (isDownloadingUpdate) return
|
||||
isDownloadingUpdate = true
|
||||
autoUpdater
|
||||
.downloadUpdate()
|
||||
.then(() => {
|
||||
console.log('wait for post download operation')
|
||||
})
|
||||
.catch((downloadError) => {
|
||||
// 下载失败记录到日志,不显示给用户
|
||||
logger.error(`[Update] Download update failed: ${downloadError}`)
|
||||
})
|
||||
.finally(() => {
|
||||
isDownloadingUpdate = false
|
||||
})
|
||||
}
|
||||
|
||||
autoUpdater.on('update-available', (info) => {
|
||||
// win.webContents.send('show-message', 'electron:发现新版本')
|
||||
if (showUpdateMessageBox) return
|
||||
@@ -145,6 +165,12 @@ const checkUpdate = (win) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isManualCheck) {
|
||||
logger.info(`[Update] New version ${info.version} found, downloading silently`)
|
||||
startDownloadUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
showUpdateMessageBox = true
|
||||
|
||||
dialog
|
||||
@@ -161,15 +187,7 @@ const checkUpdate = (win) => {
|
||||
.then((result) => {
|
||||
showUpdateMessageBox = false
|
||||
if (result.response === 0) {
|
||||
autoUpdater
|
||||
.downloadUpdate()
|
||||
.then(() => {
|
||||
console.log('wait for post download operation')
|
||||
})
|
||||
.catch((downloadError) => {
|
||||
// 下载失败记录到日志,不显示给用户
|
||||
logger.error(`[Update] Download update failed: ${downloadError}`)
|
||||
})
|
||||
startDownloadUpdate()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user