Skip to main content
Glama
1yhy
by 1yhy
parser.test.ts8.87 kB
/** * Parser Integration Tests * * Tests the complete parsing pipeline from raw Figma API response * to simplified node structure. */ import { describe, it, expect, beforeAll } from "vitest"; import * as fs from "fs"; import * as path from "path"; import { fileURLToPath } from "url"; import { parseFigmaResponse } from "~/core/parser.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const fixturesPath = path.join(__dirname, "../fixtures"); // Load fixtures function loadRawData(): unknown { const dataPath = path.join(fixturesPath, "figma-data/real-node-data.json"); return JSON.parse(fs.readFileSync(dataPath, "utf-8")); } function loadExpectedOutput(): unknown { const dataPath = path.join(fixturesPath, "expected/real-node-data-optimized.json"); return JSON.parse(fs.readFileSync(dataPath, "utf-8")); } describe("Figma Response Parser", () => { let rawData: unknown; let expectedOutput: ReturnType<typeof loadExpectedOutput>; beforeAll(() => { rawData = loadRawData(); expectedOutput = loadExpectedOutput(); }); describe("Basic Parsing", () => { it("should parse raw Figma response", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); expect(result).toBeDefined(); expect(result.name).toBeDefined(); expect(result.nodes).toBeDefined(); expect(Array.isArray(result.nodes)).toBe(true); }); it("should extract file metadata", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); expect(result.name).toBe("Vigilkids产品站"); expect(result.lastModified).toBeDefined(); }); }); describe("Node Structure", () => { it("should preserve node hierarchy", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); expect(result.nodes.length).toBeGreaterThan(0); const rootNode = result.nodes[0]; expect(rootNode.id).toBeDefined(); expect(rootNode.name).toBeDefined(); expect(rootNode.type).toBeDefined(); }); it("should generate CSS styles", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); const rootNode = result.nodes[0]; expect(rootNode.cssStyles).toBeDefined(); expect(rootNode.cssStyles?.width).toBeDefined(); expect(rootNode.cssStyles?.height).toBeDefined(); }); }); describe("Data Compression", () => { it("should significantly reduce data size", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); const originalSize = Buffer.byteLength(JSON.stringify(rawData)); const simplifiedSize = Buffer.byteLength(JSON.stringify(result)); const compressionRate = ((originalSize - simplifiedSize) / originalSize) * 100; // Should achieve at least 70% compression expect(compressionRate).toBeGreaterThan(70); }); }); describe("CSS Style Generation", () => { it("should convert colors to hex format", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); // Find a node with background color const findNodeWithBg = ( nodes: Array<{ cssStyles?: Record<string, unknown>; children?: unknown[] }>, ): Record<string, unknown> | null => { for (const node of nodes) { if (node.cssStyles?.backgroundColor) { return node.cssStyles; } if (node.children) { const found = findNodeWithBg( node.children as Array<{ cssStyles?: Record<string, unknown>; children?: unknown[] }>, ); if (found) return found; } } return null; }; const styles = findNodeWithBg(result.nodes); if (styles?.backgroundColor) { expect(styles.backgroundColor).toMatch(/^#[A-Fa-f0-9]{6}$/); } }); it("should round pixel values to integers", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); const rootNode = result.nodes[0]; const width = rootNode.cssStyles?.width as string; const height = rootNode.cssStyles?.height as string; // Should be integer pixel values expect(width).toMatch(/^\d+px$/); expect(height).toMatch(/^\d+px$/); }); }); describe("Layout Detection Integration", () => { it("should detect flex layouts in appropriate nodes", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); // Find nodes with flex properties const findFlexNode = ( nodes: Array<{ cssStyles?: Record<string, unknown>; children?: unknown[] }>, ): Record<string, unknown> | null => { for (const node of nodes) { if (node.cssStyles?.display === "flex") { return node.cssStyles; } if (node.children) { const found = findFlexNode( node.children as Array<{ cssStyles?: Record<string, unknown>; children?: unknown[] }>, ); if (found) return found; } } return null; }; const flexStyles = findFlexNode(result.nodes); if (flexStyles) { expect(flexStyles.display).toBe("flex"); expect(flexStyles.flexDirection).toBeDefined(); } }); }); describe("Icon Detection Integration", () => { it("should mark icon nodes with exportInfo", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); // Find nodes with export info const findExportNode = ( nodes: Array<{ exportInfo?: unknown; children?: unknown[] }>, ): unknown | null => { for (const node of nodes) { if (node.exportInfo) { return node.exportInfo; } if (node.children) { const found = findExportNode( node.children as Array<{ exportInfo?: unknown; children?: unknown[] }>, ); if (found) return found; } } return null; }; const exportInfo = findExportNode(result.nodes); if (exportInfo) { expect(exportInfo).toHaveProperty("type"); expect(exportInfo).toHaveProperty("format"); expect(exportInfo).toHaveProperty("fileName"); } }); }); describe("Text Node Processing", () => { it("should extract text content", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); // Find text nodes const findTextNode = ( nodes: Array<{ type?: string; text?: string; children?: unknown[] }>, ): { text?: string } | null => { for (const node of nodes) { if (node.type === "TEXT" && node.text) { return node; } if (node.children) { const found = findTextNode( node.children as Array<{ type?: string; text?: string; children?: unknown[] }>, ); if (found) return found; } } return null; }; const textNode = findTextNode(result.nodes); if (textNode) { expect(textNode.text).toBeDefined(); expect(typeof textNode.text).toBe("string"); } }); it("should include font styles for text nodes", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); const findTextStyles = ( nodes: Array<{ type?: string; cssStyles?: Record<string, unknown>; children?: unknown[] }>, ): Record<string, unknown> | null => { for (const node of nodes) { if (node.type === "TEXT" && node.cssStyles) { return node.cssStyles; } if (node.children) { const found = findTextStyles( node.children as Array<{ type?: string; cssStyles?: Record<string, unknown>; children?: unknown[]; }>, ); if (found) return found; } } return null; }; const textStyles = findTextStyles(result.nodes); if (textStyles) { expect(textStyles.fontFamily).toBeDefined(); expect(textStyles.fontSize).toBeDefined(); } }); }); describe("Output Stability", () => { it("should produce consistent output structure", () => { const result = parseFigmaResponse(rawData as Parameters<typeof parseFigmaResponse>[0]); // Compare key structure with expected output expect(Object.keys(result)).toEqual(Object.keys(expectedOutput as object)); expect(result.nodes.length).toBe((expectedOutput as { nodes: unknown[] }).nodes.length); }); }); });

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/1yhy/Figma-Context-MCP'

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