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'); }); });