or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-mocking.mdcore-mocking.mdhttp-mocking.mdindex.mdspy-functions.mdsync-mocking.mdsystem-mocking.md

system-mocking.mddocs/

0

# System Mocking

1

2

Mock system-level operations including child process spawning for testing command-line interactions and process execution without actually running external commands.

3

4

## Capabilities

5

6

### Mock Child Process Spawn

7

8

Mock `child_process.spawn()` to simulate process execution with custom exit codes, stdout, and stderr output.

9

10

```typescript { .api }

11

/**

12

* Mock child_process.spawn with custom exit codes and output

13

* @param code - Exit code for the spawned process

14

* @param stdout - Standard output data to emit

15

* @param stderr - Standard error data to emit

16

* @param timeout - Delay before emitting events in milliseconds (default: 0)

17

*/

18

function spawn(code: number, stdout: string, stderr: string, timeout?: number): void;

19

```

20

21

**Usage Examples:**

22

23

```typescript

24

import { spawn as spawnMock } from "mm";

25

import { spawn } from "node:child_process";

26

27

// Mock successful command execution

28

spawnMock(0, "Command executed successfully", "");

29

30

const process = spawn("echo", ["hello world"]);

31

32

process.stdout.on("data", (data) => {

33

console.log(`stdout: ${data}`); // => "stdout: Command executed successfully"

34

});

35

36

process.stderr.on("data", (data) => {

37

console.log(`stderr: ${data}`); // Won't be called (empty stderr)

38

});

39

40

process.on("close", (code) => {

41

console.log(`Process exited with code: ${code}`); // => "Process exited with code: 0"

42

});

43

44

process.on("exit", (code) => {

45

console.log(`Process exit event: ${code}`); // => "Process exit event: 0"

46

});

47

```

48

49

### Mock Command Failures

50

51

Simulate command failures with non-zero exit codes and error output:

52

53

```typescript

54

import { spawn as spawnMock } from "mm";

55

import { spawn } from "node:child_process";

56

57

// Mock command failure

58

spawnMock(1, "", "Command not found");

59

60

const process = spawn("nonexistent-command", ["arg1", "arg2"]);

61

62

process.stdout.on("data", (data) => {

63

// Won't be called (empty stdout)

64

});

65

66

process.stderr.on("data", (data) => {

67

console.log(`Error: ${data}`); // => "Error: Command not found"

68

});

69

70

process.on("close", (code) => {

71

console.log(`Failed with code: ${code}`); // => "Failed with code: 1"

72

});

73

```

74

75

### Mock with Output and Errors

76

77

Simulate processes that produce both stdout and stderr output:

78

79

```typescript

80

import { spawn as spawnMock } from "mm";

81

import { spawn } from "node:child_process";

82

83

// Mock process with mixed output

84

spawnMock(0, "Processing files...\nCompleted successfully", "Warning: deprecated option used");

85

86

const process = spawn("some-tool", ["--process", "files"]);

87

88

process.stdout.on("data", (data) => {

89

console.log(`Output: ${data}`);

90

// => "Output: Processing files...

91

// Completed successfully"

92

});

93

94

process.stderr.on("data", (data) => {

95

console.log(`Warning: ${data}`);

96

// => "Warning: Warning: deprecated option used"

97

});

98

99

process.on("close", (code) => {

100

console.log(`Process completed with code: ${code}`); // => 0

101

});

102

```

103

104

### Mock with Timing

105

106

Simulate delayed process execution and output timing:

107

108

```typescript

109

import { spawn as spawnMock } from "mm";

110

import { spawn } from "node:child_process";

111

112

// Mock slow command with 2 second delay

113

spawnMock(0, "Long running task completed", "", 2000);

114

115

console.log("Starting process...");

116

const process = spawn("slow-command", []);

117

118

process.on("close", (code) => {

119

console.log("Process finished after delay"); // Logs after 2 seconds

120

});

121

```

122

123

## Event Emission Sequence

124

125

The mocked spawn process emits events in the following order:

126

127

1. **stdout event** (if stdout data provided)

128

2. **stderr event** (if stderr data provided)

129

3. **close event** (with exit code)

130

4. **exit event** (with exit code)

131

132

```typescript

133

import { spawn as spawnMock } from "mm";

134

import { spawn } from "node:child_process";

135

136

spawnMock(0, "output", "error");

137

138

const process = spawn("test-command", []);

139

140

process.stdout.on("data", () => console.log("1. stdout"));

141

process.stderr.on("data", () => console.log("2. stderr"));

142

process.on("close", () => console.log("3. close"));

143

process.on("exit", () => console.log("4. exit"));

144

145

// Output:

146

// 1. stdout

147

// 2. stderr

148

// 3. close

149

// 4. exit

150

```

151

152

## Integration Patterns

153

154

### Testing Command Line Tools

155

156

Mock command execution for testing CLI-dependent code:

157

158

