Skip to content
Tauri 中文网

模拟 Tauri API

在编写前端测试时,拥有一个“假”的 Tauri 环境来模拟窗口或拦截 IPC 调用是很常见的,这就是所谓的_模拟_。 @tauri-apps/api/mocks 模块提供了一些有用的工具来帮助你更轻松地实现这一点:

🌐 When writing your frontend tests, having a “fake” Tauri environment to simulate windows or intercept IPC calls is common, so-called mocking. The @tauri-apps/api/mocks module provides some helpful tools to make this easier for you:

🌐 IPC Requests

最常见的是,你可能想拦截 IPC 请求;在各种情况下这都可能有帮助:

🌐 Most commonly, you want to intercept IPC requests; this can be helpful in a variety of situations:

  • 确保进行了正确的后端调用
  • 模拟来自后端函数的不同结果

Tauri 提供了 mockIPC 函数来拦截 IPC 请求。你可以在 这里 中找到关于具体 API 的更多详细信息。

🌐 Tauri provides the mockIPC function to intercept IPC requests. You can find more about the specific API in detail here.

🌐 Mocking Commands for invoke

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 implementation
beforeAll(() => {
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() 与其他监听和模拟工具一起使用来测试这一点:

🌐 Sometimes you want to track more information about an IPC call; how many times was the command invoked? Was it invoked at all? You can use mockIPC() with other spying and mocking tools to test this:

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 implementation
beforeAll(() => {
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 来发送后端会返回的事件:

🌐 To mock IPC requests to a sidecar or shell command you need to grab the ID of the event handler when spawn() or execute() is called and use this ID to emit events the backend would send back:

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',
},
});
}
});

🌐 Mocking Events

Since 2.7.0

[事件系统]部分支持通过 shouldMockEvents 选项模拟由你的 Rust 代码发出的事件:

🌐 There is partial support of the Event System to simulate events emitted by your Rust code via the shouldMockEvents option:

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' },
});
});

emitToemit_filter 目前被支持。

有时你会有特定于窗口的代码(例如,一个启动画面窗口),因此你需要模拟不同的窗口。你可以使用 mockWindows() 方法来创建虚拟窗口标签。第一个字符串标识“当前”窗口(即你的 JavaScript 自认为所在的窗口),所有其他字符串则被视为附加窗口。

🌐 Sometimes you have window-specific code (a splash screen window, for example), so you need to simulate different windows. You can use the mockWindows() method to create fake window labels. The first string identifies the “current” window (i.e., the window your JavaScript believes itself in), and all other strings are treated as additional windows.

import { beforeAll, expect, test } from 'vitest';
import { randomFillSync } from 'crypto';
import { mockWindows } from '@tauri-apps/api/mocks';
// jsdom doesn't come with a WebCrypto implementation
beforeAll(() => {
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']);
});

Tauri 中文网 - 粤ICP备13048890号
Nodejs.cn 旗下网站