or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-lifecycle.mdcore-ipc.mdevents.mdindex.mdmenu-system.mdsystem-integration.mdtesting.mdutilities.mdwindow-management.md

testing.mddocs/

0

# Testing & Mocks

1

2

Mock implementations and testing utilities for developing and testing Tauri applications without requiring the full Tauri runtime environment.

3

4

## Capabilities

5

6

### IPC Mocking

7

8

Mock the core IPC (Inter-Process Communication) system to simulate backend responses during testing.

9

10

```typescript { .api }

11

/**

12

* Mock the IPC system with custom command handlers

13

* @param cb - Function to handle mocked IPC commands

14

* @param options - Optional configuration for mocking behavior

15

*/

16

function mockIPC(

17

cb: (cmd: string, payload?: InvokeArgs) => unknown,

18

options?: MockIPCOptions

19

): void;

20

21

interface MockIPCOptions {

22

/** Whether to mock event system as well */

23

shouldMockEvents?: boolean;

24

}

25

26

type InvokeArgs = Record<string, unknown> | number[] | ArrayBuffer | Uint8Array;

27

```

28

29

### Window Mocking

30

31

Mock window instances and labels for testing window-related functionality.

32

33

```typescript { .api }

34

/**

35

* Mock window instances for testing

36

* @param current - Label of the current window

37

* @param additionalWindows - Labels of additional windows to mock

38

*/

39

function mockWindows(current: string, ...additionalWindows: string[]): void;

40

```

41

42

### File Source Conversion Mocking

43

44

Mock file path to URL conversion for testing asset loading.

45

46

```typescript { .api }

47

/**

48

* Mock file source conversion for testing

49

* @param osName - Operating system name to simulate ('linux', 'darwin', 'windows')

50

*/

51

function mockConvertFileSrc(osName: string): void;

52

```

53

54

### Mock Cleanup

55

56

Clear all active mocks and restore normal Tauri behavior.

57

58

```typescript { .api }

59

/**

60

* Clear all mocks and restore normal Tauri functionality

61

*/

62

function clearMocks(): void;

63

```

64

65

## Usage Examples

66

67

### Basic IPC Mocking

68

69

```typescript

70

import { mockIPC, invoke } from '@tauri-apps/api/core';

71

import { clearMocks } from '@tauri-apps/api/mocks';

72

73

// Mock IPC commands for testing

74

mockIPC((cmd, args) => {

75

switch (cmd) {

76

case 'get_user_data':

77

return { name: 'Test User', email: 'test@example.com' };

78

case 'save_file':

79

console.log('Mock: Saving file', args);

80

return { success: true, path: '/mock/path/file.txt' };

81

case 'calculate':

82

const { a, b } = args as { a: number; b: number };

83

return { result: a + b };

84

default:

85

throw new Error(`Unknown command: ${cmd}`);

86

}

87

});

88

89

// Test the application code

90

async function testUserData() {

91

const userData = await invoke('get_user_data');

92

console.log('User data:', userData); // { name: 'Test User', email: 'test@example.com' }

93

94

const saveResult = await invoke('save_file', { content: 'Hello', filename: 'test.txt' });

95

console.log('Save result:', saveResult); // { success: true, path: '/mock/path/file.txt' }

96

97

const calcResult = await invoke('calculate', { a: 5, b: 3 });

98

console.log('Calculation:', calcResult); // { result: 8 }

99

}

100

101

await testUserData();

102

103

// Clean up mocks

104

clearMocks();

105

```

106

107

### Testing with Mock Events

108

109

```typescript

110

import { mockIPC } from '@tauri-apps/api/mocks';

111

import { listen, emit } from '@tauri-apps/api/event';

112

113

// Mock IPC with events enabled

114

mockIPC((cmd, args) => {

115

if (cmd === 'start_background_task') {

116

// Simulate background task that emits progress events

117

setTimeout(() => emit('task-progress', { progress: 0.5 }), 100);

118

setTimeout(() => emit('task-complete', { result: 'done' }), 200);

119

return { taskId: 'mock-task-123' };

120

}

121

return null;

122

}, { shouldMockEvents: true });

123

124

// Test event-driven functionality

125

async function testBackgroundTask() {

126

// Set up event listeners

127

const progressListener = await listen('task-progress', (event) => {

128

console.log('Progress:', event.payload.progress);

129

});

130

131

const completeListener = await listen('task-complete', (event) => {

132

console.log('Task complete:', event.payload.result);

133

progressListener(); // Clean up listener

134

completeListener();

135

});

136

137

// Start the task

138

const result = await invoke('start_background_task', { data: 'test' });

139

console.log('Task started:', result);

140

}

141

142

await testBackgroundTask();

143

clearMocks();

144

```

