CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-mm

Mock mate library for mocking functions, HTTP requests, and file system operations in Node.js testing

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

system-mocking.mddocs/

System Mocking

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

Capabilities

Mock Child Process Spawn

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"
});

Mock Command Failures

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"
});

Mock with Output and Errors

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
});

Mock with Timing

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
});

Event Emission Sequence

The mocked spawn process emits events in the following order:

  1. stdout event (if stdout data provided)
  2. stderr event (if stderr data provided)
  3. close event (with exit code)
  4. exit event (with exit code)
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. exit

Integration Patterns

Testing Command Line Tools

Mock 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"
  }
}

Mock Different Exit Codes

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");

Mock Long-Running Processes

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
}

Error Simulation Patterns

Network-Related Command Failures

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");

File System Command Failures

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");

Testing Process Event Handlers

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 }
}

Types

// 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;
}

docs

async-mocking.md

core-mocking.md

http-mocking.md

index.md

spy-functions.md

sync-mocking.md

system-mocking.md

tile.json