Mock mate library for mocking functions, HTTP requests, and file system operations in Node.js testing
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Mock system-level operations including child process spawning for testing command-line interactions and process execution without actually running external commands.
Mock child_process.spawn() to simulate process execution with custom exit codes, stdout, and stderr output.
/**
* Mock child_process.spawn with custom exit codes and output
* @param code - Exit code for the spawned process
* @param stdout - Standard output data to emit
* @param stderr - Standard error data to emit
* @param timeout - Delay before emitting events in milliseconds (default: 0)
*/
function spawn(code: number, stdout: string, stderr: string, timeout?: number): void;Usage Examples:
import { spawn as spawnMock } from "mm";
import { spawn } from "node:child_process";
// Mock successful command execution
spawnMock(0, "Command executed successfully", "");
const process = spawn("echo", ["hello world"]);
process.stdout.on("data", (data) => {
console.log(`stdout: ${data}`); // => "stdout: Command executed successfully"
});
process.stderr.on("data", (data) => {
console.log(`stderr: ${data}`); // Won't be called (empty stderr)
});
process.on("close", (code) => {
console.log(`Process exited with code: ${code}`); // => "Process exited with code: 0"
});
process.on("exit", (code) => {
console.log(`Process exit event: ${code}`); // => "Process exit event: 0"
});Simulate command failures with non-zero exit codes and error output:
import { spawn as spawnMock } from "mm";
import { spawn } from "node:child_process";
// Mock command failure
spawnMock(1, "", "Command not found");
const process = spawn("nonexistent-command", ["arg1", "arg2"]);
process.stdout.on("data", (data) => {
// Won't be called (empty stdout)
});
process.stderr.on("data", (data) => {
console.log(`Error: ${data}`); // => "Error: Command not found"
});
process.on("close", (code) => {
console.log(`Failed with code: ${code}`); // => "Failed with code: 1"
});Simulate processes that produce both stdout and stderr output:
import { spawn as spawnMock } from "mm";
import { spawn } from "node:child_process";
// Mock process with mixed output
spawnMock(0, "Processing files...\nCompleted successfully", "Warning: deprecated option used");
const process = spawn("some-tool", ["--process", "files"]);
process.stdout.on("data", (data) => {
console.log(`Output: ${data}`);
// => "Output: Processing files...
// Completed successfully"
});
process.stderr.on("data", (data) => {
console.log(`Warning: ${data}`);
// => "Warning: Warning: deprecated option used"
});
process.on("close", (code) => {
console.log(`Process completed with code: ${code}`); // => 0
});Simulate delayed process execution and output timing:
import { spawn as spawnMock } from "mm";
import { spawn } from "node:child_process";
// Mock slow command with 2 second delay
spawnMock(0, "Long running task completed", "", 2000);
console.log("Starting process...");
const process = spawn("slow-command", []);
process.on("close", (code) => {
console.log("Process finished after delay"); // Logs after 2 seconds
});The mocked spawn process emits events in the following order:
import { spawn as spawnMock } from "mm";
import { spawn } from "node:child_process";
spawnMock(0, "output", "error");
const process = spawn("test-command", []);
process.stdout.on("data", () => console.log("1. stdout"));
process.stderr.on("data", () => console.log("2. stderr"));
process.on("close", () => console.log("3. close"));
process.on("exit", () => console.log("4. exit"));
// Output:
// 1. stdout
// 2. stderr
// 3. close
// 4. exitMock command execution for testing CLI-dependent code:
import { spawn as spawnMock, restore } from "mm";
class GitHelper {
async getCurrentBranch(): Promise<string> {
return new Promise((resolve, reject) => {
const process = spawn("git", ["branch", "--show-current"]);
let output = "";
process.stdout.on("data", (data) => {
output += data.toString();
});
process.on("close", (code) => {
if (code === 0) {
resolve(output.trim());
} else {
reject(new Error("Git command failed"));
}
});
});
}
}
// Test the GitHelper
async function testGitHelper() {
const gitHelper = new GitHelper();
// Mock successful git command
spawnMock(0, "main\n", "");
const branch = await gitHelper.getCurrentBranch();
console.log(branch); // => "main"
restore();
// Mock git command failure
spawnMock(128, "", "fatal: not a git repository");
try {
await gitHelper.getCurrentBranch();
} catch (err) {
console.log(err.message); // => "Git command failed"
}
}Test handling of various exit codes:
import { spawn as spawnMock } from "mm";
// Success
spawnMock(0, "Success", "");
// General error
spawnMock(1, "", "General error");
// Command not found
spawnMock(127, "", "Command not found");
// Permission denied
spawnMock(126, "", "Permission denied");
// Interrupted (Ctrl+C)
spawnMock(130, "Partial output", "Interrupted");Simulate processes that take time to complete:
import { spawn as spawnMock } from "mm";
class ProcessManager {
async runBuild(): Promise<void> {
return new Promise((resolve, reject) => {
console.log("Starting build...");
const process = spawn("npm", ["run", "build"]);
process.stdout.on("data", (data) => {
console.log(`Build: ${data}`);
});
process.on("close", (code) => {
if (code === 0) {
console.log("Build completed successfully");
resolve();
} else {
reject(new Error(`Build failed with code ${code}`));
}
});
});
}
}
// Test with delayed mock
async function testBuild() {
const manager = new ProcessManager();
// Mock build process with 3 second delay
spawnMock(0, "Building project...\nBuild successful!", "", 3000);
await manager.runBuild();
// Output after 3 seconds:
// Starting build...
// Build: Building project...
// Build successful!
// Build completed successfully
}import { spawn as spawnMock } from "mm";
// Mock network timeout
spawnMock(124, "", "curl: (28) Operation timed out");
// Mock DNS resolution failure
spawnMock(6, "", "curl: (6) Could not resolve host");
// Mock connection refused
spawnMock(7, "", "curl: (7) Failed to connect to host");import { spawn as spawnMock } from "mm";
// Mock file not found
spawnMock(2, "", "cat: file.txt: No such file or directory");
// Mock permission denied
spawnMock(1, "", "mkdir: cannot create directory 'restricted': Permission denied");
// Mock disk full
spawnMock(1, "", "cp: error writing 'destination': No space left on device");Mock processes to test event handling code:
import { spawn as spawnMock } from "mm";
class ProcessMonitor {
monitorProcess(command: string, args: string[]): Promise<ProcessResult> {
return new Promise((resolve) => {
const process = spawn(command, args);
const result: ProcessResult = {
stdout: "",
stderr: "",
exitCode: 0
};
process.stdout.on("data", (data) => {
result.stdout += data.toString();
});
process.stderr.on("data", (data) => {
result.stderr += data.toString();
});
process.on("close", (code) => {
result.exitCode = code;
resolve(result);
});
});
}
}
// Test the monitor
async function testMonitor() {
const monitor = new ProcessMonitor();
spawnMock(0, "Hello World", "Debug info");
const result = await monitor.monitorProcess("echo", ["Hello World"]);
console.log(result);
// => { stdout: "Hello World", stderr: "Debug info", exitCode: 0 }
}// Exit codes commonly used in process mocking
interface CommonExitCodes {
SUCCESS: 0;
GENERAL_ERROR: 1;
MISUSE_OF_SHELL_BUILTINS: 2;
PERMISSION_DENIED: 126;
COMMAND_NOT_FOUND: 127;
INVALID_EXIT_ARGUMENT: 128;
TERMINATED_BY_CTRL_C: 130;
}
// Process result structure for testing
interface ProcessResult {
stdout: string;
stderr: string;
exitCode: number;
}