figma-restoration-mcp-vue-tools
Version:
Professional Figma Component Restoration Kit - MCP tools with snapDOM-powered high-quality screenshots, intelligent shadow detection, and advanced diff analysis for Vue component restoration. Features enhanced figma_compare with color-coded region analysi
406 lines (341 loc) โข 16 kB
JavaScript
import { ErrorResponseSystem, ErrorResponseBuilder } from '../error-response-system.js';
/**
* Simple test runner for ErrorResponseSystem
*/
class TestRunner {
constructor() {
this.tests = [];
this.passed = 0;
this.failed = 0;
}
test(name, testFn) {
this.tests.push({ name, testFn });
}
async run() {
console.log('๐งช Running ErrorResponseSystem Tests...\\n');
for (const { name, testFn } of this.tests) {
try {
await testFn();
console.log(`โ
${name}`);
this.passed++;
} catch (error) {
console.log(`โ ${name}: ${error.message}`);
this.failed++;
}
}
console.log(`\\n๐ Test Results: ${this.passed} passed, ${this.failed} failed`);
return this.failed === 0;
}
assert(condition, message) {
if (!condition) {
throw new Error(message || 'Assertion failed');
}
}
assertDeepEqual(actual, expected, message) {
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new Error(message || `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
}
}
}
// Test suite
const runner = new TestRunner();
runner.test('should have all required error codes', () => {
const codes = ErrorResponseSystem.ERROR_CODES;
runner.assert(codes.VALIDATION_ERROR === 'E1001', 'Should have validation error code');
runner.assert(codes.FILE_NOT_FOUND === 'E1101', 'Should have file not found code');
runner.assert(codes.NETWORK_TIMEOUT === 'E1201', 'Should have network timeout code');
runner.assert(codes.OPERATION_TIMEOUT === 'E1301', 'Should have operation timeout code');
runner.assert(codes.SHARP_ERROR === 'E1401', 'Should have Sharp error code');
runner.assert(codes.FIGMA_COMPARE_ERROR === 'E1501', 'Should have Figma compare error code');
runner.assert(codes.UNKNOWN_ERROR === 'E1699', 'Should have unknown error code');
});
runner.test('should have all severity levels', () => {
const levels = ErrorResponseSystem.SEVERITY_LEVELS;
runner.assert(levels.LOW === 'low', 'Should have low severity');
runner.assert(levels.MEDIUM === 'medium', 'Should have medium severity');
runner.assert(levels.HIGH === 'high', 'Should have high severity');
runner.assert(levels.CRITICAL === 'critical', 'Should have critical severity');
});
runner.test('should create standardized error response', () => {
const error = new Error('Test error message');
error.code = 'ENOENT';
const response = ErrorResponseSystem.createErrorResponse(error, {
tool: 'TestTool',
operation: 'testOperation',
operationId: 'test-123'
});
runner.assert(response.success === false, 'Should mark as failed');
runner.assert(response.error.message, 'Should have error message');
runner.assert(response.error.code, 'Should have error code');
runner.assert(response.error.category, 'Should have error category');
runner.assert(response.error.severity, 'Should have severity level');
runner.assert(Array.isArray(response.error.suggestions), 'Should have suggestions array');
runner.assert(response.error.context.tool === 'TestTool', 'Should include tool context');
runner.assert(response.error.context.operation === 'testOperation', 'Should include operation context');
runner.assert(response.error.recovery, 'Should have recovery information');
runner.assert(response._reliability, 'Should have reliability metadata');
runner.assert(response._reliability.enhanced === true, 'Should mark as enhanced');
});
runner.test('should create validation error response', () => {
const response = ErrorResponseSystem.createValidationError(
'Required field is missing',
'inputPath',
{ tool: 'TestTool' }
);
runner.assert(response.success === false, 'Should mark as failed');
runner.assert(response.error.code === 'E1001', 'Should use validation error code');
runner.assert(response.error.message === 'Required field is missing', 'Should preserve message');
runner.assert(response.error.context.validationField === 'inputPath', 'Should include field context');
});
runner.test('should create timeout error response', () => {
const response = ErrorResponseSystem.createTimeoutError(
'imageProcessing',
30000,
{ tool: 'TestTool' }
);
runner.assert(response.success === false, 'Should mark as failed');
runner.assert(response.error.code === 'E1301', 'Should use timeout error code');
runner.assert(response.error.message.includes('imageProcessing'), 'Should include operation name');
runner.assert(response.error.message.includes('30000ms'), 'Should include timeout value');
runner.assert(response.error.context.timeout === 30000, 'Should include timeout context');
});
runner.test('should create file system error response', () => {
const fsError = new Error('File not found');
fsError.code = 'ENOENT';
fsError.path = '/test/path.svg';
const response = ErrorResponseSystem.createFileSystemError(
'/test/path.svg',
'read',
fsError,
{ tool: 'TestTool' }
);
runner.assert(response.success === false, 'Should mark as failed');
runner.assert(response.error.code === 'E1101', 'Should use file not found error code');
runner.assert(response.error.context.filePath === '/test/path.svg', 'Should include file path');
runner.assert(response.error.context.fileOperation === 'read', 'Should include operation');
});
runner.test('should create library error response', () => {
const libError = new Error('Sharp processing failed');
const response = ErrorResponseSystem.createLibraryError(
'sharp',
libError,
{ tool: 'TestTool' }
);
runner.assert(response.success === false, 'Should mark as failed');
runner.assert(response.error.code === 'E1401', 'Should use Sharp error code');
runner.assert(response.error.context.library === 'sharp', 'Should include library name');
runner.assert(response.error.context.libraryError === true, 'Should mark as library error');
});
runner.test('should map error codes correctly', () => {
// File system errors
const enoentError = new Error('File not found');
enoentError.code = 'ENOENT';
const enoentCode = ErrorResponseSystem.mapToStandardErrorCode(enoentError, { category: 'FileSystem' });
runner.assert(enoentCode === 'E1101', 'Should map ENOENT to file not found');
// Network errors
const timeoutError = new Error('Network timeout');
timeoutError.code = 'ETIMEDOUT';
const timeoutCode = ErrorResponseSystem.mapToStandardErrorCode(timeoutError, { category: 'Network' });
runner.assert(timeoutCode === 'E1201', 'Should map ETIMEDOUT to network timeout');
// Memory errors
const memoryError = new Error('Out of memory');
memoryError.code = 'ENOMEM';
const memoryCode = ErrorResponseSystem.mapToStandardErrorCode(memoryError, { category: 'Memory' });
runner.assert(memoryCode === 'E1303', 'Should map ENOMEM to memory insufficient');
});
runner.test('should determine severity levels correctly', () => {
// Critical severity
const memoryError = new Error('Out of memory');
memoryError.code = 'ENOMEM';
const criticalSeverity = ErrorResponseSystem.determineSeverity(memoryError, { category: 'Memory' });
runner.assert(criticalSeverity === 'critical', 'Memory errors should be critical');
// High severity
const fileError = new Error('File not found');
fileError.code = 'ENOENT';
const highSeverity = ErrorResponseSystem.determineSeverity(fileError, { category: 'FileSystem' });
runner.assert(highSeverity === 'high', 'File system errors should be high');
// Medium severity
const timeoutError = new Error('Operation timeout');
const mediumSeverity = ErrorResponseSystem.determineSeverity(timeoutError, { category: 'Timeout' });
runner.assert(mediumSeverity === 'medium', 'Timeout errors should be medium');
// Low severity
const validationError = new Error('Invalid input');
const lowSeverity = ErrorResponseSystem.determineSeverity(validationError, { category: 'Validation' });
runner.assert(lowSeverity === 'low', 'Validation errors should be low');
});
runner.test('should determine retryability correctly', () => {
// Retryable errors
const timeoutError = new Error('Timeout');
const timeoutRetryable = ErrorResponseSystem.isRetryable(timeoutError, { category: 'Timeout' });
runner.assert(timeoutRetryable === true, 'Timeout errors should be retryable');
const networkError = new Error('Network error');
networkError.code = 'ETIMEDOUT';
const networkRetryable = ErrorResponseSystem.isRetryable(networkError, { category: 'Network' });
runner.assert(networkRetryable === true, 'Network errors should be retryable');
// Non-retryable errors
const validationError = new Error('Invalid input');
const validationRetryable = ErrorResponseSystem.isRetryable(validationError, { category: 'Validation' });
runner.assert(validationRetryable === false, 'Validation errors should not be retryable');
});
runner.test('should calculate retry delays correctly', () => {
const timeoutDelay = ErrorResponseSystem.getRetryDelay(
new Error('Timeout'),
{ category: 'Timeout' }
);
runner.assert(timeoutDelay === 5000, 'Timeout errors should have 5s delay');
const networkDelay = ErrorResponseSystem.getRetryDelay(
new Error('Network error'),
{ category: 'Network' }
);
runner.assert(networkDelay === 3000, 'Network errors should have 3s delay');
const nonRetryableDelay = ErrorResponseSystem.getRetryDelay(
new Error('Validation error'),
{ category: 'Validation' }
);
runner.assert(nonRetryableDelay === 0, 'Non-retryable errors should have 0 delay');
});
runner.test('should detect fallback availability', () => {
const libraryFallback = ErrorResponseSystem.hasFallback(
new Error('Library error'),
{ category: 'Library' }
);
runner.assert(libraryFallback === true, 'Library errors should have fallbacks');
const formatFallback = ErrorResponseSystem.hasFallback(
new Error('Format error'),
{ category: 'Format' }
);
runner.assert(formatFallback === true, 'Format errors should have fallbacks');
const validationFallback = ErrorResponseSystem.hasFallback(
new Error('Validation error'),
{ category: 'Validation' }
);
runner.assert(validationFallback === false, 'Validation errors should not have fallbacks');
});
runner.test('should validate error response format', () => {
const validResponse = {
success: false,
error: {
message: 'Test error',
code: 'E1001',
category: 'Validation',
severity: 'low',
suggestions: ['Try again'],
context: { tool: 'TestTool' },
technical: {},
recovery: {}
}
};
runner.assert(
ErrorResponseSystem.validateErrorResponse(validResponse) === true,
'Should validate correct error response'
);
const invalidResponse = {
success: false,
error: {
message: 'Test error'
// Missing required fields
}
};
runner.assert(
ErrorResponseSystem.validateErrorResponse(invalidResponse) === false,
'Should reject invalid error response'
);
});
runner.test('should create success response', () => {
const result = { data: 'test result' };
const context = {
operationId: 'test-123',
duration: 1500,
metrics: { processed: 1 }
};
const response = ErrorResponseSystem.createSuccessResponse(result, context);
runner.assert(response.success === true, 'Should mark as successful');
runner.assert(response.result === result, 'Should include result');
runner.assert(response._reliability.enhanced === true, 'Should mark as enhanced');
runner.assert(response._reliability.operationId === 'test-123', 'Should include operation ID');
runner.assert(response._reliability.duration === 1500, 'Should include duration');
runner.assert(response._reliability.metrics === context.metrics, 'Should include metrics');
});
runner.test('should wrap responses correctly', () => {
// Wrap success result
const successResult = { data: 'success' };
const wrappedSuccess = ErrorResponseSystem.wrapResponse(successResult, { operationId: 'test-1' });
runner.assert(wrappedSuccess.success === true, 'Should wrap success result');
runner.assert(wrappedSuccess.result === successResult, 'Should preserve result');
runner.assert(wrappedSuccess._reliability.operationId === 'test-1', 'Should include context');
// Wrap error response
const errorResponse = {
success: false,
error: {
message: 'Test error',
code: 'E1001',
category: 'Test',
severity: 'low',
suggestions: [],
context: {},
technical: {},
recovery: {}
}
};
const wrappedError = ErrorResponseSystem.wrapResponse(errorResponse);
runner.assert(wrappedError.success === false, 'Should preserve error response');
runner.assert(wrappedError.error.message === 'Test error', 'Should preserve error message');
});
// ErrorResponseBuilder tests
runner.test('should build error response with fluent API', () => {
const response = new ErrorResponseBuilder()
.message('Test error message')
.tool('TestTool')
.operation('testOperation')
.operationId('test-123')
.duration(1500)
.context({ custom: 'data' })
.build();
runner.assert(response.success === false, 'Should create error response');
runner.assert(response.error.message === 'Test error message', 'Should set message');
runner.assert(response.error.context.tool === 'TestTool', 'Should set tool');
runner.assert(response.error.context.operation === 'testOperation', 'Should set operation');
runner.assert(response.error.context.operationId === 'test-123', 'Should set operation ID');
runner.assert(response.error.context.duration === 1500, 'Should set duration');
runner.assert(response.error.context.custom === 'data', 'Should include custom context');
});
runner.test('should build validation error with fluent API', () => {
const response = new ErrorResponseBuilder()
.message('Field is required')
.tool('TestTool')
.buildValidation('inputPath');
runner.assert(response.success === false, 'Should create validation error');
runner.assert(response.error.code === 'E1001', 'Should use validation error code');
runner.assert(response.error.context.validationField === 'inputPath', 'Should include field');
});
runner.test('should build timeout error with fluent API', () => {
const response = new ErrorResponseBuilder()
.message('Operation timed out')
.tool('TestTool')
.operation('imageProcessing')
.buildTimeout(30000);
runner.assert(response.success === false, 'Should create timeout error');
runner.assert(response.error.code === 'E1301', 'Should use timeout error code');
runner.assert(response.error.context.timeout === 30000, 'Should include timeout');
});
runner.test('should map library-specific error codes', () => {
const sharpError = new Error('Sharp processing failed');
const sharpCode = ErrorResponseSystem.mapLibraryErrorCode(sharpError);
runner.assert(sharpCode === 'E1401', 'Should map Sharp errors correctly');
const svgoError = new Error('SVGO optimization failed');
const svgoCode = ErrorResponseSystem.mapLibraryErrorCode(svgoError);
runner.assert(svgoCode === 'E1402', 'Should map SVGO errors correctly');
const puppeteerError = new Error('Puppeteer browser launch failed');
const puppeteerCode = ErrorResponseSystem.mapLibraryErrorCode(puppeteerError);
runner.assert(puppeteerCode === 'E1403', 'Should map Puppeteer errors correctly');
const genericError = new Error('Generic library error');
const genericCode = ErrorResponseSystem.mapLibraryErrorCode(genericError);
runner.assert(genericCode === 'E1302', 'Should map generic library errors to processing failed');
});
// Run tests if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
runner.run().then(success => {
process.exit(success ? 0 : 1);
});
}
export { runner as errorResponseSystemTests };