diff options
| author | Oskar <oskar@mullvad.net> | 2025-09-02 14:59:53 +0200 |
|---|---|---|
| committer | Oskar <oskar@mullvad.net> | 2025-09-05 11:47:01 +0200 |
| commit | f61e1331a5e0a40e4d351c36f9688cc1ee2d3487 (patch) | |
| tree | 9908d2df1c769ae67496d8cf5b75d41ab68d26c3 | |
| parent | 985152f6ac87396c8ddac80db28e3aa5658efa3b (diff) | |
| download | mullvadvpn-f61e1331a5e0a40e4d351c36f9688cc1ee2d3487.tar.xz mullvadvpn-f61e1331a5e0a40e4d351c36f9688cc1ee2d3487.zip | |
Add new ipc utility for mocked tests
| -rw-r--r-- | desktop/packages/mullvad-vpn/src/shared/ipc-helpers.ts | 27 | ||||
| -rw-r--r-- | desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts | 53 |
2 files changed, 59 insertions, 21 deletions
diff --git a/desktop/packages/mullvad-vpn/src/shared/ipc-helpers.ts b/desktop/packages/mullvad-vpn/src/shared/ipc-helpers.ts index db219f4535..c4f2c87c83 100644 --- a/desktop/packages/mullvad-vpn/src/shared/ipc-helpers.ts +++ b/desktop/packages/mullvad-vpn/src/shared/ipc-helpers.ts @@ -21,15 +21,16 @@ interface RendererToMain<T, R> { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -type AnyIpcCall = MainToRenderer<any> | RendererToMain<any, any>; +export type AnyIpcCall = MainToRenderer<any> | RendererToMain<any, any>; export type Schema = Record<string, Record<string, AnyIpcCall>>; // Renames all IPC calls, e.g. `callName` to either `notifyCallName` or `handleCallName` depending // on direction. -type IpcMainKey<N extends string, I extends AnyIpcCall> = I['direction'] extends 'main-to-renderer' - ? `notify${Capitalize<N>}` - : `handle${Capitalize<N>}`; +export type IpcMainKey< + N extends string, + I extends AnyIpcCall, +> = I['direction'] extends 'main-to-renderer' ? `notify${Capitalize<N>}` : `handle${Capitalize<N>}`; // Selects either the send or receive function depending on direction. type IpcMainFn<I extends AnyIpcCall> = I['direction'] extends 'main-to-renderer' @@ -61,11 +62,6 @@ export type IpcRenderer<S extends Schema> = { }; }; -// Transforms the provided schema into containing only the event keys. -export type IpcEvents<S> = { - [G in keyof S]: { [C in keyof S[G]]: string }; -}; - // Preforms the transformation of the main event channel in accordance with the above types. export function createIpcMain<S extends Schema>( schema: S, @@ -104,15 +100,10 @@ export function createIpcRenderer<S extends Schema>( }); } -export function createIpcEvents<S extends Schema>(schema: S): IpcEvents<S> { - return createIpc(schema, (event, key) => [key, event]); -} - -export function createIpc< - S extends Schema, - T, - R extends IpcMain<S> | IpcRenderer<S> | IpcEvents<S>, ->(ipc: S, fn: (event: string, key: string, spec: AnyIpcCall) => [newKey: string, newValue: T]): R { +export function createIpc<S extends Schema, T, R>( + ipc: S, + fn: (event: string, key: string, spec: AnyIpcCall) => [newKey: string, newValue: T], +): R { return Object.fromEntries( Object.entries(ipc).map(([groupKey, group]) => { const newGroup = Object.fromEntries( diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts index 0290536418..530b2c48a7 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts @@ -1,6 +1,6 @@ import { ElectronApplication } from 'playwright'; -import { createIpcEvents, IpcEvents } from '../../../src/shared/ipc-helpers'; +import { AnyIpcCall, createIpc, Schema } from '../../../src/shared/ipc-helpers'; import { IpcSchema, ipcSchema } from '../../../src/shared/ipc-schema'; import { startApp, TestUtils } from '../utils'; @@ -16,7 +16,7 @@ export interface MockedTestUtils extends TestUtils { mockIpcHandle: MockIpcHandle; sendMockIpcResponse: SendMockIpcResponse; expectIpcCall: ExpectIpcCall; - ipcEvents: IpcEvents<IpcSchema>; + ipc: IpcMockedTest<IpcSchema>; } export const startMockedApp = async (): Promise<StartMockedAppResponse> => { @@ -41,7 +41,7 @@ export const startMockedApp = async (): Promise<StartMockedAppResponse> => { sendMockIpcResponse, expectIpcCall, - ipcEvents: createIpcEvents(ipcSchema), + ipc: createTestIpc(startAppResult.app), }, }; }; @@ -101,6 +101,10 @@ export const generateExpectIpcCall = (electronApp: ElectronApplication) => { return new Promise<T>((resolve) => { ipcMain.handleOnce(channel, (_event, arg) => { resolve(arg); + return { + type: 'success', + value: null, + }; }); }); }, @@ -108,3 +112,46 @@ export const generateExpectIpcCall = (electronApp: ElectronApplication) => { ); }; }; + +type IpcMockedTestKey<I extends AnyIpcCall> = I['direction'] extends 'main-to-renderer' + ? 'notify' + : 'handle'; + +type IpcMockedTestExpectKey<I extends AnyIpcCall> = I['direction'] extends 'main-to-renderer' + ? never + : 'expect'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Async<F extends (...args: any) => any> = (arg: Parameters<F>[0]) => Promise<ReturnType<F>>; + +type IpcMockedTestFn<I extends AnyIpcCall> = I['direction'] extends 'main-to-renderer' + ? Async<NonNullable<ReturnType<I['send']>>> + : Async<Parameters<ReturnType<I['receive']>>[0]>; + +export type IpcMockedTest<S extends Schema> = { + [G in keyof S]: { + [K in keyof S[G]]: { + [C in IpcMockedTestKey<S[G][K]>]: IpcMockedTestFn<S[G][K]>; + } & { + [C in IpcMockedTestExpectKey<S[G][K]>]: () => Promise<void>; + } & { + eventKey: string; + }; + }; +}; + +export function createTestIpc(electronApp: ElectronApplication): IpcMockedTest<IpcSchema> { + return createIpc(ipcSchema, (event, key, _spec) => { + return [ + key, + { + eventKey: event, + notify: <T>(message: T) => + generateSendMockIpcResponse(electronApp)({ channel: event, response: message }), + handle: <T>(response: T) => + generateMockIpcHandle(electronApp)({ channel: event, response }), + expect: () => generateExpectIpcCall(electronApp)(event), + }, + ]; + }); +} |