145

146

### Window Mocking for Testing

147

148

```typescript

149

import { mockWindows } from '@tauri-apps/api/mocks';

150

import { getCurrentWindow, Window } from '@tauri-apps/api/window';

151

152

// Mock multiple windows

153

mockWindows('main-window', 'settings-window', 'about-window');

154

155

async function testWindowFunctionality() {

156

// Get current window (will be 'main-window')

157

const currentWindow = getCurrentWindow();

158

console.log('Current window label:', currentWindow.label); // 'main-window'

159

160

// Get all windows

161

const allWindows = await Window.getAll();

162

console.log('All windows:', allWindows.map(w => w.label));

163

// ['main-window', 'settings-window', 'about-window']

164

165

// Get specific window

166

const settingsWindow = await Window.getByLabel('settings-window');

167

console.log('Settings window found:', settingsWindow !== null); // true

168

169

// Test window operations (these will be no-ops in mock)

170

await currentWindow.setTitle('Test Title');

171

await currentWindow.setSize({ width: 800, height: 600 });

172

}

173

174

await testWindowFunctionality();

175

clearMocks();

176

```

177

178

### File Source Mocking

179

180

```typescript

181

import { mockConvertFileSrc } from '@tauri-apps/api/mocks';

182

import { convertFileSrc } from '@tauri-apps/api/core';

183

184

// Mock file conversion for different platforms

185

mockConvertFileSrc('linux');

186

187

function testFileConversion() {

188

const linuxPath = convertFileSrc('/home/user/image.png');

189

console.log('Linux path:', linuxPath); // Mock Linux-style conversion

190

191

clearMocks();

192

mockConvertFileSrc('windows');

193

194

const windowsPath = convertFileSrc('C:\\Users\\User\\image.png');

195

console.log('Windows path:', windowsPath); // Mock Windows-style conversion

196

197

clearMocks();

198

mockConvertFileSrc('darwin');

199

200

const macPath = convertFileSrc('/Users/user/image.png');

201

console.log('macOS path:', macPath); // Mock macOS-style conversion

202

}

203

204

testFileConversion();

205

clearMocks();

206

```

207

208

### Jest Testing Integration

209

210

```typescript

211

// test-utils.ts

212

import { mockIPC, mockWindows, clearMocks } from '@tauri-apps/api/mocks';

213

214

export function setupTauriMocks() {

215

// Mock basic IPC commands

216

mockIPC((cmd, args) => {

217

switch (cmd) {

218

case 'get_config':

219

return { theme: 'dark', language: 'en' };

220

case 'set_config':

221

return { success: true };

222

case 'get_version':

223

return '1.0.0';

224

default:

225

return null;

226

}

227

});

228

229

// Mock windows

230

mockWindows('main');

231

}

232

233

export function teardownTauriMocks() {

234

clearMocks();

235

}

236

237

// app.test.ts

238

import { setupTauriMocks, teardownTauriMocks } from './test-utils';

239

import { invoke } from '@tauri-apps/api/core';

240

241

describe('Application Tests', () => {

242

beforeEach(() => {

243

setupTauriMocks();

244

});

245

246

afterEach(() => {

247

teardownTauriMocks();

248

});

249

250

test('should load configuration', async () => {

251

const config = await invoke('get_config');

252

expect(config).toEqual({ theme: 'dark', language: 'en' });

253

});

254

255

test('should save configuration', async () => {

256

const result = await invoke('set_config', { theme: 'light' });

257

expect(result).toEqual({ success: true });

258

});

259

260

test('should get version', async () => {

261

const version = await invoke('get_version');

262

expect(version).toBe('1.0.0');

263

});

264

});

265

```

266

267

### Advanced Mock Scenarios

268

269

```typescript

270

import { mockIPC } from '@tauri-apps/api/mocks';

271

272

// Mock complex async operations

273

mockIPC(async (cmd, args) => {

274

switch (cmd) {

275

case 'fetch_data':

276

// Simulate network delay

277

await new Promise(resolve => setTimeout(resolve, 100));

278

return { data: ['item1', 'item2', 'item3'] };

279

280

case 'upload_file':

281

// Simulate file upload with progress

282

const { file } = args as { file: string };

283

await new Promise(resolve => setTimeout(resolve, 50));

284

return {

285

success: true,

286

url: `https://example.com/files/${file}`,

287

size: 1024

288

};

289

290

case 'database_query':

291

// Simulate database operations

292

const { query } = args as { query: string };

293

if (query.includes('SELECT')) {

294

return { rows: [{ id: 1, name: 'Test' }] };

295

} else if (query.includes('INSERT')) {

296

return { insertedId: 42 };

297

}

298

