diff --git a/src/behaviours/update-app/installing-update-using-tray.test.ts b/src/behaviours/update-app/installing-update-using-tray.test.ts index ffdb22ecfd..e0de507abc 100644 --- a/src/behaviours/update-app/installing-update-using-tray.test.ts +++ b/src/behaviours/update-app/installing-update-using-tray.test.ts @@ -8,8 +8,8 @@ import quitAndInstallUpdateInjectable from "../../main/electron-app/features/qui import type { RenderResult } from "@testing-library/react"; import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable"; import publishIsConfiguredInjectable from "../../main/update-app/publish-is-configured.injectable"; -import type { CheckForPlatformUpdates } from "../../main/update-app/check-for-platform-updates.injectable"; -import checkForPlatformUpdatesInjectable from "../../main/update-app/check-for-platform-updates.injectable"; +import type { CheckForPlatformUpdates } from "../../main/update-app/check-for-platform-updates/check-for-platform-updates.injectable"; +import checkForPlatformUpdatesInjectable from "../../main/update-app/check-for-platform-updates/check-for-platform-updates.injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; import type { UpdateChannel, UpdateChannelId } from "../../main/update-app/update-channels"; diff --git a/src/main/getDiForUnitTesting.ts b/src/main/getDiForUnitTesting.ts index 74e00db084..4ac2e19b8e 100644 --- a/src/main/getDiForUnitTesting.ts +++ b/src/main/getDiForUnitTesting.ts @@ -79,7 +79,7 @@ import productNameInjectable from "./app-paths/app-name/product-name.injectable" import quitAndInstallUpdateInjectable from "./electron-app/features/quit-and-install-update.injectable"; import electronUpdaterIsActiveInjectable from "./electron-app/features/electron-updater-is-active.injectable"; import publishIsConfiguredInjectable from "./update-app/publish-is-configured.injectable"; -import checkForPlatformUpdatesInjectable from "./update-app/check-for-platform-updates.injectable"; +import checkForPlatformUpdatesInjectable from "./update-app/check-for-platform-updates/check-for-platform-updates.injectable"; import setUpdateOnQuitInjectable from "./electron-app/features/set-update-on-quit.injectable"; export function getDiForUnitTesting(opts: GetDiForUnitTestingOptions = {}) { diff --git a/src/main/update-app/check-for-platform-updates.injectable.ts b/src/main/update-app/check-for-platform-updates.injectable.ts deleted file mode 100644 index e3fa1386e9..0000000000 --- a/src/main/update-app/check-for-platform-updates.injectable.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import electronUpdaterInjectable from "../electron-app/features/electron-updater.injectable"; -import type { UpdateChannel } from "./update-channels"; - -export type CheckForPlatformUpdates = (updateChannel: UpdateChannel) => Promise<{ updateWasDiscovered: boolean; version?: string }>; - -const checkForPlatformUpdatesInjectable = getInjectable({ - id: "check-for-platform-updates", - - instantiate: (di): CheckForPlatformUpdates => { - const electronUpdater = di.inject(electronUpdaterInjectable); - - return async (updateChannel) => { - electronUpdater.channel = updateChannel.id; - - await electronUpdater.checkForUpdates(); - - return { - updateWasDiscovered: true, - version: "42", - }; - }; - }, -}); - -export default checkForPlatformUpdatesInjectable; diff --git a/src/main/update-app/check-for-platform-updates/check-for-platform-updates.injectable.ts b/src/main/update-app/check-for-platform-updates/check-for-platform-updates.injectable.ts new file mode 100644 index 0000000000..a22be24a1e --- /dev/null +++ b/src/main/update-app/check-for-platform-updates/check-for-platform-updates.injectable.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import electronUpdaterInjectable from "../../electron-app/features/electron-updater.injectable"; +import type { UpdateChannel } from "../update-channels"; +import loggerInjectable from "../../../common/logger.injectable"; +import type { UpdateCheckResult } from "electron-updater"; + +export type CheckForPlatformUpdates = (updateChannel: UpdateChannel) => Promise<{ updateWasDiscovered: boolean; version?: string }>; + +const checkForPlatformUpdatesInjectable = getInjectable({ + id: "check-for-platform-updates", + + instantiate: (di): CheckForPlatformUpdates => { + const electronUpdater = di.inject(electronUpdaterInjectable); + const logger = di.inject(loggerInjectable); + + return async (updateChannel) => { + electronUpdater.channel = updateChannel.id; + electronUpdater.autoDownload = false; + + let result: UpdateCheckResult; + + try { + result = await electronUpdater.checkForUpdates(); + } catch (error) { + logger.error("[UPDATE-APP/CHECK-FOR-UPDATES]", error); + + return { + updateWasDiscovered: false, + }; + } + + const { updateInfo, cancellationToken } = result; + + if (!cancellationToken) { + return { + updateWasDiscovered: false, + }; + } + + return { + updateWasDiscovered: true, + version: updateInfo.version, + }; + }; + }, +}); + +export default checkForPlatformUpdatesInjectable; diff --git a/src/main/update-app/check-for-platform-updates/check-for-platform-updates.test.ts b/src/main/update-app/check-for-platform-updates/check-for-platform-updates.test.ts new file mode 100644 index 0000000000..8dd51c7a98 --- /dev/null +++ b/src/main/update-app/check-for-platform-updates/check-for-platform-updates.test.ts @@ -0,0 +1,123 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getDiForUnitTesting } from "../../getDiForUnitTesting"; +import electronUpdaterInjectable from "../../electron-app/features/electron-updater.injectable"; +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; +import type { AppUpdater, UpdateCheckResult } from "electron-updater"; +import type { CheckForPlatformUpdates } from "./check-for-platform-updates.injectable"; +import checkForPlatformUpdatesInjectable from "./check-for-platform-updates.injectable"; +import type { UpdateChannel, UpdateChannelId } from "../update-channels"; +import { getPromiseStatus } from "../../../common/test-utils/get-promise-status"; +import loggerInjectable from "../../../common/logger.injectable"; +import type { Logger } from "../../../common/logger"; + +describe("check-for-platform-updates", () => { + let checkForPlatformUpdates: CheckForPlatformUpdates; + let electronUpdaterFake: AppUpdater; + let checkForUpdatesMock: AsyncFnMock<() => UpdateCheckResult>; + let logErrorMock: jest.Mock; + + beforeEach(() => { + const di = getDiForUnitTesting(); + + checkForUpdatesMock = asyncFn(); + + electronUpdaterFake = { + channel: undefined, + autoDownload: undefined, + + checkForUpdates: checkForUpdatesMock, + } as unknown as AppUpdater; + + di.override(electronUpdaterInjectable, () => electronUpdaterFake); + + logErrorMock = jest.fn(); + + di.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger); + + checkForPlatformUpdates = di.inject(checkForPlatformUpdatesInjectable); + }); + + describe("when called", () => { + let actualPromise: Promise; + + beforeEach(() => { + const testUpdateChannel: UpdateChannel = { + id: "some-update-channel" as UpdateChannelId, + label: "Some update channel", + moreStableUpdateChannel: null, + }; + + actualPromise = checkForPlatformUpdates(testUpdateChannel); + }); + + it("sets update channel", () => { + expect(electronUpdaterFake.channel).toBe("some-update-channel"); + }); + + it("disables auto downloading for being controlled", () => { + expect(electronUpdaterFake.autoDownload).toBe(false); + }); + + it("checks for updates", () => { + expect(checkForUpdatesMock).toHaveBeenCalled(); + }); + + it("does not resolve yet", async () => { + const promiseStatus = await getPromiseStatus(actualPromise); + + expect(promiseStatus.fulfilled).toBe(false); + }); + + it("when checking for updates resolves with update, resolves with the discovered update", async () => { + await checkForUpdatesMock.resolve({ + updateInfo: { + version: "some-version", + }, + + cancellationToken: "some-cancellation-token", + } as unknown as UpdateCheckResult); + + const actual = await actualPromise; + + expect(actual).toEqual({ updateWasDiscovered: true, version: "some-version" }); + }); + + it("when checking for updates resolves without update, resolves with update not being discovered", async () => { + await checkForUpdatesMock.resolve({ + updateInfo: { + version: "some-version-that-matches-to-current-installed-version", + }, + + cancellationToken: null, + } as unknown as UpdateCheckResult); + + const actual = await actualPromise; + + expect(actual).toEqual({ updateWasDiscovered: false }); + }); + + describe("when checking for updates rejects", () => { + let errorStub: Error; + + beforeEach(() => { + errorStub = new Error("Some error"); + + checkForUpdatesMock.reject(errorStub); + }); + + it("logs errors", () => { + expect(logErrorMock).toHaveBeenCalledWith("[UPDATE-APP/CHECK-FOR-UPDATES]", errorStub); + }); + + it("resolves with update not being discovered", async () => { + const actual = await actualPromise; + + expect(actual).toEqual({ updateWasDiscovered: false }); + }); + }); + }); +}); diff --git a/src/main/update-app/version-update.injectable.ts b/src/main/update-app/version-update.injectable.ts index e8e2345d6a..4589696edc 100644 --- a/src/main/update-app/version-update.injectable.ts +++ b/src/main/update-app/version-update.injectable.ts @@ -7,8 +7,8 @@ import type { IComputedValue, IObservableValue } from "mobx"; import { computed, observable, runInAction } from "mobx"; import selectedUpdateChannelInjectable from "./selected-update-channel.injectable"; import downloadPlatformUpdateInjectable from "./download-platform-update.injectable"; -import type { CheckForPlatformUpdates } from "./check-for-platform-updates.injectable"; -import checkForPlatformUpdatesInjectable from "./check-for-platform-updates.injectable"; +import type { CheckForPlatformUpdates } from "./check-for-platform-updates/check-for-platform-updates.injectable"; +import checkForPlatformUpdatesInjectable from "./check-for-platform-updates/check-for-platform-updates.injectable"; import type { UpdateChannel } from "./update-channels"; import showNotificationInjectable from "../show-notification/show-notification.injectable";