doc-testing
Comprehensive guide for writing tests in magenta.nvim, including test environment setup, mock providers, driver interactions, and best practices
Install
mkdir -p .claude/skills/doc-testing && curl -L -o skill.zip "https://mcp.directory/api/skills/download/3175" && unzip -o skill.zip -d .claude/skills/doc-testing && rm skill.zipInstalls to .claude/skills/doc-testing
About this skill
Testing in magenta.nvim
To run the full test suite, use npx vitest run from the project root. You do not need to cd.
To run a specific test file, use npx vitest run <file>. Important You do not need to cd.
Test files should use the .test.ts extension (e.g., myFeature.test.ts).
Tests should make use of the node/test/preamble.ts helpers.
When doing integration-level testing, like user flows, use the withDriver helper and the interactions in node/test/driver.ts. When performing generic user actions that may be reusable between tests, put them into the NvimDriver class as helpers.
As of July 2025, tests are now run in parallel for improved performance. The test infrastructure has been updated to support concurrent test execution.
Test Environment Setup
Fixture Files & Directory Structure:
- Each test gets a fresh temporary directory in
/tmp/magenta-test/{testId}/ - Files from
node/test/fixtures/are copied into this temp directory for each test - Available fixture files include
poem.txt,test.jpg,sample2.pdf,test.bin, and others - Nvim runs in this temporary directory, so files can be safely mutated during tests
- The temp directory is automatically cleaned up after each test - no manual cleanup needed
- Use
await getcwd(driver.nvim)to get the current working directory for file path operations - The temporary directory is completely isolated between tests
Test Pattern:
import { withDriver } from "../test/preamble";
test("my test", async () => {
await withDriver({}, async (driver) => {
// Test code here - nvim runs in temp dir with fixture files
// Access cwd with: const cwd = await getcwd(driver.nvim)
});
});
Custom File Setup:
test("test with custom files", async () => {
await withDriver(
{
setupFiles: async (tmpDir) => {
const fs = await import("fs/promises");
const path = await import("path");
await fs.writeFile(path.join(tmpDir, "custom.txt"), "content");
await fs.mkdir(path.join(tmpDir, "subfolder"));
},
},
async (driver) => {
// Custom files are now available in the test environment
},
);
});
Directory Structure:
The test environment creates an isolated directory structure:
baseDir:/tmp/magenta-test/{testId}/- root of all test directoriestmpDir:{baseDir}/cwd/- the working directory where nvim runs (fixtures copied here)homeDir:{baseDir}/home/- simulated home directory ($HOMEis set to this)
The withDriver callback receives a dirs object with all three paths:
await withDriver({}, async (driver, dirs) => {
console.log(dirs.tmpDir); // /tmp/magenta-test/abc123/cwd
console.log(dirs.homeDir); // /tmp/magenta-test/abc123/home
console.log(dirs.baseDir); // /tmp/magenta-test/abc123
});
Setting Up Home Directory Files:
Use setupHome to create files in the simulated home directory. This is useful for testing features that read from ~/.magenta/ or other home directory paths:
test("test with home directory config", async () => {
await withDriver(
{
setupHome: async (homeDir) => {
const fs = await import("fs/promises");
const path = await import("path");
// Create ~/.magenta/options.json
const magentaDir = path.join(homeDir, ".magenta");
await fs.mkdir(magentaDir, { recursive: true });
await fs.writeFile(
path.join(magentaDir, "options.json"),
JSON.stringify({
filePermissions: [{ path: "~/Documents", read: true }],
}),
);
},
},
async (driver) => {
// Magenta will load options from the simulated ~/.magenta/options.json
},
);
});
Setting Up Directories Outside CWD:
Use setupExtraDirs to create directories outside the working directory. This is useful for testing file permission boundaries:
test("test with external directories", async () => {
let outsidePath: string;
await withDriver(
{
setupExtraDirs: async (baseDir) => {
const fs = await import("fs/promises");
const path = await import("path");
// Create a directory outside cwd
outsidePath = path.join(baseDir, "outside");
await fs.mkdir(outsidePath, { recursive: true });
await fs.writeFile(path.join(outsidePath, "secret.txt"), "secret");
},
},
async (driver, dirs) => {
// outsidePath is outside dirs.tmpDir, so file access should be restricted
// unless explicitly permitted via filePermissions
},
);
});
Combined Setup for Permission Testing:
A common pattern for testing file permissions is to use both setupExtraDirs and setupHome together:
test("can access external dir with filePermissions", async () => {
let outsidePath: string;
await withDriver(
{
setupExtraDirs: async (baseDir) => {
const fs = await import("fs/promises");
const path = await import("path");
outsidePath = path.join(baseDir, "outside");
await fs.mkdir(outsidePath, { recursive: true });
await fs.writeFile(path.join(outsidePath, "allowed.txt"), "content");
// Write options.json here since we now have the path
const homeDir = path.join(baseDir, "home");
const magentaDir = path.join(homeDir, ".magenta");
await fs.mkdir(magentaDir, { recursive: true });
await fs.writeFile(
path.join(magentaDir, "options.json"),
JSON.stringify({
filePermissions: [{ path: outsidePath, read: true }],
}),
);
},
},
async (driver) => {
// Tools can now access outsidePath due to filePermissions
},
);
});
Available Mocks & Test Interactions
Configuring Magenta Options:
Tests can override magenta options by passing them to withDriver:
test("test with custom options", async () => {
await withDriver(
{
options: {
getFileAutoAllowGlobs: ["*.log", "config/*"],
changeDebounceMs: 100,
// Any other MagentaOptions can be overridden here
},
},
async (driver) => {
// Magenta will use the custom options
},
);
});
Available options include:
getFileAutoAllowGlobs- Array of glob patterns for auto-allowing file readschangeDebounceMs- Override the default change tracking debounce- Any other options from
MagentaOptionstype
Mock Provider Interactions:
The mock provider (driver.mockAnthropic) uses MockStream objects that mirror Anthropic's streaming API. Streams contain Anthropic-formatted messages (Anthropic.MessageParam[]), not our internal ProviderMessage[] format.
Required Type Imports for Tests:
import type Anthropic from "@anthropic-ai/sdk";
type ToolResultBlockParam = Anthropic.Messages.ToolResultBlockParam;
type ContentBlockParam = Anthropic.Messages.ContentBlockParam;
type TextBlockParam = Anthropic.Messages.TextBlockParam;
type DocumentBlockParam = Anthropic.Messages.DocumentBlockParam;
Awaiting Streams:
// Wait for any pending stream
const stream = await driver.mockAnthropic.awaitPendingStream();
// Wait for stream with specific text in message content
const stream =
await driver.mockAnthropic.awaitPendingStreamWithText("specific text");
// Wait for user message (tool results, etc.)
const stream = await driver.mockAnthropic.awaitPendingUserRequest();
// Wait for forced tool use requests
const forceRequest =
await driver.mockAnthropic.awaitPendingForceToolUseRequest();
// Check if there's a pending stream with specific text (non-blocking)
const hasPending = driver.mockAnthropic.hasPendingStreamWithText("text");
Responding to Streams:
// Simple text response
stream.respond({
stopReason: "end_turn",
text: "Response text",
toolRequests: [],
});
// Response with tool use
stream.respond({
stopReason: "tool_use",
text: "I'll use a tool",
toolRequests: [
{
status: "ok",
value: {
id: "tool_id" as ToolRequestId,
toolName: "get_file" as ToolName,
input: { filePath: "./file.txt" as UnresolvedFilePath },
},
},
],
});
// Response with error tool request
stream.respond({
stopReason: "tool_use",
text: "Tool failed",
toolRequests: [
{
status: "error",
rawRequest: { invalid: "request" },
},
],
});
Responding to Force Tool Use Requests:
const forceRequest =
await driver.mockAnthropic.awaitPendingForceToolUseRequest();
// Successful tool response
await driver.mockAnthropic.respondToForceToolUse({
toolRequest: {
status: "ok",
value: {
id: "tool_id" as ToolRequestId,
toolName: "get_file" as ToolName,
input: { filePath: "./file.txt" as UnresolvedFilePath },
},
},
stopReason: "tool_use",
});
// Error tool response
await driver.mockAnthropic.respondToForceToolUse({
toolRequest: {
status: "error",
rawRequest: { invalid: "data" },
},
stopReason: "tool_use",
});
Stream Inspection:
// Access stream properties (Anthropic format)
console.log(stream.messages); // Anthropic.MessageParam[] - raw Anthropic format
console.log(stream.getProviderMessages()); // ProviderMessage[] - converted format
console.log(stream.systemPrompt); // System prompt (if any)
// For force tool use requests
console.log(forceRequest.spec); // Tool specification
console.log(forceRequest.model); // Model used
console.log(forceRequest.messages); // Message history
// Check if stream was aborted
if (stream.aborted) {
// Handle aborted stream
}
Advanced Response Patterns:
// Stream individual parts of response
stream.streamText("First part of response");
stream.streamToolUse(toolId, toolName, input);
stream.streamThinking("Thinking content", "signature");
stream.finishRes
---
*Content truncated.*
More by dlants
View all skills by dlants →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
pdf-to-markdown
aliceisjustplaying
Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.
Related MCP Servers
Browse all serversStructured Workflow guides disciplined software engineering via refactoring, feature creation, and test driven developme
AI-ready access to Grafana UI: full React component library—TypeScript source, MDX docs, Storybook examples, tests, and
Discover Modus Design System: comprehensive docs, specs, and guides for React UI library and component implementation in
Zendesk MCP — manage Support, Talk, Chat & Guide via the Zendesk API. Automate tickets, users, organizations and article
Uno Platform — Documentation and prompts for building cross-platform .NET apps with a single codebase. Get guides, sampl
Desktop Commander MCP unifies code management with advanced source control, git, and svn support—streamlining developmen
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.