Skip to main content
Glama
holyfata

Mermaid-Grammer-Inspector

parse.test.ts7.08 kB
/** * Parse module test cases */ import type { ChildProcess } from "node:child_process"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { type ParseResult, ParseStatus, parseMermaid } from "./parse"; // Mock the child_process module vi.mock("node:child_process", () => ({ exec: vi.fn(), })); // Define proper types for the callback type ExecCallback = ( error: Error | null, stdout: string, stderr: string, ) => void; describe("parseMermaid", () => { let mockExec: ReturnType<typeof vi.fn>; beforeEach(async () => { vi.clearAllMocks(); // Get the mocked exec function const childProcess = await import("node:child_process"); mockExec = childProcess.exec as unknown as ReturnType<typeof vi.fn>; }); afterEach(() => { vi.restoreAllMocks(); }); it("should return SUCCESS status when parsing succeeds", async () => { // Mock successful execution mockExec.mockImplementation((_command: string, callback: ExecCallback) => { callback(null, "success output", ""); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.SUCCESS); expect(result.message).toBeUndefined(); }); it("should return FAIL status and error message when parsing fails", async () => { const errorMessage = "Syntax error in mermaid diagram"; mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error(errorMessage); callback(error, "", `Error: ${errorMessage}`); return {} as ChildProcess; }); const result = await parseMermaid("invalid.mmd", "output.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toContain(errorMessage); }); it("should filter out npm warn messages", async () => { const stderr = `npm warn deprecated package@1.0.0 npm WARN old lockfile Error: Parse error on line 1: Unexpected token`; mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error("Command failed"); callback(error, "", stderr); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).not.toContain("npm warn"); expect(result.message).not.toContain("npm WARN"); expect(result.message).toContain("Error: Parse error on line 1:"); }); it("should properly handle stack trace information", async () => { const stderr = `Error: Invalid syntax at Parser.parse (/path/to/parser.js:123:45) at async processFile (/path/to/process.js:67:89)`; mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error("Command failed"); callback(error, "", stderr); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toBe("Error: Invalid syntax"); expect(result.message).not.toContain("at Parser.parse"); }); it("should use default filename parameters", async () => { mockExec.mockImplementation((command: string, callback: ExecCallback) => { expect(command).toContain("input.mmd"); expect(command).toContain("output.svg"); callback(null, "", ""); return {} as ChildProcess; }); await parseMermaid(); expect(mockExec).toHaveBeenCalledWith( expect.stringContaining("input.mmd"), expect.any(Function), ); }); it("should use custom filename parameters", async () => { const customInput = "custom-input.mmd"; const customOutput = "custom-output.svg"; mockExec.mockImplementation((command: string, callback: ExecCallback) => { expect(command).toContain(customInput); expect(command).toContain(customOutput); callback(null, "", ""); return {} as ChildProcess; }); await parseMermaid(customInput, customOutput); expect(mockExec).toHaveBeenCalledWith( expect.stringContaining(customInput), expect.any(Function), ); }); it("should correctly build mmdc command", async () => { mockExec.mockImplementation((command: string, callback: ExecCallback) => { expect(command).toMatch(/npx mmdc -i .+ -o .+/); callback(null, "", ""); return {} as ChildProcess; }); await parseMermaid("test.mmd", "test.svg"); expect(mockExec).toHaveBeenCalled(); }); it("should handle empty error output", async () => { mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error("Unknown error"); callback(error, "", ""); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toBe("Unknown error"); }); it("should handle stderr-only scenarios", async () => { const stderrMessage = "Error: Mermaid parsing failed"; mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error(); callback(error, "", stderrMessage); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toBe(stderrMessage); }); it("should handle complex error output filtering", async () => { const complexStderr = `npm warn deprecated package@1.0.0: This package is deprecated npm WARN old lockfile The package-lock.json file was created with an old version Error: Parse error on line 5: ...graph TD -----------^ Expecting 'NEWLINE', 'SPACE', 'GRAPH', got 'MINUS' at Parser.parseError (/node_modules/mermaid/dist/mermaid.js:1234:56) at Parser.parse (/node_modules/mermaid/dist/mermaid.js:2345:67) at async generateSVG (/node_modules/@mermaid-js/mermaid-cli/src/index.js:123:45)`; mockExec.mockImplementation((_command: string, callback: ExecCallback) => { const error = new Error("Command failed"); callback(error, "", complexStderr); return {} as ChildProcess; }); const result = await parseMermaid("test.mmd", "test.svg"); expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toContain("Error: Parse error on line 5:"); expect(result.message).toContain( "Expecting 'NEWLINE', 'SPACE', 'GRAPH', got 'MINUS'", ); expect(result.message).not.toContain("npm warn"); expect(result.message).not.toContain("at Parser.parseError"); }); }); describe("ParseStatus enum", () => { it("should have correct enum values", () => { expect(ParseStatus.SUCCESS).toBe(0); expect(ParseStatus.FAIL).toBe(1); }); }); describe("ParseResult interface", () => { it("should support success result", () => { const result: ParseResult = { status: ParseStatus.SUCCESS, }; expect(result.status).toBe(ParseStatus.SUCCESS); expect(result.message).toBeUndefined(); }); it("should support failure result", () => { const result: ParseResult = { status: ParseStatus.FAIL, message: "Test error message", }; expect(result.status).toBe(ParseStatus.FAIL); expect(result.message).toBe("Test error message"); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/holyfata/Mermaid-Grammer-Inspector'

If you have feedback or need assistance with the MCP directory API, please join our Discord server