throw new Error('Invalid query');

299

300

default:

301

throw new Error(`Command not mocked: ${cmd}`);

302

}

303

});

304

305

// Test error scenarios

306

async function testErrorHandling() {

307

try {

308

await invoke('invalid_command');

309

} catch (error) {

310

console.log('Expected error:', error.message); // "Command not mocked: invalid_command"

311

}

312

313

try {

314

await invoke('database_query', { query: 'DROP TABLE users' });

315

} catch (error) {

316

console.log('Database error:', error.message); // "Invalid query"

317

}

318

}

319

320

await testErrorHandling();

321

```

322

323

### Mock State Management

324

325

```typescript

326

import { mockIPC } from '@tauri-apps/api/mocks';

327

328

// Create stateful mocks

329

class MockDatabase {

330

private data: Record<string, any> = {};

331

332

get(key: string) {

333

return this.data[key] || null;

334

}

335

336

set(key: string, value: any) {

337

this.data[key] = value;

338

return { success: true };

339

}

340

341

list() {

342

return Object.keys(this.data);

343

}

344

345

clear() {

346

this.data = {};

347

return { success: true };

348

}

349

}

350

351

const mockDb = new MockDatabase();

352

353

mockIPC((cmd, args) => {

354

switch (cmd) {

355

case 'db_get':

356

const { key } = args as { key: string };

357

return mockDb.get(key);

358

359

case 'db_set':

360

const { key: setKey, value } = args as { key: string; value: any };

361

return mockDb.set(setKey, value);

362

363

case 'db_list':

364

return mockDb.list();

365

366

case 'db_clear':

367

return mockDb.clear();

368

369

default:

370

return null;

371

}

372

});

373

374

// Test stateful operations

375

async function testStatefulMocks() {

376

// Set some data

377

await invoke('db_set', { key: 'user:1', value: { name: 'Alice' } });

378

await invoke('db_set', { key: 'user:2', value: { name: 'Bob' } });

379

380

// Retrieve data

381

const user1 = await invoke('db_get', { key: 'user:1' });

382

console.log('User 1:', user1); // { name: 'Alice' }

383

384

// List keys

385

const keys = await invoke('db_list');

386

console.log('Keys:', keys); // ['user:1', 'user:2']

387

388

// Clear all data

389

await invoke('db_clear');

390

const keysAfterClear = await invoke('db_list');

391

console.log('Keys after clear:', keysAfterClear); // []

392

}

393

394

await testStatefulMocks();

395

```

396

397

### Testing Best Practices

398

399

```typescript

400

import { mockIPC, mockWindows, clearMocks } from '@tauri-apps/api/mocks';

401

402

// Utility for consistent mock setup

403

export class TauriTestEnvironment {

404

private mockHandlers = new Map<string, Function>();

405

406

mockCommand(cmd: string, handler: Function) {

407

this.mockHandlers.set(cmd, handler);

408

}

409

410

setup() {

411

mockIPC((cmd, args) => {

412

const handler = this.mockHandlers.get(cmd);

413

if (handler) {

414

return handler(args);

415

}

416

throw new Error(`Unmocked command: ${cmd}`);

417

});

418

419

mockWindows('main-window');

420

}

421

422

teardown() {

423

clearMocks();

424

this.mockHandlers.clear();

425

}

426

}

427

428

// Usage in tests

429

describe('Feature Tests', () => {

430

let testEnv: TauriTestEnvironment;

431

432

beforeEach(() => {

433

testEnv = new TauriTestEnvironment();

434

435

// Set up common mocks

436

testEnv.mockCommand('get_config', () => ({ theme: 'light' }));

437

testEnv.mockCommand('save_config', () => ({ success: true }));

438

439

testEnv.setup();

440

});

441

442

afterEach(() => {

443

testEnv.teardown();

444

});

445

446

test('feature specific test', async () => {

447

// Add feature-specific mocks

448

testEnv.mockCommand('feature_command', (args) => {

449

return { result: `processed ${args.input}` };

450

});

451

452

// Test the feature

453

const result = await invoke('feature_command', { input: 'test' });

454

expect(result.result).toBe('processed test');

455

});

456

});

457

```

458

459

## Mock Limitations

460

461

The mocking system has some limitations to be aware of:

462

463

- **Window operations**: Mocked windows don't actually create system windows

464

- **File system**: File operations still need proper mocking at the command level

465

- **Platform APIs**: Platform-specific features may not be fully mockable

466

- **Event timing**: Event emission timing is simplified in mocks

467

- **Resource management**: Mocked resources don't have the same lifecycle as real ones

468

469

For comprehensive testing, combine Tauri mocks with other testing tools and consider running integration tests with the actual Tauri runtime when possible.