模拟 Tauri API
在编写前端测试时,通常需要一个“伪”Tauri 环境来模拟窗口或拦截 IPC 调用,即所谓的*模拟*。@tauri-apps/api/mocks
模块提供了一些有用的工具来方便你进行此操作。
最常见的是,您希望拦截 IPC 请求;这在各种情况下都很有用
- 确保后端调用正确
- 模拟后端函数的不同结果
Tauri 提供了 mockIPC 函数来拦截 IPC 请求。您可以在此处找到有关特定 API 的更多详细信息。
import { beforeAll, expect, test } from "vitest";import { randomFillSync } from "crypto";
import { mockIPC } from "@tauri-apps/api/mocks";import { invoke } from "@tauri-apps/api/core";
// jsdom doesn't come with a WebCrypto implementationbeforeAll(() => { Object.defineProperty(window, 'crypto', { value: { // @ts-ignore getRandomValues: (buffer) => { return randomFillSync(buffer); }, }, });});
test("invoke simple", async () => { mockIPC((cmd, args) => { // simulated rust command called "add" that just adds two numbers if(cmd === "add") { return (args.a as number) + (args.b as number); } });});
有时您希望跟踪有关 IPC 调用的更多信息;命令被调用了多少次?它被调用了吗?您可以使用 mockIPC()
以及其他监视和模拟工具来测试这一点
import { beforeAll, expect, test, vi } from "vitest";import { randomFillSync } from "crypto";
import { mockIPC } from "@tauri-apps/api/mocks";import { invoke } from "@tauri-apps/api/core";
// jsdom doesn't come with a WebCrypto implementationbeforeAll(() => { Object.defineProperty(window, 'crypto', { value: { // @ts-ignore getRandomValues: (buffer) => { return randomFillSync(buffer); }, }, });});
test("invoke", async () => { mockIPC((cmd, args) => { // simulated rust command called "add" that just adds two numbers if(cmd === "add") { return (args.a as number) + (args.b as number); } });
// we can use the spying tools provided by vitest to track the mocked function const spy = vi.spyOn(window.__TAURI_INTERNALS__, "invoke");
expect(invoke("add", { a: 12, b: 15 })).resolves.toBe(27); expect(spy).toHaveBeenCalled();});
要模拟对 sidecar 或 shell 命令的 IPC 请求,您需要获取调用 spawn()
或 execute()
时事件处理程序的 ID,并使用此 ID 发送后端将发送回的事件
mockIPC(async (cmd, args) => { if (args.message.cmd === 'execute') { const eventCallbackId = `_${args.message.onEventFn}`; const eventEmitter = window[eventCallbackId];
// 'Stdout' event can be called multiple times eventEmitter({ event: 'Stdout', payload: 'some data sent from the process', });
// 'Terminated' event must be called at the end to resolve the promise eventEmitter({ event: 'Terminated', payload: { code: 0, signal: 'kill', }, }); }});
2.7.0
起
通过 shouldMockEvents
选项,对 事件系统 的部分支持,以模拟 Rust 代码发出的事件
import { mockIPC, clearMocks } from '@tauri-apps/api/mocks';import { emit, listen } from '@tauri-apps/api/event';import { afterEach, expect, test, vi } from 'vitest';
test('mocked event', () => { mockIPC(() => {}, { shouldMockEvents: true }); // enable event mocking
const eventHandler = vi.fn(); listen('test-event', eventHandler);
emit('test-event', { foo: 'bar' }); expect(eventHandler).toHaveBeenCalledWith({ event: 'test-event', payload: { foo: 'bar' }, });});
emitTo
和 emit_filter
尚不支持。
有时您有特定于窗口的代码(例如,一个启动画面窗口),因此您需要模拟不同的窗口。您可以使用 mockWindows()
方法来创建虚假的窗口标签。第一个字符串标识“当前”窗口(即您的 JavaScript 认为自己所在的窗口),所有其他字符串都被视为附加窗口。
import { beforeAll, expect, test } from 'vitest';import { randomFillSync } from 'crypto';
import { mockWindows } from '@tauri-apps/api/mocks';
// jsdom doesn't come with a WebCrypto implementationbeforeAll(() => { Object.defineProperty(window, 'crypto', { value: { // @ts-ignore getRandomValues: (buffer) => { return randomFillSync(buffer); }, }, });});
test('invoke', async () => { mockWindows('main', 'second', 'third');
const { getCurrent, getAll } = await import('@tauri-apps/api/webviewWindow');
expect(getCurrent()).toHaveProperty('label', 'main'); expect(getAll().map((w) => w.label)).toEqual(['main', 'second', 'third']);});
© 2025 Tauri 贡献者。CC-BY / MIT