TypeScript/JavaScript API bindings for Tauri applications providing comprehensive desktop app functionality
—
Mock implementations and testing utilities for developing and testing Tauri applications without requiring the full Tauri runtime environment.
Mock the core IPC (Inter-Process Communication) system to simulate backend responses during testing.
/**
* Mock the IPC system with custom command handlers
* @param cb - Function to handle mocked IPC commands
* @param options - Optional configuration for mocking behavior
*/
function mockIPC(
cb: (cmd: string, payload?: InvokeArgs) => unknown,
options?: MockIPCOptions
): void;
interface MockIPCOptions {
/** Whether to mock event system as well */
shouldMockEvents?: boolean;
}
type InvokeArgs = Record<string, unknown> | number[] | ArrayBuffer | Uint8Array;Mock window instances and labels for testing window-related functionality.
/**
* Mock window instances for testing
* @param current - Label of the current window
* @param additionalWindows - Labels of additional windows to mock
*/
function mockWindows(current: string, ...additionalWindows: string[]): void;Mock file path to URL conversion for testing asset loading.
/**
* Mock file source conversion for testing
* @param osName - Operating system name to simulate ('linux', 'darwin', 'windows')
*/
function mockConvertFileSrc(osName: string): void;Clear all active mocks and restore normal Tauri behavior.
/**
* Clear all mocks and restore normal Tauri functionality
*/
function clearMocks(): void;import { mockIPC, invoke } from '@tauri-apps/api/core';
import { clearMocks } from '@tauri-apps/api/mocks';
// Mock IPC commands for testing
mockIPC((cmd, args) => {
switch (cmd) {
case 'get_user_data':
return { name: 'Test User', email: 'test@example.com' };
case 'save_file':
console.log('Mock: Saving file', args);
return { success: true, path: '/mock/path/file.txt' };
case 'calculate':
const { a, b } = args as { a: number; b: number };
return { result: a + b };
default:
throw new Error(`Unknown command: ${cmd}`);
}
});
// Test the application code
async function testUserData() {
const userData = await invoke('get_user_data');
console.log('User data:', userData); // { name: 'Test User', email: 'test@example.com' }
const saveResult = await invoke('save_file', { content: 'Hello', filename: 'test.txt' });
console.log('Save result:', saveResult); // { success: true, path: '/mock/path/file.txt' }
const calcResult = await invoke('calculate', { a: 5, b: 3 });
console.log('Calculation:', calcResult); // { result: 8 }
}
await testUserData();
// Clean up mocks
clearMocks();import { mockIPC } from '@tauri-apps/api/mocks';
import { listen, emit } from '@tauri-apps/api/event';
// Mock IPC with events enabled
mockIPC((cmd, args) => {
if (cmd === 'start_background_task') {
// Simulate background task that emits progress events
setTimeout(() => emit('task-progress', { progress: 0.5 }), 100);
setTimeout(() => emit('task-complete', { result: 'done' }), 200);
return { taskId: 'mock-task-123' };
}
return null;
}, { shouldMockEvents: true });
// Test event-driven functionality
async function testBackgroundTask() {
// Set up event listeners
const progressListener = await listen('task-progress', (event) => {
console.log('Progress:', event.payload.progress);
});
const completeListener = await listen('task-complete', (event) => {
console.log('Task complete:', event.payload.result);
progressListener(); // Clean up listener
completeListener();
});
// Start the task
const result = await invoke('start_background_task', { data: 'test' });
console.log('Task started:', result);
}
await testBackgroundTask();
clearMocks();import { mockWindows } from '@tauri-apps/api/mocks';
import { getCurrentWindow, Window } from '@tauri-apps/api/window';
// Mock multiple windows
mockWindows('main-window', 'settings-window', 'about-window');
async function testWindowFunctionality() {
// Get current window (will be 'main-window')
const currentWindow = getCurrentWindow();
console.log('Current window label:', currentWindow.label); // 'main-window'
// Get all windows
const allWindows = await Window.getAll();
console.log('All windows:', allWindows.map(w => w.label));
// ['main-window', 'settings-window', 'about-window']
// Get specific window
const settingsWindow = await Window.getByLabel('settings-window');
console.log('Settings window found:', settingsWindow !== null); // true
// Test window operations (these will be no-ops in mock)
await currentWindow.setTitle('Test Title');
await currentWindow.setSize({ width: 800, height: 600 });
}
await testWindowFunctionality();
clearMocks();import { mockConvertFileSrc } from '@tauri-apps/api/mocks';
import { convertFileSrc } from '@tauri-apps/api/core';
// Mock file conversion for different platforms
mockConvertFileSrc('linux');
function testFileConversion() {
const linuxPath = convertFileSrc('/home/user/image.png');
console.log('Linux path:', linuxPath); // Mock Linux-style conversion
clearMocks();
mockConvertFileSrc('windows');
const windowsPath = convertFileSrc('C:\\Users\\User\\image.png');
console.log('Windows path:', windowsPath); // Mock Windows-style conversion
clearMocks();
mockConvertFileSrc('darwin');
const macPath = convertFileSrc('/Users/user/image.png');
console.log('macOS path:', macPath); // Mock macOS-style conversion
}
testFileConversion();
clearMocks();// test-utils.ts
import { mockIPC, mockWindows, clearMocks } from '@tauri-apps/api/mocks';
export function setupTauriMocks() {
// Mock basic IPC commands
mockIPC((cmd, args) => {
switch (cmd) {
case 'get_config':
return { theme: 'dark', language: 'en' };
case 'set_config':
return { success: true };
case 'get_version':
return '1.0.0';
default:
return null;
}
});
// Mock windows
mockWindows('main');
}
export function teardownTauriMocks() {
clearMocks();
}
// app.test.ts
import { setupTauriMocks, teardownTauriMocks } from './test-utils';
import { invoke } from '@tauri-apps/api/core';
describe('Application Tests', () => {
beforeEach(() => {
setupTauriMocks();
});
afterEach(() => {
teardownTauriMocks();
});
test('should load configuration', async () => {
const config = await invoke('get_config');
expect(config).toEqual({ theme: 'dark', language: 'en' });
});
test('should save configuration', async () => {
const result = await invoke('set_config', { theme: 'light' });
expect(result).toEqual({ success: true });
});
test('should get version', async () => {
const version = await invoke('get_version');
expect(version).toBe('1.0.0');
});
});import { mockIPC } from '@tauri-apps/api/mocks';
// Mock complex async operations
mockIPC(async (cmd, args) => {
switch (cmd) {
case 'fetch_data':
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, 100));
return { data: ['item1', 'item2', 'item3'] };
case 'upload_file':
// Simulate file upload with progress
const { file } = args as { file: string };
await new Promise(resolve => setTimeout(resolve, 50));
return {
success: true,
url: `https://example.com/files/${file}`,
size: 1024
};
case 'database_query':
// Simulate database operations
const { query } = args as { query: string };
if (query.includes('SELECT')) {
return { rows: [{ id: 1, name: 'Test' }] };
} else if (query.includes('INSERT')) {
return { insertedId: 42 };
}
throw new Error('Invalid query');
default:
throw new Error(`Command not mocked: ${cmd}`);
}
});
// Test error scenarios
async function testErrorHandling() {
try {
await invoke('invalid_command');
} catch (error) {
console.log('Expected error:', error.message); // "Command not mocked: invalid_command"
}
try {
await invoke('database_query', { query: 'DROP TABLE users' });
} catch (error) {
console.log('Database error:', error.message); // "Invalid query"
}
}
await testErrorHandling();import { mockIPC } from '@tauri-apps/api/mocks';
// Create stateful mocks
class MockDatabase {
private data: Record<string, any> = {};
get(key: string) {
return this.data[key] || null;
}
set(key: string, value: any) {
this.data[key] = value;
return { success: true };
}
list() {
return Object.keys(this.data);
}
clear() {
this.data = {};
return { success: true };
}
}
const mockDb = new MockDatabase();
mockIPC((cmd, args) => {
switch (cmd) {
case 'db_get':
const { key } = args as { key: string };
return mockDb.get(key);
case 'db_set':
const { key: setKey, value } = args as { key: string; value: any };
return mockDb.set(setKey, value);
case 'db_list':
return mockDb.list();
case 'db_clear':
return mockDb.clear();
default:
return null;
}
});
// Test stateful operations
async function testStatefulMocks() {
// Set some data
await invoke('db_set', { key: 'user:1', value: { name: 'Alice' } });
await invoke('db_set', { key: 'user:2', value: { name: 'Bob' } });
// Retrieve data
const user1 = await invoke('db_get', { key: 'user:1' });
console.log('User 1:', user1); // { name: 'Alice' }
// List keys
const keys = await invoke('db_list');
console.log('Keys:', keys); // ['user:1', 'user:2']
// Clear all data
await invoke('db_clear');
const keysAfterClear = await invoke('db_list');
console.log('Keys after clear:', keysAfterClear); // []
}
await testStatefulMocks();import { mockIPC, mockWindows, clearMocks } from '@tauri-apps/api/mocks';
// Utility for consistent mock setup
export class TauriTestEnvironment {
private mockHandlers = new Map<string, Function>();
mockCommand(cmd: string, handler: Function) {
this.mockHandlers.set(cmd, handler);
}
setup() {
mockIPC((cmd, args) => {
const handler = this.mockHandlers.get(cmd);
if (handler) {
return handler(args);
}
throw new Error(`Unmocked command: ${cmd}`);
});
mockWindows('main-window');
}
teardown() {
clearMocks();
this.mockHandlers.clear();
}
}
// Usage in tests
describe('Feature Tests', () => {
let testEnv: TauriTestEnvironment;
beforeEach(() => {
testEnv = new TauriTestEnvironment();
// Set up common mocks
testEnv.mockCommand('get_config', () => ({ theme: 'light' }));
testEnv.mockCommand('save_config', () => ({ success: true }));
testEnv.setup();
});
afterEach(() => {
testEnv.teardown();
});
test('feature specific test', async () => {
// Add feature-specific mocks
testEnv.mockCommand('feature_command', (args) => {
return { result: `processed ${args.input}` };
});
// Test the feature
const result = await invoke('feature_command', { input: 'test' });
expect(result.result).toBe('processed test');
});
});The mocking system has some limitations to be aware of:
For comprehensive testing, combine Tauri mocks with other testing tools and consider running integration tests with the actual Tauri runtime when possible.
Install with Tessl CLI
npx tessl i tessl/npm-tauri-apps--api