Initial commit: Penpot MCP Server - Complete AI-powered design workflow automation with MCP protocol, Penpot API integration, Claude AI support, CLI tools, and comprehensive documentation

This commit is contained in:
Chema
2025-05-26 19:16:46 +02:00
commit 85e658d2cd
42 changed files with 8159 additions and 0 deletions

1
tests/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""Package tests."""

52
tests/conftest.py Normal file
View File

@@ -0,0 +1,52 @@
"""Test configuration for Penpot MCP tests."""
import os
from unittest.mock import MagicMock
import pytest
from penpot_mcp.api.penpot_api import PenpotAPI
from penpot_mcp.server.mcp_server import PenpotMCPServer
# Add the project root directory to the Python path
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
@pytest.fixture
def mock_penpot_api(monkeypatch):
"""Create a mock PenpotAPI object."""
mock_api = MagicMock(spec=PenpotAPI)
# Add default behavior to the mock
mock_api.list_projects.return_value = [
{"id": "project1", "name": "Test Project 1"},
{"id": "project2", "name": "Test Project 2"}
]
mock_api.get_project_files.return_value = [
{"id": "file1", "name": "Test File 1"},
{"id": "file2", "name": "Test File 2"}
]
mock_api.get_file.return_value = {
"id": "file1",
"name": "Test File",
"data": {
"pages": [
{
"id": "page1",
"name": "Page 1",
"objects": {
"obj1": {"id": "obj1", "name": "Object 1", "type": "frame"},
"obj2": {"id": "obj2", "name": "Object 2", "type": "text"}
}
}
]
}
}
return mock_api
@pytest.fixture
def mock_server(mock_penpot_api):
"""Create a mock PenpotMCPServer with a mock API."""
server = PenpotMCPServer(name="Test Server")
server.api = mock_penpot_api
return server

86
tests/test_cache.py Normal file
View File

@@ -0,0 +1,86 @@
"""
Tests for the memory caching functionality.
"""
import time
import pytest
from penpot_mcp.utils.cache import MemoryCache
@pytest.fixture
def memory_cache():
"""Create a MemoryCache instance with a short TTL for testing."""
return MemoryCache(ttl_seconds=2)
def test_cache_set_get(memory_cache):
"""Test setting and getting a file from cache."""
test_data = {"test": "data"}
file_id = "test123"
# Set data in cache
memory_cache.set(file_id, test_data)
# Get data from cache
cached_data = memory_cache.get(file_id)
assert cached_data == test_data
def test_cache_expiration(memory_cache):
"""Test that cached files expire after TTL."""
test_data = {"test": "data"}
file_id = "test123"
# Set data in cache
memory_cache.set(file_id, test_data)
# Data should be available immediately
assert memory_cache.get(file_id) == test_data
# Wait for cache to expire
time.sleep(3)
# Data should be expired
assert memory_cache.get(file_id) is None
def test_cache_clear(memory_cache):
"""Test clearing the cache."""
test_data = {"test": "data"}
file_id = "test123"
# Set data in cache
memory_cache.set(file_id, test_data)
# Verify data is cached
assert memory_cache.get(file_id) == test_data
# Clear cache
memory_cache.clear()
# Verify data is gone
assert memory_cache.get(file_id) is None
def test_get_all_cached_files(memory_cache):
"""Test getting all cached files."""
test_data1 = {"test": "data1"}
test_data2 = {"test": "data2"}
# Set multiple files in cache
memory_cache.set("file1", test_data1)
memory_cache.set("file2", test_data2)
# Get all cached files
all_files = memory_cache.get_all_cached_files()
# Verify all files are present
assert len(all_files) == 2
assert all_files["file1"] == test_data1
assert all_files["file2"] == test_data2
# Wait for cache to expire
time.sleep(3)
# Verify expired files are removed
all_files = memory_cache.get_all_cached_files()
assert len(all_files) == 0
def test_cache_nonexistent_file(memory_cache):
"""Test getting a nonexistent file from cache."""
assert memory_cache.get("nonexistent") is None

38
tests/test_config.py Normal file
View File

@@ -0,0 +1,38 @@
"""Tests for config module."""
from penpot_mcp.utils import config
def test_config_values():
"""Test that config has the expected values and types."""
assert isinstance(config.PORT, int)
assert isinstance(config.DEBUG, bool)
assert isinstance(config.PENPOT_API_URL, str)
assert config.RESOURCES_PATH is not None
def test_environment_variable_override(monkeypatch):
"""Test that environment variables override default config values."""
# Save original values
original_port = config.PORT
original_debug = config.DEBUG
original_api_url = config.PENPOT_API_URL
# Override with environment variables
monkeypatch.setenv("PORT", "8080")
monkeypatch.setenv("DEBUG", "false")
monkeypatch.setenv("PENPOT_API_URL", "https://test.example.com/api")
# Reload the config module to apply the environment variables
import importlib
importlib.reload(config)
# Check the new values
assert config.PORT == 8080
assert config.DEBUG is False
assert config.PENPOT_API_URL == "https://test.example.com/api"
# Restore original values
monkeypatch.setattr(config, "PORT", original_port)
monkeypatch.setattr(config, "DEBUG", original_debug)
monkeypatch.setattr(config, "PENPOT_API_URL", original_api_url)

1074
tests/test_mcp_server.py Normal file

File diff suppressed because it is too large Load Diff

1090
tests/test_penpot_tree.py Normal file

File diff suppressed because it is too large Load Diff