mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
* feat: update to latest wry * wry dev branch [skip ci] * fix linux [skip ci] * refactor(runtime): split webview and window types * split dispatch * implement create_webview * move webview message * wip webview mod * create webview manager, finish webview struct and builder * fix tests and docs * rename WindowUrl to WebviewUrl * update examples * event refactor * update JS API * fix events * update example * add WebviewWindow class on JS * fix macos build * allow creating window+webview on the same runtime call * rename tauri://window-created to tauri://webview-created * Window::add_child * use inner_size from webview on macOS * add multiwebview example * automatically resize webviews on window resize * fix tests * set_position, set_size * position, size getters * set_focus * add close fn * update mock runtime * lint [skip ci] * fix inner_size getter [skip ci] * import hwnd [skip ci] * update webview bound ratios on set_size/set_position * add auto_resize option * fix android * fix build on windows * typo * with_webview isnt desktop only * add WebviewWindow rust struct (and builder) * fix build on android * license header * fix macos/windows * fix macos build * resolve todo * handle window not found * hide unstable features * document unstable feature [skip ci] * webview plugin permissions * hide more stuff * fix doctests * typos * add change files * fix examples * rename hook
231 lines
6.2 KiB
TypeScript
231 lines
6.2 KiB
TypeScript
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import { InvokeArgs, InvokeOptions } from './core'
|
|
|
|
function mockInternals() {
|
|
window.__TAURI_INTERNALS__ = window.__TAURI_INTERNALS__ ?? {}
|
|
}
|
|
|
|
/**
|
|
* Intercepts all IPC requests with the given mock handler.
|
|
*
|
|
* This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
|
|
*
|
|
* # Examples
|
|
*
|
|
* Testing setup using vitest:
|
|
* ```js
|
|
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
|
|
* import { invoke } from "@tauri-apps/api/core"
|
|
*
|
|
* afterEach(() => {
|
|
* clearMocks()
|
|
* })
|
|
*
|
|
* test("mocked command", () => {
|
|
* mockIPC((cmd, payload) => {
|
|
* switch (cmd) {
|
|
* case "add":
|
|
* return (payload.a as number) + (payload.b as number);
|
|
* default:
|
|
* break;
|
|
* }
|
|
* });
|
|
*
|
|
* expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
|
|
* })
|
|
* ```
|
|
*
|
|
* The callback function can also return a Promise:
|
|
* ```js
|
|
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
|
|
* import { invoke } from "@tauri-apps/api/core"
|
|
*
|
|
* afterEach(() => {
|
|
* clearMocks()
|
|
* })
|
|
*
|
|
* test("mocked command", () => {
|
|
* mockIPC((cmd, payload) => {
|
|
* if(cmd === "get_data") {
|
|
* return fetch("https://example.com/data.json")
|
|
* .then((response) => response.json())
|
|
* }
|
|
* });
|
|
*
|
|
* expect(invoke('get_data')).resolves.toBe({ foo: 'bar' });
|
|
* })
|
|
* ```
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
export function mockIPC(
|
|
cb: <T>(cmd: string, payload?: InvokeArgs) => Promise<T>
|
|
): void {
|
|
mockInternals()
|
|
|
|
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 <T>(
|
|
cmd: string,
|
|
args?: InvokeArgs,
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
options?: InvokeOptions
|
|
): Promise<T> {
|
|
return cb(cmd, args)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mocks one or many window labels.
|
|
* In non-tauri context it is required to call this function *before* using the `@tauri-apps/api/window` module.
|
|
*
|
|
* This function only mocks the *presence* of windows,
|
|
* window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
|
|
*
|
|
* # Examples
|
|
*
|
|
* ```js
|
|
* import { mockWindows } from "@tauri-apps/api/mocks";
|
|
* import { getCurrent } from "@tauri-apps/api/window";
|
|
*
|
|
* mockWindows("main", "second", "third");
|
|
*
|
|
* const win = getCurrent();
|
|
*
|
|
* win.label // "main"
|
|
* ```
|
|
*
|
|
* ```js
|
|
* import { mockWindows } from "@tauri-apps/api/mocks";
|
|
*
|
|
* mockWindows("main", "second", "third");
|
|
*
|
|
* mockIPC((cmd, args) => {
|
|
* if (cmd === "plugin:event|emit") {
|
|
* console.log('emit event', args?.event, args?.payload);
|
|
* }
|
|
* });
|
|
*
|
|
* const { emit } = await import("@tauri-apps/api/event");
|
|
* await emit('loaded'); // this will cause the mocked IPC handler to log to the console.
|
|
* ```
|
|
*
|
|
* @param current Label of window this JavaScript context is running in.
|
|
* @param additionalWindows Label of additional windows the app has.
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
export function mockWindows(
|
|
current: string,
|
|
...additionalWindows: string[]
|
|
): void {
|
|
mockInternals()
|
|
window.__TAURI_INTERNALS__.metadata = {
|
|
windows: [current, ...additionalWindows].map((label) => ({ label })),
|
|
currentWindow: { label: current },
|
|
webviews: [current, ...additionalWindows].map((label) => ({
|
|
windowLabel: label,
|
|
label
|
|
})),
|
|
currentWebview: { windowLabel: current, label: current }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mock `convertFileSrc` function
|
|
*
|
|
*
|
|
* @example
|
|
* ```js
|
|
* import { mockConvertFileSrc } from "@tauri-apps/api/mocks";
|
|
* import { convertFileSrc } from "@tauri-apps/api/core";
|
|
*
|
|
* mockConvertFileSrc("windows")
|
|
*
|
|
* const url = convertFileSrc("C:\\Users\\user\\file.txt")
|
|
* ```
|
|
*
|
|
* @param osName The operating system to mock, can be one of linux, macos, or windows
|
|
*
|
|
* @since 1.6.0
|
|
*/
|
|
export function mockConvertFileSrc(osName: string): void {
|
|
mockInternals()
|
|
window.__TAURI_INTERNALS__.convertFileSrc = function (
|
|
filePath,
|
|
protocol = 'asset'
|
|
) {
|
|
const path = encodeURIComponent(filePath)
|
|
return osName === 'windows'
|
|
? `http://${protocol}.localhost/${path}`
|
|
: `${protocol}://localhost/${path}`
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears mocked functions/data injected by the other functions in this module.
|
|
* When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
|
|
*
|
|
* # Example
|
|
*
|
|
* ```js
|
|
* import { mockWindows, clearMocks } from "@tauri-apps/api/mocks"
|
|
*
|
|
* afterEach(() => {
|
|
* clearMocks()
|
|
* })
|
|
*
|
|
* test("mocked windows", () => {
|
|
* mockWindows("main", "second", "third");
|
|
*
|
|
* expect(window.__TAURI_INTERNALS__).toHaveProperty("metadata")
|
|
* })
|
|
*
|
|
* test("no mocked windows", () => {
|
|
* expect(window.__TAURI_INTERNALS__).not.toHaveProperty("metadata")
|
|
* })
|
|
* ```
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
export function clearMocks(): void {
|
|
if (typeof window.__TAURI_INTERNALS__ !== 'object') {
|
|
return
|
|
}
|
|
|
|
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__?.invoke)
|
|
// @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case
|
|
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
|
|
}
|