From 3770183088271b9ed2351ccbf77d516c21d77498 Mon Sep 17 00:00:00 2001 From: Iku-turso Date: Wed, 1 Jun 2022 15:05:29 +0300 Subject: [PATCH] Add behaviours for opening application window using tray and fix indicative bug about opening involuntary duplicate app windows Co-authored-by: Janne Savolainen Signed-off-by: Iku-turso --- ...ning-application-window-using-tray.test.ts | 151 ++++++++++++++++++ .../create-lens-window.injectable.ts | 2 + .../lens-window-injection-token.ts | 1 + .../show-application-window.injectable.ts | 2 +- 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/behaviours/quitting-and-restarting-the-app/opening-application-window-using-tray.test.ts diff --git a/src/behaviours/quitting-and-restarting-the-app/opening-application-window-using-tray.test.ts b/src/behaviours/quitting-and-restarting-the-app/opening-application-window-using-tray.test.ts new file mode 100644 index 0000000000..c345dc2299 --- /dev/null +++ b/src/behaviours/quitting-and-restarting-the-app/opening-application-window-using-tray.test.ts @@ -0,0 +1,151 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import { lensWindowInjectionToken } from "../../main/start-main-application/lens-window/application-window/lens-window-injection-token"; +import applicationWindowInjectable from "../../main/start-main-application/lens-window/application-window/application-window.injectable"; +import createElectronWindowForInjectable from "../../main/start-main-application/lens-window/application-window/create-electron-window-for.injectable"; +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; + +import type { + ElectronWindow, + LensWindowConfiguration, +} from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; + +import { flushPromises } from "../../common/test-utils/flush-promises"; +import type { DiContainer } from "@ogre-tools/injectable"; + +describe("opening application window using tray", () => { + describe("given application has started", () => { + let applicationBuilder: ApplicationBuilder; + + let createElectronWindowMock: AsyncFnMock< + (configuration: LensWindowConfiguration) => ElectronWindow + >; + + let expectWindowsToBeOpen: (windowIds: string[]) => void; + let resolveOpeningOfWindow: (windowId: string) => Promise; + + beforeEach(async () => { + applicationBuilder = getApplicationBuilder().beforeApplicationStart( + ({ mainDi }) => { + createElectronWindowMock = asyncFn(); + + mainDi.override( + createElectronWindowForInjectable, + + () => (configuration) => () => + createElectronWindowMock(configuration), + ); + + expectWindowsToBeOpen = expectWindowsToBeOpenFor(mainDi); + + resolveOpeningOfWindow = resolveOpeningOfWindowFor( + createElectronWindowMock, + ); + }, + ); + + const renderPromise = applicationBuilder.render(); + + await flushPromises(); + + await resolveOpeningOfWindow("splash"); + await resolveOpeningOfWindow("only-application-window"); + + await renderPromise; + }); + + it("only an application window is open", () => { + expectWindowsToBeOpen(["only-application-window"]); + }); + + describe("when the application window is closed", () => { + beforeEach(() => { + const applicationWindow = applicationBuilder.dis.mainDi.inject( + applicationWindowInjectable, + ); + + applicationWindow.close(); + }); + + it("no windows are open", () => { + expectWindowsToBeOpen([]); + }); + + describe("when an application window is reopened using tray", () => { + beforeEach(() => { + applicationBuilder.tray.click("open-app"); + }); + + it("still no windows are open", () => { + expectWindowsToBeOpen([]); + }); + + describe("when opening of splash window resolves", () => { + beforeEach(async () => { + await resolveOpeningOfWindow("splash"); + }); + + it("still only splash window is open", () => { + expectWindowsToBeOpen(["splash"]); + }); + + it("when opening finishes, only an application window is open", async () => { + await resolveOpeningOfWindow("only-application-window"); + + expectWindowsToBeOpen(["only-application-window"]); + }); + + describe("given opening has not finished yet, but another attempt to open the application is made", () => { + beforeEach(() => { + createElectronWindowMock.mockClear(); + + applicationBuilder.tray.click("open-app"); + }); + + it("does not open any new windows", () => { + expect(createElectronWindowMock).not.toHaveBeenCalled(); + }); + + it("when opening finishes, only an application window is open", async () => { + await resolveOpeningOfWindow("only-application-window"); + + expectWindowsToBeOpen(["only-application-window"]); + }); + }); + }); + }); + }); + }); +}); + +const expectWindowsToBeOpenFor = (di: DiContainer) => (windowIds: string[]) => { + const windows = di.injectMany(lensWindowInjectionToken); + + expect( + windows.filter((window) => window.visible).map((window) => window.id), + ).toEqual(windowIds); +}; + +const resolveOpeningOfWindowFor = + ( + createElectronWindowMock: AsyncFnMock< + (configuration: LensWindowConfiguration) => ElectronWindow + >, + ) => + async (windowId: string) => { + await createElectronWindowMock.resolveSpecific( + [{ id: windowId }], + + { + send: () => {}, + close: () => {}, + show: () => {}, + }, + ); + }; diff --git a/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts b/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts index 8d8f720121..ba26ce8e4b 100644 --- a/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts +++ b/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts @@ -44,6 +44,8 @@ const createLensWindowInjectable = getInjectable({ }); return { + id: configuration.id, + get visible() { return !!browserWindow; }, diff --git a/src/main/start-main-application/lens-window/application-window/lens-window-injection-token.ts b/src/main/start-main-application/lens-window/application-window/lens-window-injection-token.ts index 3e62b0894b..1a31c18780 100644 --- a/src/main/start-main-application/lens-window/application-window/lens-window-injection-token.ts +++ b/src/main/start-main-application/lens-window/application-window/lens-window-injection-token.ts @@ -12,6 +12,7 @@ export interface SendToViewArgs { } export interface LensWindow { + id: string; show: () => Promise; close: () => void; send: (args: SendToViewArgs) => void; diff --git a/src/main/start-main-application/lens-window/show-application-window.injectable.ts b/src/main/start-main-application/lens-window/show-application-window.injectable.ts index b514c41891..a862455567 100644 --- a/src/main/start-main-application/lens-window/show-application-window.injectable.ts +++ b/src/main/start-main-application/lens-window/show-application-window.injectable.ts @@ -17,7 +17,7 @@ const showApplicationWindowInjectable = getInjectable({ ); return async () => { - if (applicationWindow.visible) { + if (applicationWindow.visible || splashWindow.visible) { return; }