diff --git a/electron/auto-updater.test.ts b/electron/auto-updater.test.ts index 3f60a2ec2..a92b700d7 100644 --- a/electron/auto-updater.test.ts +++ b/electron/auto-updater.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { blockedFromInstalling, checkForSelfUpdate, @@ -148,11 +148,23 @@ describe("self-update flow", () => { expect(result).toMatchObject({ error: { message: "connection reset" } }); }); - // isSilent=false so a per-machine Windows install can show its UAC prompt — a silent upgrade - // of a Program Files install hits elevation and, if dismissed, quits having done nothing. - // isForceRunAfter=true so the app comes back. - it("hands over to the installer non-silently and relaunches", async () => { - await installSelfUpdate(); - expect(mocks.autoUpdater.quitAndInstall).toHaveBeenCalledWith(false, true); + describe("installSelfUpdate", () => { + const REAL_PLATFORM = process.platform; + const setPlatform = (value: NodeJS.Platform) => + Object.defineProperty(process, "platform", { value, configurable: true }); + afterEach(() => setPlatform(REAL_PLATFORM)); + + // Without /S the assisted NSIS installer opens on its install-mode page (#1437). + it("runs the Windows installer silently and relaunches", async () => { + setPlatform("win32"); + await installSelfUpdate(); + expect(mocks.autoUpdater.quitAndInstall).toHaveBeenCalledWith(true, true); + }); + + it.each(["darwin", "linux"] as const)("leaves %s non-silent", async (platform) => { + setPlatform(platform); + await installSelfUpdate(); + expect(mocks.autoUpdater.quitAndInstall).toHaveBeenCalledWith(false, true); + }); }); }); diff --git a/electron/auto-updater.ts b/electron/auto-updater.ts index fdee80d2b..39853d042 100644 --- a/electron/auto-updater.ts +++ b/electron/auto-updater.ts @@ -85,8 +85,10 @@ export async function downloadSelfUpdate(): Promise { /** Quit and hand over to the installer. Callers MUST have checked `blockedFromInstalling`. */ export async function installSelfUpdate(): Promise { const autoUpdater = await getUpdater(); - // isSilent=false so a per-machine Windows install can show its elevation prompt: a silent - // upgrade of a Program Files install hits UAC and, if the user dismisses it, quits having - // done nothing. isForceRunAfter=true so the app comes back up. - autoUpdater.quitAndInstall(false, true); + // Silent on Windows: our NSIS installer is assisted (`oneClick: false`), so without /S it + // shows its install-mode page and lets the user pick the copy to update — the wrong one when + // a per-user and a per-machine install coexist (#1437). Silent, it updates the per-machine + // install whenever there is one, elevating through UAC itself. The flag means nothing to the + // macOS and Linux updaters. isForceRunAfter=true so the app comes back up. + autoUpdater.quitAndInstall(process.platform === "win32", true); }