模拟 Tauri API
编写前端测试时,使用 “fake” 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:
:::caution 提醒
请记住在每次测试运行后清除模拟,以撤消运行之间的模拟状态更改!有关更多信息,请参阅 clearMocks()
文档。
¥Remember to clear mocks after each test run to undo mock state changes between runs! See clearMocks()
docs for more info.
:::
IPC 请求
¥IPC Requests
最常见的是,你想要拦截 IPC 请求;这在各种情况下都很有用:
¥Most commonly, you want to intercept IPC requests; this can be helpful in a variety of situations:
-
确保进行了正确的后端调用
¥Ensure the correct backend calls are made
-
模拟来自后端函数的不同结果
¥Simulate different results from backend functions
Tauri 提供了 mockIPC 函数来拦截 IPC 请求。你可以在 此处 中找到有关特定 API 的详细信息。
¥Tauri provides the mockIPC function to intercept IPC requests. You can find more about the specific API in detail here.
:::note 注意
以下示例使用 Vitest,但你可以使用任何其他前端测试库,例如 jest。
¥The following examples use Vitest, but you can use any other frontend testing library such as jest.
:::
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()
与其他监视和模拟工具一起使用来测试这一点:
¥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 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 发出后端将发回的事件:
¥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', }, }); }});
Windows
有时你有特定于窗口的代码(例如,启动画面窗口),因此你需要模拟不同的窗口。你可以使用 mockWindows()
方法创建虚假窗口标签。第一个字符串标识 “current” 窗口(即 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.
:::note 注意
mockWindows()
仅伪造窗口的存在,但没有窗口属性。要模拟窗口属性,你需要使用 mockIPC()
拦截正确的调用
¥mockWindows()
only fakes the existence of windows but no window properties. To simulate window properties, you need to intercept the correct calls using mockIPC()
:::
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']);});
Tauri 中文网 - 粤ICP备13048890号