Files
michaelschiemer/tests/Framework/Design/Service/TokenAnalyzerTest.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

200 lines
8.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Design\Service\TokenAnalyzer;
use App\Framework\Design\ValueObjects\CustomProperty;
use App\Framework\Design\ValueObjects\DesignToken;
use App\Framework\Design\ValueObjects\TokenCategory;
describe('TokenAnalyzer', function () {
beforeEach(function () {
$this->analyzer = new TokenAnalyzer();
});
it('categorizes design tokens correctly', function () {
$customProperties = [
new CustomProperty('primary-color', '#3b82f6'),
new CustomProperty('text-base', '16px'),
new CustomProperty('spacing-md', '1rem'),
new CustomProperty('border-radius', '4px'),
new CustomProperty('font-weight-bold', '700'),
new CustomProperty('shadow-lg', '0 10px 15px -3px rgba(0, 0, 0, 0.1)'),
new CustomProperty('duration-fast', '150ms'),
];
$tokens = $this->analyzer->categorizeTokens($customProperties);
expect($tokens)->toHaveCount(7);
// Check categories
$categories = array_map(fn ($token) => $token->category, $tokens);
expect($categories)->toContain(TokenCategory::COLOR);
expect($categories)->toContain(TokenCategory::TYPOGRAPHY);
expect($categories)->toContain(TokenCategory::SPACING);
expect($categories)->toContain(TokenCategory::BORDER);
expect($categories)->toContain(TokenCategory::SHADOW);
expect($categories)->toContain(TokenCategory::ANIMATION);
});
it('analyzes token naming patterns', function () {
$customProperties = [
new CustomProperty('color-primary-500', '#3b82f6'), // Design system naming
new CustomProperty('spacing-xs', '0.25rem'), // Descriptive naming
new CustomProperty('fontSize', '16px'), // camelCase (inconsistent)
new CustomProperty('main-color', '#1f2937'), // Simple naming
];
$analysis = $this->analyzer->analyzeNamingPatterns($customProperties);
expect($analysis['patterns'])->toHaveKey('design-system');
expect($analysis['patterns'])->toHaveKey('descriptive');
expect($analysis['patterns'])->toHaveKey('camelCase');
expect($analysis['patterns'])->toHaveKey('simple');
expect($analysis['consistency_score'])->toBeLessThan(1.0); // Mixed patterns
expect($analysis['recommendations'])->not->toBeEmpty();
});
it('detects token relationships', function () {
$customProperties = [
new CustomProperty('color-primary-100', '#dbeafe'),
new CustomProperty('color-primary-500', '#3b82f6'),
new CustomProperty('color-primary-900', '#1e3a8a'),
new CustomProperty('spacing-sm', '0.5rem'),
new CustomProperty('spacing-md', '1rem'),
new CustomProperty('spacing-lg', '1.5rem'),
];
$relationships = $this->analyzer->detectTokenRelationships($customProperties);
expect($relationships)->toHaveKey('color-primary');
expect($relationships)->toHaveKey('spacing');
expect($relationships['color-primary'])->toHaveCount(3);
expect($relationships['spacing'])->toHaveCount(3);
});
it('validates token values', function () {
$customProperties = [
new CustomProperty('color-valid', '#3b82f6'),
new CustomProperty('color-invalid', 'not-a-color'),
new CustomProperty('spacing-valid', '1rem'),
new CustomProperty('spacing-invalid', 'invalid-size'),
new CustomProperty('duration-valid', '300ms'),
new CustomProperty('duration-invalid', 'fast'),
];
$validation = $this->analyzer->validateTokenValues($customProperties);
expect($validation['valid'])->toHaveCount(3);
expect($validation['invalid'])->toHaveCount(3);
$invalidToken = $validation['invalid'][0];
expect($invalidToken['property'])->toBe('color-invalid');
expect($invalidToken['reason'])->toContain('Invalid color format');
});
it('analyzes token usage patterns', function () {
$tokens = [
new DesignToken('primary-color', '#3b82f6', TokenCategory::COLOR),
new DesignToken('secondary-color', '#6b7280', TokenCategory::COLOR),
new DesignToken('text-base', '16px', TokenCategory::TYPOGRAPHY),
];
// Mock CSS rules that reference these tokens
$cssReferences = [
'var(--primary-color)' => 15, // Used 15 times
'var(--secondary-color)' => 3, // Used 3 times
'var(--text-base)' => 8, // Used 8 times
];
$usage = $this->analyzer->analyzeTokenUsage($tokens, $cssReferences);
expect($usage)->toHaveCount(3);
expect($usage[0]['usage_count'])->toBe(15);
expect($usage[0]['usage_frequency'])->toBe('high');
});
it('suggests token optimizations', function () {
$customProperties = [
new CustomProperty('red-color', '#ef4444'),
new CustomProperty('error-color', '#ef4444'), // Duplicate value
new CustomProperty('danger-color', '#ef4444'), // Another duplicate
new CustomProperty('unused-color', '#10b981'), // Unused token
new CustomProperty('spacing-tiny', '2px'), // Non-standard spacing
];
$suggestions = $this->analyzer->suggestOptimizations($customProperties);
expect($suggestions['duplicates'])->toHaveCount(1);
expect($suggestions['duplicates'][0]['tokens'])->toHaveCount(3);
expect($suggestions['duplicates'][0]['value'])->toBe('#ef4444');
expect($suggestions['non_standard_values'])->not->toBeEmpty();
expect($suggestions['consolidation_opportunities'])->not->toBeEmpty();
});
it('generates token documentation', function () {
$tokens = [
new DesignToken('primary-color', '#3b82f6', TokenCategory::COLOR),
new DesignToken('spacing-md', '1rem', TokenCategory::SPACING),
new DesignToken('font-size-lg', '1.125rem', TokenCategory::TYPOGRAPHY),
];
$documentation = $this->analyzer->generateTokenDocumentation($tokens);
expect($documentation)->toHaveKey('color');
expect($documentation)->toHaveKey('spacing');
expect($documentation)->toHaveKey('typography');
expect($documentation['color'])->toHaveCount(1);
expect($documentation['color'][0]['name'])->toBe('primary-color');
expect($documentation['color'][0]['value'])->toBe('#3b82f6');
expect($documentation['color'][0]['example'])->toContain('background-color: var(--primary-color)');
});
it('calculates token coverage metrics', function () {
$tokens = [
new DesignToken('primary-color', '#3b82f6', TokenCategory::COLOR),
new DesignToken('spacing-md', '1rem', TokenCategory::SPACING),
];
// Mock CSS analysis showing hardcoded values
$hardcodedValues = [
'#ff0000' => 5, // 5 hardcoded red colors
'8px' => 3, // 3 hardcoded 8px spacings
'12px' => 2, // 2 hardcoded 12px spacings
];
$coverage = $this->analyzer->calculateTokenCoverage($tokens, $hardcodedValues);
expect($coverage['token_usage'])->toBe(2);
expect($coverage['hardcoded_values'])->toBe(10);
expect($coverage['coverage_ratio'])->toBeCloseTo(0.167, 2); // 2/12
expect($coverage['recommendations'])->not->toBeEmpty();
});
it('validates design system consistency', function () {
$customProperties = [
// Consistent color scale
new CustomProperty('blue-100', '#dbeafe'),
new CustomProperty('blue-500', '#3b82f6'),
new CustomProperty('blue-900', '#1e3a8a'),
// Inconsistent spacing (missing steps)
new CustomProperty('space-1', '0.25rem'),
new CustomProperty('space-3', '0.75rem'), // Missing space-2
new CustomProperty('space-5', '1.25rem'), // Missing space-4
];
$consistency = $this->analyzer->validateDesignSystemConsistency($customProperties);
expect($consistency['color_scales']['blue']['complete'])->toBeTrue();
expect($consistency['spacing_scales']['space']['complete'])->toBeFalse();
expect($consistency['spacing_scales']['space']['missing_steps'])->toContain('space-2');
expect($consistency['spacing_scales']['space']['missing_steps'])->toContain('space-4');
});
});