From 85826ddafef4fb8d4e9e8dc5a76e4b79ba9d884f Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 3 Jan 2024 17:11:36 +0100 Subject: [PATCH 1/2] fix(api.js): mock `__TAURI_INTERNALS__` in `mockIPC` and `mockWindows` --- .changes/fix-mock-tauri-internals.md | 5 +++++ tooling/api/src/mocks.ts | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changes/fix-mock-tauri-internals.md diff --git a/.changes/fix-mock-tauri-internals.md b/.changes/fix-mock-tauri-internals.md new file mode 100644 index 000000000000..25a7b2ebb74a --- /dev/null +++ b/.changes/fix-mock-tauri-internals.md @@ -0,0 +1,5 @@ +--- +'@tauri-apps/api': 'patch:bug' +--- + +`mockIPC` and `mockWindows` no longer crash if `window.__TAURI_INTERNALS__` is undefined. diff --git a/tooling/api/src/mocks.ts b/tooling/api/src/mocks.ts index f7fcd880510e..edaf50efd2fd 100644 --- a/tooling/api/src/mocks.ts +++ b/tooling/api/src/mocks.ts @@ -9,6 +9,10 @@ interface IPCMessage { [key: string]: unknown } +function mockInternals() { + window.__TAURI_INTERNALS__ = window.__TAURI_INTERNALS__ ?? {} +} + /** * Intercepts all IPC requests with the given mock handler. * @@ -65,6 +69,7 @@ interface IPCMessage { export function mockIPC( cb: (cmd: string, payload: Record) => unknown ): void { + mockInternals() // eslint-disable-next-line @typescript-eslint/no-misused-promises window.__TAURI_INTERNALS__.ipc = async ({ cmd, @@ -128,6 +133,7 @@ export function mockWindows( current: string, ...additionalWindows: string[] ): void { + mockInternals() window.__TAURI_INTERNALS__.metadata = { windows: [current, ...additionalWindows].map((label) => ({ label })), currentWindow: { label: current } @@ -153,7 +159,7 @@ export function mockWindows( * @since 1.6.0 */ export function mockConvertFileSrc(osName: string): void { - window.__TAURI_INTERNALS__ = window.__TAURI_INTERNALS__ ?? {} + mockInternals() window.__TAURI_INTERNALS__.convertFileSrc = function ( filePath, protocol = 'asset' From 4a79fd38706d065e18203608ef34de067fb5c8d6 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 3 Jan 2024 20:05:29 +0100 Subject: [PATCH 2/2] mock internals.invoke instead of internals.ipc --- tooling/api/src/mocks.ts | 61 ++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/tooling/api/src/mocks.ts b/tooling/api/src/mocks.ts index edaf50efd2fd..e6022d39546f 100644 --- a/tooling/api/src/mocks.ts +++ b/tooling/api/src/mocks.ts @@ -2,12 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -interface IPCMessage { - cmd: string - callback: number - error: number - [key: string]: unknown -} +import { InvokeArgs, InvokeOptions } from './core' function mockInternals() { window.__TAURI_INTERNALS__ = window.__TAURI_INTERNALS__ ?? {} @@ -67,25 +62,41 @@ function mockInternals() { * @since 1.0.0 */ export function mockIPC( - cb: (cmd: string, payload: Record) => unknown + cb: (cmd: string, payload?: InvokeArgs) => Promise ): void { mockInternals() - // eslint-disable-next-line @typescript-eslint/no-misused-promises - window.__TAURI_INTERNALS__.ipc = async ({ - cmd, - callback, - error, - payload - }: IPCMessage) => { - try { - // @ts-expect-error The function key is dynamic and therefore not typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - window[`_${callback}`](await cb(cmd, payload)) - } catch (err) { - // @ts-expect-error The function key is dynamic and therefore not typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - window[`_${error}`](err) - } + + window.__TAURI_INTERNALS__.transformCallback = function transformCallback( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callback?: (response: any) => void, + once = false + ) { + const identifier = window.crypto.getRandomValues(new Uint32Array(1))[0] + const prop = `_${identifier}` + + Object.defineProperty(window, prop, { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: (result: any) => { + if (once) { + Reflect.deleteProperty(window, prop) + } + + return callback && callback(result) + }, + writable: false, + configurable: true + }) + + return identifier + } + + window.__TAURI_INTERNALS__.invoke = function ( + cmd: string, + args?: InvokeArgs, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: InvokeOptions + ): Promise { + return cb(cmd, args) } } @@ -205,9 +216,9 @@ export function clearMocks(): void { if (window.__TAURI_INTERNALS__?.convertFileSrc) // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case delete window.__TAURI_INTERNALS__.convertFileSrc - if (window.__TAURI_INTERNALS__?.ipc) + if (window.__TAURI_INTERNALS__?.invoke) // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case - delete window.__TAURI_INTERNALS__.ipc + delete window.__TAURI_INTERNALS__.invoke if (window.__TAURI_INTERNALS__?.metadata) // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case delete window.__TAURI_INTERNALS__.metadata