Skip to content

Commit

Permalink
feat: add mock functions for testing and SSG (#3437)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>
  • Loading branch information
JonasKruckenberg and lucasfernog authored Feb 13, 2022
1 parent 49955ea commit 7e04c07
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changes/mock-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": minor
---

Provide functions to mock IPC calls during testing and static site generation.
146 changes: 146 additions & 0 deletions tooling/api/src/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
interface IPCMessage {
cmd: string
callback: number
error: number
[key: string]: unknown
}

/**
* 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/tauri"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, args) => {
* switch (cmd) {
* case "add":
* return (args.a as number) + (args.b as number);
* default:
* break;
* }
* });
*
* expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
* })
* ```
*
* @param cb
*/
export function mockIPC(
cb: (cmd: string, args: Record<string, unknown>) => any
): void {
window.__TAURI_IPC__ = async ({
cmd,
callback,
error,
...args
}: 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, args))
} 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)
}
}
}

/**
* 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 === "tauri") {
* if (
* args?.__tauriModule === "Window" &&
* args?.message?.cmd === "manage" &&
* args?.message?.data?.cmd?.type === "close"
* ) {
* console.log('closing window!');
* }
* }
* });
*
* const { getCurrent } = await import("@tauri-apps/api/window");
*
* const win = getCurrent();
* await win.close(); // 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.
*/
export function mockWindows(
current: string,
...additionalWindows: string[]
): void {
window.__TAURI_METADATA__ = {
__windows: [current, ...additionalWindows].map((label) => ({ label })),
__currentWindow: { label: current }
}
}

/**
* 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).toHaveProperty("__TAURI_METADATA__")
* })
*
* test("no mocked windows", () => {
* expect(window).not.toHaveProperty("__TAURI_METADATA__")
* })
* ```
*/
export function clearMocks(): void {
// @ts-expect-error
delete window.__TAURI_IPC__
// @ts-expect-error
delete window.__TAURI_METADATA__
}

0 comments on commit 7e04c07

Please sign in to comment.