```typescript

159

import { spawn as spawnMock, restore } from "mm";

160

161

class GitHelper {

162

async getCurrentBranch(): Promise<string> {

163

return new Promise((resolve, reject) => {

164

const process = spawn("git", ["branch", "--show-current"]);

165

let output = "";

166

167

process.stdout.on("data", (data) => {

168

output += data.toString();

169

});

170

171

process.on("close", (code) => {

172

if (code === 0) {

173

resolve(output.trim());

174

} else {

175

reject(new Error("Git command failed"));

176

}

177

});

178

});

179

}

180

}

181

182

// Test the GitHelper

183

async function testGitHelper() {

184

const gitHelper = new GitHelper();

185

186

// Mock successful git command

187

spawnMock(0, "main\n", "");

188

const branch = await gitHelper.getCurrentBranch();

189

console.log(branch); // => "main"

190

191

restore();

192

193

// Mock git command failure

194

spawnMock(128, "", "fatal: not a git repository");

195

try {

196

await gitHelper.getCurrentBranch();

197

} catch (err) {

198

console.log(err.message); // => "Git command failed"

199

}

200

}

201

```

202

203

### Mock Different Exit Codes

204

205

Test handling of various exit codes:

206

207

```typescript

208

import { spawn as spawnMock } from "mm";

209

210

// Success

211

spawnMock(0, "Success", "");

212

213

// General error

214

spawnMock(1, "", "General error");

215

216

// Command not found

217

spawnMock(127, "", "Command not found");

218

219

// Permission denied

220

spawnMock(126, "", "Permission denied");

221

222

// Interrupted (Ctrl+C)

223

spawnMock(130, "Partial output", "Interrupted");

224

```

225

226

### Mock Long-Running Processes

227

228

Simulate processes that take time to complete:

229

230

```typescript

231

import { spawn as spawnMock } from "mm";

232

233

class ProcessManager {

234

async runBuild(): Promise<void> {

235

return new Promise((resolve, reject) => {

236

console.log("Starting build...");

237

238

const process = spawn("npm", ["run", "build"]);

239

240

process.stdout.on("data", (data) => {

241

console.log(`Build: ${data}`);

242

});

243

244

process.on("close", (code) => {

245

if (code === 0) {

246

console.log("Build completed successfully");

247

resolve();

248

} else {

249

reject(new Error(`Build failed with code ${code}`));

250

}

251

});

252

});

253

}

254

}

255

256

// Test with delayed mock

257

async function testBuild() {

258

const manager = new ProcessManager();

259

260

// Mock build process with 3 second delay

261

spawnMock(0, "Building project...\nBuild successful!", "", 3000);

262

263

await manager.runBuild();

264

// Output after 3 seconds:

265

// Starting build...

266

// Build: Building project...

267

// Build successful!

268

// Build completed successfully

269

}

270

```

271

272

## Error Simulation Patterns

273

274

### Network-Related Command Failures

275

276

```typescript

277

import { spawn as spawnMock } from "mm";

278

279

// Mock network timeout

280

spawnMock(124, "", "curl: (28) Operation timed out");

281

282

// Mock DNS resolution failure

283

spawnMock(6, "", "curl: (6) Could not resolve host");

284

285

// Mock connection refused

286

spawnMock(7, "", "curl: (7) Failed to connect to host");

287

```

288

289

### File System Command Failures

290

291

```typescript

292

import { spawn as spawnMock } from "mm";

293

294

// Mock file not found

295

spawnMock(2, "", "cat: file.txt: No such file or directory");

296

297

// Mock permission denied

298

spawnMock(1, "", "mkdir: cannot create directory 'restricted': Permission denied");

299

300

// Mock disk full

301

spawnMock(1, "", "cp: error writing 'destination': No space left on device");

302

```

303

304

## Testing Process Event Handlers

305

306

Mock processes to test event handling code:

307

308

```typescript

309

import { spawn as spawnMock } from "mm";

310

311

class ProcessMonitor {

312

monitorProcess(command: string, args: string[]): Promise<ProcessResult> {

313

return new Promise((resolve) => {

314

const process = spawn(command, args);

315

const result: ProcessResult = {

316

stdout: "",

317

stderr: "",

318

exitCode: 0

319

};

320

321

process.stdout.on("data", (data) => {

322

result.stdout += data.toString();

323

});

324

325

process.stderr.on("data", (data) => {

326

result.stderr += data.toString();

327

});

328

329

process.on("close", (code) => {

330

result.exitCode = code;

331

resolve(result);

332

});

333

});

334

}

335

}

336

337

// Test the monitor

338

async function testMonitor() {

339

const monitor = new ProcessMonitor();

340

341

spawnMock(0, "Hello World", "Debug info");

342

343

const result = await monitor.monitorProcess("echo", ["Hello World"]);

344

console.log(result);

345

// => { stdout: "Hello World", stderr: "Debug info", exitCode: 0 }

346

}

347

```

348

349

## Types

350

351

```typescript { .api }

352

// Exit codes commonly used in process mocking

353

interface CommonExitCodes {

354

SUCCESS: 0;

355

GENERAL_ERROR: 1;

356

MISUSE_OF_SHELL_BUILTINS: 2;

357

PERMISSION_DENIED: 126;

358

COMMAND_NOT_FOUND: 127;

359

INVALID_EXIT_ARGUMENT: 128;

360

TERMINATED_BY_CTRL_C: 130;

361

}

362

363

// Process result structure for testing

364

interface ProcessResult {

365

stdout: string;

366

stderr: string;

367

exitCode: number;

368

}

369

```