mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce way to install update directly from tray. Make application updater unit testable... (#5433)
* Extract product name as injectable Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make tray items comply with Open Closed Principle Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Replace duplicated overrides with global Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add behaviour for navigating to preferences using tray Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce a tray item for updating application Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak naming Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak more naming Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant indirection Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak more naming Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce injectable for package.json being side-effect Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Relocate file to directory containing feature Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using injectable for limiting side effect Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add missing injection token for implementation of tray item Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove resetting state for update is ready to be installed for being unclear Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Kill dead code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make label of tray item reactive Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Extract updating is enabled to separate injectable Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for tray Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Expand scope of behaviour for updating using tray also contain checking for updates Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove dead code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Kill dead code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement checking of updates from multiple update channels Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Start installing updates automatically when quitting application Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Show application window when checking of updates has happened Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Show notifications and dialog for downloading update Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement naive notifications for version updates Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement checking of Electron specific updates as responsibility Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement downloading of Electron specific updates as responsibility Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce competition for channel abstraction Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant global override Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix typing after enabling strict mode Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce abstraction for a state that is shared between environments Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Extract states of application update to be usable from all environments Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Handle failing download of update Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make code for window visibility actually work Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate code for sending messages between processes to a window Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Split bloated dependency in smaller pieces Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make state of download progress accessible from all environments Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Rename files for accuracy Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move channel abstraction to more global directory Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Enhance typing of channels and sync-box Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate channel abstraction types Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Update asyncFn to support strict mode Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix snapshot after rebase Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add missing global override Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce injection token for channels to allow injecting all of them at once Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add notifications about change in update status Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Rename property for accuracy Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak code style Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make notifications unit testable in behaviours Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add implementation for asking boolean over processes Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Reorganize responsibilities for checking updates Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Reorganize tests for installing update under separate scenarios Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make stuff happening when root frame is rendered unit testable Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce periodical check for updates Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Allow downgrading app versions Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using competition for checking of updates in application menu Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Kill dead code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make test less prone to fail for wrong reason Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant boilerplate Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make tests for specific migrations less prone to failing for wrong reason Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move shared stuff under common Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using single source of truth for selected update channel Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Extract tests for installing update from different update channels to separate scenario Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add missing global override Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Switch to using release channel of installed application version as default value for selected update channel Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate usage of channel abstraction to same implementation Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make Channel abstraction support return values Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix direct calling of runnables Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Synchronize initial values of sync boxes when window starts Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add missing global override Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak message of question from user Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Consolidate names of directories Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Add TODO Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove unimplemented scenario from test Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Simplify test Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Improve name of test Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant overrides Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix code style Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make Animate deterministic in unit tests Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Simplify naming Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify more naming Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify even more naming Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify more and more naming Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Add todo for cleaning unacceptable code encountered Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Improve name of behaviour Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make unit test more strict Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Enhance name of behaviour Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce dependency to get random IDs Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make asking of boolean value from user not require explicit ID for question Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Simplify code for asking of boolean value from user Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make setting of initial state for sync boxes not trigger irrelevant messaging to main Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make a channel have default type for sent and returned message Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce higher order function to log errors in decorated functions Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Export type for error logging Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak test name Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce higher order function for suppressing errors Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Relocate some explicit error handlings to proper level of abstraction Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make higher order function for logging errors support asynchronous rejecting with non error instance Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make overridden version of application exactly the one required by unit test Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Mark injectable causing side effects Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Revert not required changes Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make code for asserting a promise more strict Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Make dependencies readonly Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove duplication for disposers Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement initial values for sync-boxes Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Separate concept of message and request channels Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Introduce tests for requesting from channel in renderer Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Implement requesting from renderer in main Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Revert "Implement requesting from renderer in main" This reverts commit d3e7899d7900516f3dbfacdb317a453202318305. Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak typing of request channel listeners to get rid of unexpected undefined Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove unused variable Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Tweak timing of sentry setup Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Require messages for MessageChannels be JsonValues for serialization Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Require requests and responses for RequestChannels be JsonValues for serialization Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make different MessageChannels not require explicit "extends JsonObject" Note: Non-escaped lint breaks type here for forcing interface over type. Reasonable effort brought no understanding for what is the relevant difference between the two. Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make a primitive argument an object for readability Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make typing of higher order function for error suppression not lie Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Serialize messages in channels to make IPC not blow up Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Introduce a way to make intentional orphan promises uniform, controllable and deliberate Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Make downloading of update and what follows more deliberate as orphan promise Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Move utility function under directory Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Move another utility function under directory Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix incorrect name of file Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Remove redundant code Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Kill dead code Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Round percentage of update download progress in tray Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix rebase conflicts Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> * Fix CheckForUpdate type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> Co-authored-by: Iku-turso <mikko.aspiala@gmail.com> Co-authored-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
229 files changed
+8652
-1217
No files matched your search
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { nextUpdateChannel } from "../update-channel";
|
||||
|
||||
describe("nextUpdateChannel", () => {
|
||||
it("returns latest if current channel is latest", () => {
|
||||
expect(nextUpdateChannel("latest", "latest")).toEqual("latest");
|
||||
});
|
||||
|
||||
it("returns beta if current channel is alpha", () => {
|
||||
expect(nextUpdateChannel("alpha", "alpha")).toEqual("beta");
|
||||
expect(nextUpdateChannel("beta", "alpha")).toEqual("beta");
|
||||
expect(nextUpdateChannel("rc", "alpha")).toEqual("beta");
|
||||
expect(nextUpdateChannel("latest", "alpha")).toEqual("beta");
|
||||
});
|
||||
|
||||
it("returns latest if current channel is beta", () => {
|
||||
expect(nextUpdateChannel("alpha", "beta")).toEqual("latest");
|
||||
expect(nextUpdateChannel("beta", "beta")).toEqual("latest");
|
||||
expect(nextUpdateChannel("rc", "beta")).toEqual("latest");
|
||||
expect(nextUpdateChannel("latest", "beta")).toEqual("latest");
|
||||
});
|
||||
|
||||
it("returns default if current channel is unknown", () => {
|
||||
expect(nextUpdateChannel("alpha", "rc")).toEqual("alpha");
|
||||
expect(nextUpdateChannel("beta", "rc")).toEqual("beta");
|
||||
expect(nextUpdateChannel("rc", "rc")).toEqual("rc");
|
||||
expect(nextUpdateChannel("latest", "rc")).toEqual("latest");
|
||||
});
|
||||
});
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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 type { IpcMainEvent } from "electron";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { tentativeParseJson } from "../../../../common/utils/tentative-parse-json";
|
||||
|
||||
const enlistMessageChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-message-channel-listener-for-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeOnCallback = (_: IpcMainEvent, message: unknown) => {
|
||||
pipeline(
|
||||
message,
|
||||
tentativeParseJson,
|
||||
handler,
|
||||
);
|
||||
};
|
||||
|
||||
ipcMain.on(channel.id, nativeOnCallback);
|
||||
|
||||
return () => {
|
||||
ipcMain.off(channel.id, nativeOnCallback);
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: enlistMessageChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default enlistMessageChannelListenerInjectable;
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import type { EnlistMessageChannelListener } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import type { IpcMain, IpcMainEvent } from "electron";
|
||||
|
||||
describe("enlist message channel listener in main", () => {
|
||||
let enlistMessageChannelListener: EnlistMessageChannelListener;
|
||||
let ipcMainStub: IpcMain;
|
||||
let onMock: jest.Mock;
|
||||
let offMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
onMock = jest.fn();
|
||||
offMock = jest.fn();
|
||||
|
||||
ipcMainStub = {
|
||||
on: onMock,
|
||||
off: offMock,
|
||||
} as unknown as IpcMain;
|
||||
|
||||
di.override(ipcMainInjectable, () => ipcMainStub);
|
||||
|
||||
enlistMessageChannelListener = di.inject(
|
||||
enlistMessageChannelListenerInjectionToken,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let handlerMock: jest.Mock;
|
||||
let disposer: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
handlerMock = jest.fn();
|
||||
|
||||
disposer = enlistMessageChannelListener({
|
||||
channel: { id: "some-channel-id" },
|
||||
handler: handlerMock,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call handler yet", () => {
|
||||
expect(handlerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers the listener", () => {
|
||||
expect(onMock).toHaveBeenCalledWith(
|
||||
"some-channel-id",
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not de-register the listener yet", () => {
|
||||
expect(offMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when message arrives", () => {
|
||||
beforeEach(() => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, "some-message");
|
||||
});
|
||||
|
||||
it("calls the handler with the message", () => {
|
||||
expect(handlerMock).toHaveBeenCalledWith("some-message");
|
||||
});
|
||||
|
||||
it("when disposing the listener, de-registers the listener", () => {
|
||||
disposer();
|
||||
|
||||
expect(offMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, 42);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("given boolean as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, true);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("given stringified object as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, JSON.stringify({ some: "object" }));
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith({ some: "object" });
|
||||
});
|
||||
});
|
||||
});
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 type { IpcMainInvokeEvent } from "electron";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import { enlistRequestChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-request-channel-listener-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { tentativeParseJson } from "../../../../common/utils/tentative-parse-json";
|
||||
import { tentativeStringifyJson } from "../../../../common/utils/tentative-stringify-json";
|
||||
|
||||
const enlistRequestChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-request-channel-listener-for-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeHandleCallback = (_: IpcMainInvokeEvent, request: unknown) =>
|
||||
pipeline(request, tentativeParseJson, handler, tentativeStringifyJson);
|
||||
|
||||
ipcMain.handle(channel.id, nativeHandleCallback);
|
||||
|
||||
return () => {
|
||||
ipcMain.off(channel.id, nativeHandleCallback);
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: enlistRequestChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default enlistRequestChannelListenerInjectable;
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import type { IpcMain, IpcMainInvokeEvent } from "electron";
|
||||
import type { EnlistRequestChannelListener } from "../../../../common/utils/channel/enlist-request-channel-listener-injection-token";
|
||||
import { enlistRequestChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-request-channel-listener-injection-token";
|
||||
import { getPromiseStatus } from "../../../../common/test-utils/get-promise-status";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
|
||||
describe("enlist request channel listener in main", () => {
|
||||
let enlistRequestChannelListener: EnlistRequestChannelListener;
|
||||
let ipcMainStub: IpcMain;
|
||||
let handleMock: jest.Mock;
|
||||
let offMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
handleMock = jest.fn();
|
||||
offMock = jest.fn();
|
||||
|
||||
ipcMainStub = {
|
||||
handle: handleMock,
|
||||
off: offMock,
|
||||
} as unknown as IpcMain;
|
||||
|
||||
di.override(ipcMainInjectable, () => ipcMainStub);
|
||||
|
||||
enlistRequestChannelListener = di.inject(
|
||||
enlistRequestChannelListenerInjectionToken,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let handlerMock: AsyncFnMock<(message: any) => any>;
|
||||
let disposer: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
handlerMock = asyncFn();
|
||||
|
||||
disposer = enlistRequestChannelListener({
|
||||
channel: { id: "some-channel-id" },
|
||||
handler: handlerMock,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call handler yet", () => {
|
||||
expect(handlerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers the listener", () => {
|
||||
expect(handleMock).toHaveBeenCalledWith(
|
||||
"some-channel-id",
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not de-register the listener yet", () => {
|
||||
expect(offMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when request arrives", () => {
|
||||
let actualPromise: Promise<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
actualPromise = handleMock.mock.calls[0][1](
|
||||
{} as IpcMainInvokeEvent,
|
||||
"some-request",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls the handler with the request", () => {
|
||||
expect(handlerMock).toHaveBeenCalledWith("some-request");
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
describe("when handler resolves with response, listener resolves with the response", () => {
|
||||
beforeEach(async () => {
|
||||
await handlerMock.resolve("some-response");
|
||||
});
|
||||
|
||||
it("resolves with the response", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe('"some-response"');
|
||||
});
|
||||
|
||||
it("when disposing the listener, de-registers the listener", () => {
|
||||
disposer();
|
||||
|
||||
expect(offMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as response, when handler resolves with response, listener resolves with stringified response", async () => {
|
||||
await handlerMock.resolve(42);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe("42");
|
||||
});
|
||||
|
||||
it("given boolean as response, when handler resolves with response, listener resolves with stringified response", async () => {
|
||||
await handlerMock.resolve(true);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe("true");
|
||||
});
|
||||
|
||||
it("given object as response, when handler resolves with response, listener resolves with stringified response", async () => {
|
||||
await handlerMock.resolve({ some: "object" });
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(JSON.stringify({ some: "object" }));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, 42);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("given boolean as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, true);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("given stringified object as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, JSON.stringify({ some: "object" }));
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith({ some: "object" });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
import listeningOfChannelsInjectable from "../../../../common/utils/channel/listening-of-channels.injectable";
|
||||
|
||||
const startListeningOfChannelsInjectable = getInjectable({
|
||||
id: "start-listening-of-channels-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const listeningOfChannels = di.inject(listeningOfChannelsInjectable);
|
||||
|
||||
return {
|
||||
run: async () => {
|
||||
await listeningOfChannels.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default startListeningOfChannelsInjectable;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 { ipcMain } from "electron";
|
||||
|
||||
const ipcMainInjectable = getInjectable({
|
||||
id: "ipc-main",
|
||||
instantiate: () => ipcMain,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default ipcMainInjectable;
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { lensWindowInjectionToken } from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { filter } from "lodash/fp";
|
||||
import { messageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import type { MessageChannel } from "../../../common/utils/channel/message-channel-injection-token";
|
||||
import { tentativeStringifyJson } from "../../../common/utils/tentative-stringify-json";
|
||||
|
||||
const messageToChannelInjectable = getInjectable({
|
||||
id: "message-to-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getAllLensWindows = () => di.injectMany(lensWindowInjectionToken);
|
||||
|
||||
// TODO: Figure out way to improve typing in internals
|
||||
// Notice that this should be injected using "messageToChannelInjectionToken" which is typed correctly.
|
||||
return (channel: MessageChannel<any>, message?: unknown) => {
|
||||
const stringifiedMessage = tentativeStringifyJson(message);
|
||||
|
||||
|
||||
const visibleWindows = pipeline(
|
||||
getAllLensWindows(),
|
||||
filter((lensWindow) => !!lensWindow.visible),
|
||||
);
|
||||
|
||||
visibleWindows.forEach((lensWindow) =>
|
||||
lensWindow.send({ channel: channel.id, data: stringifiedMessage ? [stringifiedMessage] : [] }),
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: messageToChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default messageToChannelInjectable;
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { MessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import { messageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import closeAllWindowsInjectable from "../../start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
|
||||
import type { MessageChannel } from "../../../common/utils/channel/message-channel-injection-token";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import createLensWindowInjectable from "../../start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import type { LensWindow } from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
import { lensWindowInjectionToken } from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import sendToChannelInElectronBrowserWindowInjectable from "../../start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
|
||||
|
||||
describe("message to channel from main", () => {
|
||||
let messageToChannel: MessageToChannel;
|
||||
let someTestWindow: LensWindow;
|
||||
let someOtherTestWindow: LensWindow;
|
||||
let sendToChannelInBrowserMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
sendToChannelInBrowserMock = jest.fn();
|
||||
di.override(sendToChannelInElectronBrowserWindowInjectable, () => sendToChannelInBrowserMock);
|
||||
|
||||
someTestWindow = createTestWindow(di, "some-test-window-id");
|
||||
someOtherTestWindow = createTestWindow(di, "some-other-test-window-id");
|
||||
|
||||
messageToChannel = di.inject(messageToChannelInjectionToken);
|
||||
|
||||
const closeAllWindows = di.inject(closeAllWindowsInjectable);
|
||||
|
||||
closeAllWindows();
|
||||
});
|
||||
|
||||
it("given no visible windows, when messaging to channel, does not message to any window", () => {
|
||||
messageToChannel(someChannel, "some-message");
|
||||
|
||||
expect(sendToChannelInBrowserMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("given visible window", () => {
|
||||
beforeEach(async () => {
|
||||
await someTestWindow.show();
|
||||
});
|
||||
|
||||
it("when messaging to channel, messages to window", () => {
|
||||
messageToChannel(someChannel, "some-message");
|
||||
|
||||
expect(sendToChannelInBrowserMock.mock.calls).toEqual([
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: ['"some-message"'],
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it("given boolean as message, when messaging to channel, messages to window with stringified message", () => {
|
||||
messageToChannel(someChannel, true);
|
||||
|
||||
expect(sendToChannelInBrowserMock.mock.calls).toEqual([
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: ["true"],
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it("given number as message, when messaging to channel, messages to window with stringified message", () => {
|
||||
messageToChannel(someChannel, 42);
|
||||
|
||||
expect(sendToChannelInBrowserMock.mock.calls).toEqual([
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: ["42"],
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it("given object as message, when messaging to channel, messages to window with stringified message", () => {
|
||||
messageToChannel(someChannel, { some: "object" });
|
||||
|
||||
expect(sendToChannelInBrowserMock.mock.calls).toEqual([
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: [JSON.stringify({ some: "object" })],
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it("given multiple visible windows, when messaging to channel, messages to window", async () => {
|
||||
await someTestWindow.show();
|
||||
await someOtherTestWindow.show();
|
||||
|
||||
messageToChannel(someChannel, "some-message");
|
||||
|
||||
expect(sendToChannelInBrowserMock.mock.calls).toEqual([
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: ['"some-message"'],
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
null,
|
||||
|
||||
{
|
||||
channel: "some-channel",
|
||||
data: ['"some-message"'],
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
const someChannel: MessageChannel<any> = { id: "some-channel" };
|
||||
|
||||
const createTestWindow = (di: DiContainer, id: string) => {
|
||||
const testWindowInjectable = getInjectable({
|
||||
id,
|
||||
|
||||
instantiate: (di) => {
|
||||
const createLensWindow = di.inject(createLensWindowInjectable);
|
||||
|
||||
return createLensWindow({
|
||||
id,
|
||||
title: "Some test window",
|
||||
defaultHeight: 42,
|
||||
defaultWidth: 42,
|
||||
getContentSource: () => ({ url: "some-content-url" }),
|
||||
resizable: true,
|
||||
windowFrameUtilitiesAreShown: false,
|
||||
centered: false,
|
||||
});
|
||||
},
|
||||
|
||||
injectionToken: lensWindowInjectionToken,
|
||||
});
|
||||
|
||||
di.register(testWindowInjectable);
|
||||
|
||||
return di.inject(testWindowInjectable);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 syncBoxInitialValueChannelInjectable from "../../../common/utils/sync-box/sync-box-initial-value-channel.injectable";
|
||||
import { syncBoxInjectionToken } from "../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { requestChannelListenerInjectionToken } from "../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
|
||||
const syncBoxInitialValueChannelListenerInjectable = getInjectable({
|
||||
id: "sync-box-initial-value-channel-listener",
|
||||
|
||||
instantiate: (di) => {
|
||||
const channel = di.inject(syncBoxInitialValueChannelInjectable);
|
||||
const syncBoxes = di.injectMany(syncBoxInjectionToken);
|
||||
|
||||
return {
|
||||
channel,
|
||||
|
||||
handler: () =>
|
||||
syncBoxes.map((box) => ({
|
||||
id: box.id,
|
||||
value: box.value.get(),
|
||||
})),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: requestChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default syncBoxInitialValueChannelListenerInjectable;
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compute the next update channel from the current updating channel
|
||||
* @param defaultChannel The default (initial) channel to check
|
||||
* @param channel The current channel that did not have a new version associated with it
|
||||
* @returns The channel name of the next release version
|
||||
*/
|
||||
export function nextUpdateChannel(defaultChannel: string, channel: string | null): string {
|
||||
switch (channel) {
|
||||
case "alpha":
|
||||
return "beta";
|
||||
case "beta":
|
||||
return "latest"; // there is no RC currently
|
||||
default:
|
||||
return defaultChannel;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user