Skip to main content
Glama
media.test.js22.3 kB
import { vi } from "vitest"; // NOTE: fs mock removed as upload tests requiring it were deleted // Upload functionality is validated through integration tests import { MediaTools } from "@/tools/media.js"; describe("MediaTools", () => { let mediaTools; let mockClient; beforeEach(() => { vi.clearAllMocks(); // Mock WordPress client with all needed methods mockClient = { request: vi.fn(), getMedia: vi.fn(), getMediaItem: vi.fn(), uploadMedia: vi.fn(), updateMedia: vi.fn(), deleteMedia: vi.fn(), getSiteUrl: vi.fn().mockReturnValue("https://test-site.com"), config: { baseUrl: "https://test-site.com", }, }; mediaTools = new MediaTools(); }); describe("getTools", () => { it("should return an array of media tools", () => { const tools = mediaTools.getTools(); expect(Array.isArray(tools)).toBe(true); expect(tools).toHaveLength(5); const toolNames = tools.map((tool) => tool.name); expect(toolNames).toContain("wp_list_media"); expect(toolNames).toContain("wp_get_media"); expect(toolNames).toContain("wp_upload_media"); expect(toolNames).toContain("wp_update_media"); expect(toolNames).toContain("wp_delete_media"); }); it("should have proper tool definitions", () => { const tools = mediaTools.getTools(); tools.forEach((tool) => { expect(tool).toHaveProperty("name"); expect(tool).toHaveProperty("description"); expect(tool).toHaveProperty("handler"); expect(typeof tool.handler).toBe("function"); }); }); it("should have correct parameter definitions for each tool", () => { const tools = mediaTools.getTools(); const toolsByName = {}; tools.forEach((tool) => { toolsByName[tool.name] = tool; }); // wp_list_media should have optional parameters expect(toolsByName["wp_list_media"].parameters).toHaveLength(3); const listParams = toolsByName["wp_list_media"].parameters; expect(listParams.find((p) => p.name === "per_page")).toBeTruthy(); expect(listParams.find((p) => p.name === "search")).toBeTruthy(); expect(listParams.find((p) => p.name === "media_type")).toBeTruthy(); // Check media_type enum values const mediaTypeParam = listParams.find((p) => p.name === "media_type"); expect(mediaTypeParam.enum).toEqual(["image", "video", "audio", "application"]); // wp_get_media should require id const getMediaParams = toolsByName["wp_get_media"].parameters; const idParam = getMediaParams.find((p) => p.name === "id"); expect(idParam).toBeTruthy(); expect(idParam.required).toBe(true); // wp_upload_media should have file_path as required and other optional params const uploadParams = toolsByName["wp_upload_media"].parameters; expect(uploadParams.find((p) => p.name === "file_path")).toBeTruthy(); expect(uploadParams.find((p) => p.name === "file_path").required).toBe(true); expect(uploadParams.find((p) => p.name === "title")).toBeTruthy(); expect(uploadParams.find((p) => p.name === "alt_text")).toBeTruthy(); expect(uploadParams.find((p) => p.name === "caption")).toBeTruthy(); expect(uploadParams.find((p) => p.name === "description")).toBeTruthy(); expect(uploadParams.find((p) => p.name === "post")).toBeTruthy(); // wp_update_media should require id const updateParams = toolsByName["wp_update_media"].parameters; expect(updateParams.find((p) => p.name === "id").required).toBe(true); // wp_delete_media should require id const deleteParams = toolsByName["wp_delete_media"].parameters; expect(deleteParams.find((p) => p.name === "id").required).toBe(true); }); }); describe("handleListMedia", () => { it("should list media items successfully", async () => { const mockMedia = [ { id: 1, title: { rendered: "Test Image 1" }, mime_type: "image/jpeg", media_type: "image", source_url: "https://test-site.com/media1.jpg", date: "2024-01-01T00:00:00", }, { id: 2, title: { rendered: "Test Video" }, mime_type: "video/mp4", media_type: "video", source_url: "https://test-site.com/video.mp4", date: "2024-01-02T00:00:00", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, {}); expect(mockClient.getMedia).toHaveBeenCalledWith({}); expect(typeof result).toBe("string"); expect(result).toContain("Found 2 media items:"); expect(result).toContain("Test Image 1"); expect(result).toContain("Test Video"); expect(result).toContain("image/jpeg"); expect(result).toContain("video/mp4"); expect(result).toContain("https://test-site.com/media1.jpg"); }); it("should handle empty results", async () => { mockClient.getMedia.mockResolvedValueOnce([]); const result = await mediaTools.handleListMedia(mockClient, {}); expect(typeof result).toBe("string"); expect(result).toContain("No media items found matching the criteria"); }); it("should handle search parameters", async () => { const mockMedia = [ { id: 1, title: { rendered: "Wedding Photo" }, mime_type: "image/jpeg", media_type: "image", source_url: "https://test-site.com/wedding.jpg", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, { search: "Wedding", per_page: 5, }); expect(mockClient.getMedia).toHaveBeenCalledWith({ search: "Wedding", per_page: 5, }); expect(typeof result).toBe("string"); expect(result).toContain("Wedding Photo"); }); it("should handle media_type filtering", async () => { const mockMedia = [ { id: 1, title: { rendered: "Image File" }, mime_type: "image/png", media_type: "image", source_url: "https://test-site.com/image.png", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, { media_type: "image", }); expect(mockClient.getMedia).toHaveBeenCalledWith({ media_type: "image", }); expect(typeof result).toBe("string"); expect(result).toContain("Image File"); expect(result).toContain("image/png"); }); it("should handle API errors", async () => { mockClient.getMedia.mockRejectedValueOnce(new Error("API Error")); await expect(mediaTools.handleListMedia(mockClient, {})).rejects.toThrow("Failed to list media"); }); it("should handle per_page parameter", async () => { const mockMedia = Array.from({ length: 20 }, (_, i) => ({ id: i + 1, title: { rendered: `Media ${i + 1}` }, mime_type: "image/jpeg", media_type: "image", source_url: `https://test-site.com/media-${i + 1}.jpg`, })); mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, { per_page: 20 }); expect(mockClient.getMedia).toHaveBeenCalledWith({ per_page: 20 }); expect(result).toContain("Found 20 media items:"); }); it("should format different media types correctly", async () => { const mockMedia = [ { id: 1, title: { rendered: "Image" }, mime_type: "image/jpeg", media_type: "image", source_url: "https://test-site.com/image.jpg", }, { id: 2, title: { rendered: "Audio" }, mime_type: "audio/mp3", media_type: "audio", source_url: "https://test-site.com/audio.mp3", }, { id: 3, title: { rendered: "Document" }, mime_type: "application/pdf", media_type: "application", source_url: "https://test-site.com/doc.pdf", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, {}); expect(result).toContain("(image/jpeg)"); expect(result).toContain("(audio/mp3)"); expect(result).toContain("(application/pdf)"); }); }); describe("handleGetMedia", () => { it("should get a media item successfully", async () => { const mockMedia = { id: 1, title: { rendered: "Test Media" }, source_url: "https://test-site.com/test.jpg", media_type: "image", mime_type: "image/jpeg", date: "2024-01-01T00:00:00", alt_text: "Alternative text", caption: { rendered: "Media caption" }, }; mockClient.getMediaItem.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleGetMedia(mockClient, { id: 1 }); expect(mockClient.getMediaItem).toHaveBeenCalledWith(1); expect(typeof result).toBe("string"); expect(result).toContain("Media Details (ID: 1)"); expect(result).toContain("Test Media"); expect(result).toContain("https://test-site.com/test.jpg"); expect(result).toContain("image (image/jpeg)"); expect(result).toContain("Alternative text"); expect(result).toContain("Media caption"); }); it("should handle media without optional fields", async () => { const mockMedia = { id: 2, title: { rendered: "Simple Media" }, source_url: "https://test-site.com/simple.jpg", media_type: "image", mime_type: "image/jpeg", date: "2024-01-01T00:00:00", alt_text: "", caption: { rendered: "" }, }; mockClient.getMediaItem.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleGetMedia(mockClient, { id: 2 }); expect(result).toContain("Simple Media"); expect(result).not.toContain("Alt Text:"); expect(result).not.toContain("Caption:"); }); it("should handle media not found", async () => { mockClient.getMediaItem.mockRejectedValueOnce(new Error("Media not found")); await expect(mediaTools.handleGetMedia(mockClient, { id: 999 })).rejects.toThrow("Failed to get media item"); }); it("should handle invalid ID parameter", async () => { mockClient.getMediaItem.mockRejectedValueOnce(new Error("Invalid ID")); await expect(mediaTools.handleGetMedia(mockClient, { id: "invalid" })).rejects.toThrow( "Failed to get media item", ); }); it("should format date correctly", async () => { const mockMedia = { id: 1, title: { rendered: "Date Test Media" }, source_url: "https://test-site.com/date-test.jpg", media_type: "image", mime_type: "image/jpeg", date: "2024-01-15T14:30:00", alt_text: "", caption: { rendered: "" }, }; mockClient.getMediaItem.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleGetMedia(mockClient, { id: 1 }); expect(result).toContain("Date Test Media"); expect(result).toMatch(/Date:.*2024/); // Should contain formatted date with year }); it("should handle different media types", async () => { const mockVideo = { id: 1, title: { rendered: "Test Video" }, source_url: "https://test-site.com/video.mp4", media_type: "video", mime_type: "video/mp4", date: "2024-01-01T00:00:00", alt_text: "", caption: { rendered: "" }, }; mockClient.getMediaItem.mockResolvedValueOnce(mockVideo); const result = await mediaTools.handleGetMedia(mockClient, { id: 1 }); expect(result).toContain("video (video/mp4)"); expect(result).toContain("Test Video"); }); }); // NOTE: handleUploadMedia tests removed - file system mocking incompatible with ES modules // Upload functionality is validated through integration tests and production usage describe("handleUpdateMedia", () => { it("should update media successfully", async () => { const mockUpdatedMedia = { id: 1, title: { rendered: "Updated Media" }, alt_text: "Updated alt text", caption: { rendered: "Updated caption" }, description: { rendered: "Updated description" }, }; mockClient.updateMedia.mockResolvedValueOnce(mockUpdatedMedia); const updateData = { id: 1, title: "Updated Media", alt_text: "Updated alt text", caption: "Updated caption", }; const result = await mediaTools.handleUpdateMedia(mockClient, updateData); expect(mockClient.updateMedia).toHaveBeenCalledWith(updateData); expect(typeof result).toBe("string"); expect(result).toContain("✅ Media 1 updated successfully"); }); it("should handle update errors", async () => { mockClient.updateMedia.mockRejectedValueOnce(new Error("Update failed")); await expect( mediaTools.handleUpdateMedia(mockClient, { id: 1, title: "Updated Media", }), ).rejects.toThrow("Failed to update media"); }); it("should handle missing ID", async () => { mockClient.updateMedia.mockRejectedValueOnce(new Error("ID is required")); await expect( mediaTools.handleUpdateMedia(mockClient, { title: "Updated Media", }), ).rejects.toThrow("Failed to update media"); }); it("should handle partial updates", async () => { const mockUpdatedMedia = { id: 2, title: { rendered: "Partially Updated" }, }; mockClient.updateMedia.mockResolvedValueOnce(mockUpdatedMedia); const result = await mediaTools.handleUpdateMedia(mockClient, { id: 2, alt_text: "New alt text only", }); expect(mockClient.updateMedia).toHaveBeenCalledWith({ id: 2, alt_text: "New alt text only", }); expect(result).toContain("✅ Media 2 updated successfully"); }); it("should handle all metadata fields", async () => { const mockUpdatedMedia = { id: 3 }; mockClient.updateMedia.mockResolvedValueOnce(mockUpdatedMedia); const allFieldsData = { id: 3, title: "New Title", alt_text: "New Alt Text", caption: "New Caption", description: "New Description", }; const result = await mediaTools.handleUpdateMedia(mockClient, allFieldsData); expect(mockClient.updateMedia).toHaveBeenCalledWith(allFieldsData); expect(result).toContain("✅ Media 3 updated successfully"); }); }); describe("handleDeleteMedia", () => { it("should delete media successfully (move to trash)", async () => { const mockDeleteResult = { deleted: true, previous: { id: 1, title: { rendered: "Deleted Media" }, }, }; mockClient.deleteMedia.mockResolvedValueOnce(mockDeleteResult); const result = await mediaTools.handleDeleteMedia(mockClient, { id: 1 }); expect(mockClient.deleteMedia).toHaveBeenCalledWith(1, undefined); expect(typeof result).toBe("string"); expect(result).toContain("✅ Media item 1 has been moved to trash"); }); it("should handle forced deletion", async () => { const mockDeleteResult = { deleted: true, previous: { id: 1, title: { rendered: "Permanently Deleted Media" }, }, }; mockClient.deleteMedia.mockResolvedValueOnce(mockDeleteResult); const result = await mediaTools.handleDeleteMedia(mockClient, { id: 1, force: true, }); expect(mockClient.deleteMedia).toHaveBeenCalledWith(1, true); expect(typeof result).toBe("string"); expect(result).toContain("✅ Media item 1 has been permanently deleted"); }); it("should handle deletion errors", async () => { mockClient.deleteMedia.mockRejectedValueOnce(new Error("Delete failed")); await expect(mediaTools.handleDeleteMedia(mockClient, { id: 1 })).rejects.toThrow("Failed to delete media"); }); it("should handle invalid ID", async () => { mockClient.deleteMedia.mockRejectedValueOnce(new Error("Invalid ID")); await expect(mediaTools.handleDeleteMedia(mockClient, { id: "invalid" })).rejects.toThrow( "Failed to delete media", ); }); it("should properly handle force parameter", async () => { const mockDeleteResult = { deleted: true }; mockClient.deleteMedia.mockResolvedValue(mockDeleteResult); // Test with force: false await mediaTools.handleDeleteMedia(mockClient, { id: 1, force: false }); expect(mockClient.deleteMedia).toHaveBeenCalledWith(1, false); // Test with force: true await mediaTools.handleDeleteMedia(mockClient, { id: 2, force: true }); expect(mockClient.deleteMedia).toHaveBeenCalledWith(2, true); }); it("should handle no force parameter (defaults to trash)", async () => { const mockDeleteResult = { deleted: true }; mockClient.deleteMedia.mockResolvedValueOnce(mockDeleteResult); const result = await mediaTools.handleDeleteMedia(mockClient, { id: 3 }); expect(mockClient.deleteMedia).toHaveBeenCalledWith(3, undefined); expect(result).toContain("moved to trash"); }); }); describe("Edge Cases and Error Handling", () => { it("should handle null/undefined parameters gracefully", async () => { await expect(mediaTools.handleListMedia(mockClient, null)).rejects.toThrow("Failed to list media"); }); it("should handle very large result sets", async () => { const largeMockMedia = Array.from({ length: 100 }, (_, i) => ({ id: i + 1, title: { rendered: `Media ${i + 1}` }, mime_type: "image/jpeg", media_type: "image", source_url: `https://test-site.com/media-${i + 1}.jpg`, })); mockClient.getMedia.mockResolvedValueOnce(largeMockMedia); const result = await mediaTools.handleListMedia(mockClient, { per_page: 100 }); expect(typeof result).toBe("string"); expect(result).toContain("Found 100 media items:"); }); it("should handle network timeouts gracefully", async () => { const timeoutError = new Error("Request timeout"); timeoutError.code = "ECONNABORTED"; mockClient.getMedia.mockRejectedValueOnce(timeoutError); await expect(mediaTools.handleListMedia(mockClient, {})).rejects.toThrow("Failed to list media"); }); it("should handle concurrent requests properly", async () => { const mockMedia = { id: 1, title: { rendered: "Test" }, source_url: "https://test-site.com/test.jpg", media_type: "image", mime_type: "image/jpeg", date: "2024-01-01T00:00:00", alt_text: "", caption: { rendered: "" }, }; mockClient.getMediaItem.mockResolvedValue(mockMedia); const promises = [ mediaTools.handleGetMedia(mockClient, { id: 1 }), mediaTools.handleGetMedia(mockClient, { id: 2 }), mediaTools.handleGetMedia(mockClient, { id: 3 }), ]; const results = await Promise.all(promises); expect(results).toHaveLength(3); expect(mockClient.getMediaItem).toHaveBeenCalledTimes(3); }); it("should handle media with special characters in names", async () => { const mockMedia = [ { id: 1, title: { rendered: "Special & Characters @ Media.jpg" }, mime_type: "image/jpeg", media_type: "image", source_url: "https://test-site.com/special%20file.jpg", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, {}); expect(result).toContain("Special & Characters @ Media.jpg"); expect(result).toContain("special%20file.jpg"); }); }); describe("Performance and Validation", () => { it("should validate media type enum parameters", async () => { const validMediaTypes = ["image", "video", "audio", "application"]; for (const mediaType of validMediaTypes) { mockClient.getMedia.mockResolvedValueOnce([]); const result = await mediaTools.handleListMedia(mockClient, { media_type: mediaType }); expect(typeof result).toBe("string"); expect(mockClient.getMedia).toHaveBeenCalledWith({ media_type: mediaType }); } }); it("should handle mixed parameter types", async () => { const mockMedia = [ { id: 1, title: { rendered: "Mixed Test" }, mime_type: "image/jpeg", media_type: "image", source_url: "https://test-site.com/mixed.jpg", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, { per_page: 10, search: "test query", media_type: "image", }); expect(mockClient.getMedia).toHaveBeenCalledWith({ per_page: 10, search: "test query", media_type: "image", }); expect(result).toContain("Mixed Test"); }); it("should maintain consistent response format", async () => { const mockMedia = [ { id: 1, title: { rendered: "Format Test" }, mime_type: "image/png", media_type: "image", source_url: "https://test-site.com/format.png", }, ]; mockClient.getMedia.mockResolvedValueOnce(mockMedia); const result = await mediaTools.handleListMedia(mockClient, {}); expect(result).toMatch(/Found \d+ media items:/); expect(result).toContain("ID 1:"); expect(result).toContain("**Format Test**"); expect(result).toContain("(image/png)"); expect(result).toContain("Link: https://test-site.com/format.png"); }); }); });

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/docdyhr/mcp-wordpress'

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