import { assert, describe, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Ref from "effect/Ref"; import type * as Electron from "electron"; import * as ElectronApp from "../electron/ElectronApp.ts"; import * as ElectronTheme from "../electron/ElectronTheme.ts"; import * as DesktopEnvironment from "./DesktopEnvironment.ts"; import * as DesktopLifecycle from "./DesktopLifecycle.ts"; import * as DesktopShutdown from "./DesktopShutdown.ts"; import * as DesktopState from "./DesktopState.ts"; import * as DesktopWindow from "../window/DesktopWindow.ts"; describe("DesktopLifecycle", () => { for (const platform of ["darwin", "win32", "linux"] satisfies ReadonlyArray) { it.effect(`lets the updater's quit event proceed on ${platform}`, () => { const appListeners = new Map void>(); const electronAppLayer = Layer.succeed(ElectronApp.ElectronApp, { metadata: Effect.die("unexpected metadata read"), name: Effect.succeed("T3 Code"), whenReady: Effect.void, quit: Effect.void, exit: () => Effect.void, relaunch: () => Effect.void, setPath: () => Effect.void, setName: () => Effect.void, setAboutPanelOptions: () => Effect.void, setAppUserModelId: () => Effect.void, getAppMetrics: Effect.succeed([]), isDefaultProtocolClient: () => Effect.succeed(false), setAsDefaultProtocolClient: () => Effect.succeed(true), setDesktopName: () => Effect.void, setDockIcon: () => Effect.void, appendCommandLineSwitch: () => Effect.void, removeCommandLineSwitch: () => Effect.void, onBeforeQuitForUpdate: (listener) => Effect.acquireRelease( Effect.sync(() => { appListeners.set("before-quit-for-update", listener); }), () => Effect.sync(() => { appListeners.delete("before-quit-for-update"); }), ).pipe(Effect.asVoid), on: (eventName, listener) => Effect.acquireRelease( Effect.sync(() => { appListeners.set( eventName, listener as unknown as (...args: readonly unknown[]) => void, ); }), () => Effect.sync(() => { appListeners.delete(eventName); }), ).pipe(Effect.asVoid), } satisfies ElectronApp.ElectronApp["Service"]); const electronThemeLayer = Layer.succeed(ElectronTheme.ElectronTheme, { shouldUseDarkColors: Effect.succeed(false), setSource: () => Effect.void, onUpdated: () => Effect.void, }); const desktopWindowLayer = Layer.succeed(DesktopWindow.DesktopWindow, { createMain: Effect.die("unexpected window creation"), ensureMain: Effect.die("unexpected window creation"), revealOrCreateMain: Effect.die("unexpected window creation"), activate: Effect.void, createMainIfBackendReady: Effect.void, showConnectingSplash: Effect.void, handleBackendReady: () => Effect.void, handleBackendNotReady: Effect.void, flushMainWindowBounds: Effect.void, dispatchMenuAction: () => Effect.void, syncAppearance: Effect.void, }); const environmentLayer = Layer.succeed(DesktopEnvironment.DesktopEnvironment, { platform, isDevelopment: false, } as DesktopEnvironment.DesktopEnvironment["Service"]); const layer = DesktopLifecycle.layer.pipe( Layer.provideMerge(electronAppLayer), Layer.provideMerge(electronThemeLayer), Layer.provideMerge(desktopWindowLayer), Layer.provideMerge(environmentLayer), Layer.provideMerge(DesktopShutdown.layer), Layer.provideMerge(DesktopState.layer), ); return Effect.scoped( Effect.gen(function* () { const lifecycle = yield* DesktopLifecycle.DesktopLifecycle; yield* lifecycle.register; appListeners.get("before-quit-for-update")?.(); let prevented = false; const event = { preventDefault: () => { prevented = true; }, } as Electron.Event; appListeners.get("before-quit")?.(event); assert.isFalse( prevented, "cancelling this event prevents the updater from completing its relaunch", ); const state = yield* DesktopState.DesktopState; assert.isTrue(yield* Ref.get(state.quitting)); }), ).pipe(Effect.provide(layer)); }); } });